summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.mailmap137
-rw-r--r--.shippable.yml2
-rw-r--r--.travis.yml47
-rw-r--r--CODING_STYLE216
-rw-r--r--CODING_STYLE.rst641
-rw-r--r--HACKING257
-rw-r--r--MAINTAINERS10
-rw-r--r--Makefile1
-rw-r--r--Makefile.target3
-rw-r--r--README.rst (renamed from README)47
-rw-r--r--accel/tcg/atomic_template.h2
-rw-r--r--accel/tcg/cputlb.c412
-rw-r--r--accel/tcg/user-exec.c32
-rw-r--r--audio/audio.c10
-rw-r--r--backends/Makefile.objs2
-rw-r--r--backends/hostmem-file.c4
-rw-r--r--backends/rng-builtin.c77
-rw-r--r--block.c5
-rw-r--r--block/file-posix.c60
-rw-r--r--block/io.c2
-rw-r--r--block/nbd.c18
-rw-r--r--block/vmdk.c64
-rw-r--r--blockdev-nbd.c5
-rw-r--r--chardev/char-socket.c2
-rwxr-xr-xconfigure173
-rw-r--r--contrib/gitdm/aliases20
-rw-r--r--contrib/gitdm/domain-map1
-rw-r--r--contrib/gitdm/filetypes.txt2
-rw-r--r--contrib/gitdm/group-map-individuals3
-rw-r--r--contrib/gitdm/group-map-redhat1
-rw-r--r--contrib/libvhost-user/libvhost-user.c19
-rw-r--r--default-configs/m68k-softmmu.mak1
-rw-r--r--docs/interop/nbd.txt2
-rw-r--r--docs/qemu-block-drivers.texi72
-rw-r--r--docs/qemu-cpu-models.texi10
-rw-r--r--exec.c182
-rw-r--r--gdbstub.c12
-rw-r--r--hw/acpi/aml-build.c10
-rw-r--r--hw/arm/allwinner-a10.c3
-rw-r--r--hw/arm/aspeed.c5
-rw-r--r--hw/arm/boot.c21
-rw-r--r--hw/arm/collie.c8
-rw-r--r--hw/arm/cubieboard.c8
-rw-r--r--hw/arm/digic.c3
-rw-r--r--hw/arm/exynos4_boards.c11
-rw-r--r--hw/arm/fsl-imx25.c4
-rw-r--r--hw/arm/fsl-imx31.c4
-rw-r--r--hw/arm/fsl-imx6.c3
-rw-r--r--hw/arm/fsl-imx6ul.c2
-rw-r--r--hw/arm/highbank.c8
-rw-r--r--hw/arm/imx25_pdk.c5
-rw-r--r--hw/arm/integratorcp.c8
-rw-r--r--hw/arm/kzm.c5
-rw-r--r--hw/arm/mainstone.c5
-rw-r--r--hw/arm/mcimx6ul-evk.c5
-rw-r--r--hw/arm/mcimx7d-sabre.c14
-rw-r--r--hw/arm/mps2-tz.c15
-rw-r--r--hw/arm/musca.c9
-rw-r--r--hw/arm/musicpal.c8
-rw-r--r--hw/arm/nseries.c5
-rw-r--r--hw/arm/omap_sx1.c5
-rw-r--r--hw/arm/palm.c10
-rw-r--r--hw/arm/raspi.c6
-rw-r--r--hw/arm/realview.c5
-rw-r--r--hw/arm/sabrelite.c5
-rw-r--r--hw/arm/sbsa-ref.c12
-rw-r--r--hw/arm/smmuv3-internal.h1
-rw-r--r--hw/arm/smmuv3.c18
-rw-r--r--hw/arm/spitz.c5
-rw-r--r--hw/arm/tosa.c8
-rw-r--r--hw/arm/versatilepb.c5
-rw-r--r--hw/arm/vexpress.c5
-rw-r--r--hw/arm/virt-acpi-build.c19
-rw-r--r--hw/arm/virt.c17
-rw-r--r--hw/arm/xilinx_zynq.c8
-rw-r--r--hw/arm/xlnx-versal-virt.c7
-rw-r--r--hw/arm/xlnx-zcu102.c5
-rw-r--r--hw/arm/xlnx-zynqmp.c8
-rw-r--r--hw/arm/z2.c8
-rw-r--r--hw/char/escc.c30
-rw-r--r--hw/core/machine-hmp-cmds.c13
-rw-r--r--hw/core/machine-qmp-cmds.c4
-rw-r--r--hw/core/machine.c18
-rw-r--r--hw/core/numa.c80
-rw-r--r--hw/display/Makefile.objs1
-rw-r--r--hw/display/next-fb.c146
-rw-r--r--hw/dma/xilinx_axidma.c16
-rw-r--r--hw/i386/acpi-build.c4
-rw-r--r--hw/i386/kvm/clock.c15
-rw-r--r--hw/i386/pc.c33
-rw-r--r--hw/i386/vmmouse.c1
-rw-r--r--hw/intc/armv7m_nvic.c13
-rw-r--r--hw/m68k/Kconfig5
-rw-r--r--hw/m68k/Makefile.objs1
-rw-r--r--hw/m68k/next-cube.c978
-rw-r--r--hw/m68k/next-kbd.c291
-rw-r--r--hw/mem/pc-dimm.c2
-rw-r--r--hw/misc/Makefile.objs90
-rw-r--r--hw/net/xilinx_axienet.c17
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c9
-rw-r--r--hw/ppc/pnv.c81
-rw-r--r--hw/ppc/pnv_xscom.c20
-rw-r--r--hw/ppc/spapr.c58
-rw-r--r--hw/ppc/spapr_cpu_core.c5
-rw-r--r--hw/ppc/spapr_hcall.c2
-rw-r--r--hw/ppc/spapr_pci.c44
-rw-r--r--hw/ppc/spapr_pci_nvlink2.c40
-rw-r--r--hw/ppc/spapr_rtas.c15
-rw-r--r--hw/s390x/s390-pci-inst.c11
-rw-r--r--hw/timer/aspeed_timer.c17
-rw-r--r--hw/usb/dev-mtp.c38
-rw-r--r--hw/usb/hcd-xhci.c2
-rw-r--r--hw/vfio/pci-quirks.c7
-rw-r--r--hw/virtio/virtio-pci.c25
-rw-r--r--hw/virtio/virtio-pci.h4
-rw-r--r--hw/virtio/virtio-rng.c19
-rw-r--r--include/block/nbd.h6
-rw-r--r--include/exec/cpu-all.h8
-rw-r--r--include/exec/cpu-defs.h2
-rw-r--r--include/exec/exec-all.h10
-rw-r--r--include/exec/memattrs.h2
-rw-r--r--include/exec/memop.h134
-rw-r--r--include/exec/memory.h22
-rw-r--r--include/hw/acpi/aml-build.h2
-rw-r--r--include/hw/arm/boot.h4
-rw-r--r--include/hw/boards.h1
-rw-r--r--include/hw/char/escc.h1
-rw-r--r--include/hw/core/cpu.h37
-rw-r--r--include/hw/m68k/next-cube.h47
-rw-r--r--include/hw/pci-host/spapr.h24
-rw-r--r--include/hw/ppc/spapr.h1
-rw-r--r--include/hw/virtio/virtio-rng.h2
-rw-r--r--include/io/channel-socket.h4
-rw-r--r--include/io/net-listener.h2
-rw-r--r--include/qemu/memfd.h4
-rw-r--r--include/qemu/sockets.h2
-rw-r--r--include/sysemu/numa.h17
-rw-r--r--include/sysemu/rng.h2
-rw-r--r--include/sysemu/sysemu.h2
-rw-r--r--io/channel-socket.c35
-rw-r--r--io/net-listener.c3
-rw-r--r--io/trace-events4
-rw-r--r--linux-user/arm/target_cpu.h24
-rw-r--r--linux-user/elfload.c33
-rw-r--r--linux-user/ioctls.h13
-rw-r--r--linux-user/main.c69
-rw-r--r--linux-user/openrisc/target_elf.h2
-rw-r--r--linux-user/syscall.c14
-rw-r--r--linux-user/syscall_defs.h15
-rw-r--r--linux-user/xtensa/signal.c25
-rw-r--r--memory.c67
-rw-r--r--memory_ldst.inc.c81
-rw-r--r--migration/socket.c7
-rw-r--r--nbd/client.c85
-rw-r--r--nbd/common.c5
-rw-r--r--nbd/server.c83
-rw-r--r--nbd/trace-events2
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/skiboot.lidbin1591384 -> 1667280 bytes
-rw-r--r--pc-bios/slof.binbin926784 -> 930656 bytes
-rw-r--r--qapi/machine.json5
-rw-r--r--qemu-deprecated.texi7
-rw-r--r--qemu-doc.texi94
-rw-r--r--qemu-io-cmds.c99
-rw-r--r--qemu-nbd.c9
-rw-r--r--qemu-options.hx135
-rw-r--r--qga/channel-posix.c2
m---------roms/SLOF0
m---------roms/skiboot0
-rwxr-xr-xscripts/checkpatch.pl2
-rw-r--r--scsi/qemu-pr-helper.c3
-rw-r--r--target/alpha/translate.c2
-rw-r--r--target/arm/Makefile.objs24
-rw-r--r--target/arm/a32-uncond.decode74
-rw-r--r--target/arm/a32.decode534
-rw-r--r--target/arm/cpu.h6
-rw-r--r--target/arm/helper.c107
-rw-r--r--target/arm/t16.decode281
-rw-r--r--target/arm/t32.decode631
-rw-r--r--target/arm/translate-a64.c61
-rw-r--r--target/arm/translate-a64.h4
-rw-r--r--target/arm/translate-sve.c2
-rw-r--r--target/arm/translate-vfp.inc.c2
-rw-r--r--target/arm/translate.c7221
-rw-r--r--target/arm/translate.h4
-rw-r--r--target/hppa/op_helper.c2
-rw-r--r--target/hppa/translate.c14
-rw-r--r--target/i386/translate.c132
-rw-r--r--target/m68k/translate.c2
-rw-r--r--target/microblaze/translate.c4
-rw-r--r--target/mips/cpu.h113
-rw-r--r--target/mips/op_helper.c29
-rw-r--r--target/mips/translate.c1150
-rw-r--r--target/openrisc/cpu.c30
-rw-r--r--target/openrisc/cpu.h24
-rw-r--r--target/openrisc/disas.c81
-rw-r--r--target/openrisc/fpu_helper.c49
-rw-r--r--target/openrisc/helper.h6
-rw-r--r--target/openrisc/insns.decode45
-rw-r--r--target/openrisc/machine.c11
-rw-r--r--target/openrisc/sys_helper.c36
-rw-r--r--target/openrisc/translate.c714
-rw-r--r--target/ppc/cpu-qom.h1
-rw-r--r--target/ppc/fpu_helper.c42
-rw-r--r--target/ppc/translate.c12
-rw-r--r--target/ppc/translate/vmx-impl.inc.c66
-rw-r--r--target/ppc/translate/vsx-impl.inc.c2
-rw-r--r--target/ppc/translate_init.inc.c6
-rw-r--r--target/riscv/insn_trans/trans_rva.inc.c8
-rw-r--r--target/riscv/insn_trans/trans_rvi.inc.c4
-rw-r--r--target/s390x/mem_helper.c13
-rw-r--r--target/s390x/translate.c6
-rw-r--r--target/s390x/translate_vx.inc.c10
-rw-r--r--target/sparc/cpu.h2
-rw-r--r--target/sparc/mmu_helper.c40
-rw-r--r--target/sparc/translate.c14
-rw-r--r--target/tilegx/translate.c10
-rw-r--r--target/tricore/translate.c8
-rw-r--r--target/xtensa/cpu.c24
-rw-r--r--target/xtensa/cpu.h3
-rw-r--r--tcg/README4
-rw-r--r--tcg/aarch64/tcg-target.inc.c26
-rw-r--r--tcg/arm/tcg-target.inc.c26
-rw-r--r--tcg/i386/tcg-target.inc.c24
-rw-r--r--tcg/mips/tcg-target.inc.c16
-rw-r--r--tcg/optimize.c2
-rw-r--r--tcg/ppc/tcg-target.inc.c12
-rw-r--r--tcg/riscv/tcg-target.inc.c20
-rw-r--r--tcg/s390/tcg-target.inc.c14
-rw-r--r--tcg/sparc/tcg-target.inc.c6
-rw-r--r--tcg/tcg-op.c38
-rw-r--r--tcg/tcg-op.h86
-rw-r--r--tcg/tcg.c2
-rw-r--r--tcg/tcg.h101
-rw-r--r--tests/Makefile.include27
-rw-r--r--tests/acceptance/avocado_qemu/__init__.py3
-rw-r--r--tests/acceptance/boot_linux_console.py40
-rw-r--r--tests/acceptance/linux_initrd.py5
-rw-r--r--tests/acceptance/linux_ssh_mips_malta.py10
-rw-r--r--tests/acceptance/machine_m68k_nextcube.py121
-rw-r--r--tests/acceptance/migration.py3
-rw-r--r--tests/acceptance/pc_cpu_hotplug_props.py35
-rw-r--r--tests/acceptance/vnc.py4
-rw-r--r--tests/ahci-test.c1
-rw-r--r--tests/bios-tables-test.c1
-rw-r--r--tests/boot-serial-test.c15
-rwxr-xr-xtests/check-block.sh5
-rw-r--r--tests/cpu-plug-test.c2
-rw-r--r--tests/display-vga-test.c2
-rw-r--r--tests/docker/Makefile.include58
-rwxr-xr-xtests/docker/common.rc4
-rwxr-xr-xtests/docker/docker.py76
-rw-r--r--tests/docker/dockerfiles/debian-alpha-cross.docker7
-rw-r--r--tests/docker/dockerfiles/debian-amd64-cross.docker22
-rw-r--r--tests/docker/dockerfiles/debian-arm64-cross.docker7
-rw-r--r--tests/docker/dockerfiles/debian-armel-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-armhf-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-buster-arm64-cross.docker16
-rw-r--r--tests/docker/dockerfiles/debian-hppa-cross.docker5
-rw-r--r--tests/docker/dockerfiles/debian-m68k-cross.docker5
-rw-r--r--tests/docker/dockerfiles/debian-mips-cross.docker7
-rw-r--r--tests/docker/dockerfiles/debian-mips64-cross.docker5
-rw-r--r--tests/docker/dockerfiles/debian-mips64el-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-mipsel-cross.docker2
-rw-r--r--tests/docker/dockerfiles/debian-powerpc-cross.docker8
-rw-r--r--tests/docker/dockerfiles/debian-powerpc-user-cross.docker8
-rw-r--r--tests/docker/dockerfiles/debian-ppc64-cross.docker7
-rw-r--r--tests/docker/dockerfiles/debian-ppc64el-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-riscv64-cross.docker5
-rw-r--r--tests/docker/dockerfiles/debian-s390x-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-sh4-cross.docker5
-rw-r--r--tests/docker/dockerfiles/debian-sid.docker24
-rw-r--r--tests/docker/dockerfiles/debian-sparc64-cross.docker5
-rw-r--r--tests/docker/dockerfiles/ubuntu1804.docker3
-rwxr-xr-xtests/docker/run4
-rwxr-xr-xtests/docker/test-build1
-rwxr-xr-xtests/docker/test-mingw1
-rwxr-xr-xtests/docker/test-quick1
-rw-r--r--tests/e1000e-test.c2
-rw-r--r--tests/fdc-test.c2
-rw-r--r--tests/i440fx-test.c2
-rw-r--r--tests/i82801b11-test.c2
-rw-r--r--tests/intel-hda-test.c2
-rw-r--r--tests/ioh3420-test.c2
-rw-r--r--tests/ipmi-kcs-test.c3
-rw-r--r--tests/ivshmem-test.c3
-rw-r--r--tests/libqos/e1000e.c16
-rw-r--r--tests/libqos/virtio-mmio.c14
-rw-r--r--tests/libqos/virtio-pci.c14
-rw-r--r--tests/libqos/virtio.c20
-rw-r--r--tests/libqos/virtio.h6
-rw-r--r--tests/libqtest-single.h315
-rw-r--r--tests/libqtest.c13
-rw-r--r--tests/libqtest.h289
-rw-r--r--tests/m25p80-test.c2
-rw-r--r--tests/migration-test.c6
-rw-r--r--tests/pnv-xscom-test.c16
-rwxr-xr-xtests/qemu-iotests/0021
-rwxr-xr-xtests/qemu-iotests/0031
-rwxr-xr-xtests/qemu-iotests/0053
-rwxr-xr-xtests/qemu-iotests/0091
-rwxr-xr-xtests/qemu-iotests/0101
-rwxr-xr-xtests/qemu-iotests/0111
-rwxr-xr-xtests/qemu-iotests/0173
-rwxr-xr-xtests/qemu-iotests/0183
-rwxr-xr-xtests/qemu-iotests/0193
-rwxr-xr-xtests/qemu-iotests/0203
-rwxr-xr-xtests/qemu-iotests/0264
-rwxr-xr-xtests/qemu-iotests/0271
-rwxr-xr-xtests/qemu-iotests/0321
-rwxr-xr-xtests/qemu-iotests/0331
-rwxr-xr-xtests/qemu-iotests/0343
-rwxr-xr-xtests/qemu-iotests/0373
-rwxr-xr-xtests/qemu-iotests/0394
-rwxr-xr-xtests/qemu-iotests/0522
-rwxr-xr-xtests/qemu-iotests/05934
-rw-r--r--tests/qemu-iotests/059.out26
-rwxr-xr-xtests/qemu-iotests/0633
-rwxr-xr-xtests/qemu-iotests/0711
-rwxr-xr-xtests/qemu-iotests/0721
-rwxr-xr-xtests/qemu-iotests/0814
-rwxr-xr-xtests/qemu-iotests/0914
-rwxr-xr-xtests/qemu-iotests/0991
-rwxr-xr-xtests/qemu-iotests/1053
-rwxr-xr-xtests/qemu-iotests/1103
-rwxr-xr-xtests/qemu-iotests/1201
-rwxr-xr-xtests/qemu-iotests/1262
-rw-r--r--tests/qemu-iotests/150.out.qcow2 (renamed from tests/qemu-iotests/150.out)0
-rw-r--r--tests/qemu-iotests/150.out.raw12
-rwxr-xr-xtests/qemu-iotests/1624
-rwxr-xr-xtests/qemu-iotests/17547
-rw-r--r--tests/qemu-iotests/175.out16
-rw-r--r--tests/qemu-iotests/178.out.qcow24
-rwxr-xr-xtests/qemu-iotests/1841
-rwxr-xr-xtests/qemu-iotests/1861
-rwxr-xr-xtests/qemu-iotests/1971
-rwxr-xr-xtests/qemu-iotests/2151
-rw-r--r--tests/qemu-iotests/221.out12
-rw-r--r--tests/qemu-iotests/223.out4
-rw-r--r--tests/qemu-iotests/233.out10
-rwxr-xr-xtests/qemu-iotests/2511
-rw-r--r--tests/qemu-iotests/253.out12
-rwxr-xr-xtests/qemu-iotests/check6
-rw-r--r--tests/qemu-iotests/common.filter4
-rw-r--r--tests/qemu-iotests/common.rc14
-rw-r--r--tests/qos-test.c2
-rw-r--r--tests/requirements.txt2
-rw-r--r--tests/rtas-test.c1
-rw-r--r--tests/rtc-test.c2
-rw-r--r--tests/rtl8139-test.c2
-rw-r--r--tests/tcg/.gitignore5
-rw-r--r--tests/tcg/Makefile.include88
-rw-r--r--tests/tcg/Makefile.prereqs18
-rw-r--r--tests/tcg/Makefile.probe31
-rw-r--r--tests/tcg/Makefile.qemu95
-rw-r--r--tests/tcg/Makefile.target (renamed from tests/tcg/Makefile)15
-rw-r--r--tests/tcg/aarch64/Makefile.include8
-rw-r--r--tests/tcg/aarch64/Makefile.softmmu-target4
-rw-r--r--tests/tcg/aarch64/Makefile.target12
-rw-r--r--tests/tcg/alpha/Makefile.include2
-rw-r--r--tests/tcg/alpha/Makefile.softmmu-target4
-rw-r--r--tests/tcg/arm/Makefile.include8
-rw-r--r--tests/tcg/arm/Makefile.softmmu-target6
-rwxr-xr-xtests/tcg/configure.sh234
-rw-r--r--tests/tcg/cris/Makefile.include6
-rw-r--r--tests/tcg/hppa/Makefile.include2
-rw-r--r--tests/tcg/i386/Makefile.include9
-rw-r--r--tests/tcg/i386/Makefile.softmmu-target12
-rw-r--r--tests/tcg/i386/Makefile.target13
-rw-r--r--tests/tcg/m68k/Makefile.include2
-rw-r--r--tests/tcg/minilib/Makefile.target2
-rw-r--r--tests/tcg/mips/Makefile.include20
-rw-r--r--tests/tcg/multiarch/Makefile.target7
-rw-r--r--tests/tcg/ppc/Makefile.include10
-rw-r--r--tests/tcg/riscv/Makefile.include10
-rw-r--r--tests/tcg/s390x/Makefile.include2
-rw-r--r--tests/tcg/sh4/Makefile.include4
-rw-r--r--tests/tcg/sparc64/Makefile.include2
-rw-r--r--tests/tcg/x86_64/Makefile.softmmu-target36
-rw-r--r--tests/tcg/x86_64/Makefile.target7
-rw-r--r--tests/tcg/xtensa/Makefile.include11
-rw-r--r--tests/tcg/xtensa/Makefile.softmmu-target4
-rw-r--r--tests/test-arm-mptimer.c2
-rw-r--r--tests/test-char.c4
-rw-r--r--tests/test-io-channel-socket.c4
-rw-r--r--tests/test-netfilter.c2
-rw-r--r--tests/test-util-filemonitor.c43
-rw-r--r--tests/test-util-sockets.c12
-rw-r--r--tests/test-x86-cpuid-compat.c2
-rw-r--r--tests/tmp105-test.c2
-rw-r--r--tests/tpm-crb-test.c2
-rw-r--r--tests/tpm-emu.c2
-rw-r--r--tests/tpm-tests.c2
-rw-r--r--tests/tpm-tis-test.c2
-rw-r--r--tests/usb-hcd-ohci-test.c2
-rw-r--r--tests/usb-hcd-uhci-test.c2
-rw-r--r--tests/usb-hcd-xhci-test.c2
-rw-r--r--tests/vhost-user-test.c2
-rw-r--r--tests/virtio-9p-test.c2
-rw-r--r--tests/virtio-blk-test.c5
-rw-r--r--tests/virtio-ccw-test.c2
-rw-r--r--tests/virtio-net-test.c2
-rw-r--r--tests/virtio-scsi-test.c2
-rw-r--r--tests/virtio-serial-test.c2
-rw-r--r--tests/vm/Makefile.include1
-rwxr-xr-xtests/vm/fedora2
-rw-r--r--trace/mem-internal.h4
-rw-r--r--trace/mem.h4
-rw-r--r--ui/vnc.c4
-rw-r--r--util/memfd.c2
-rw-r--r--util/qemu-sockets.c33
-rw-r--r--util/trace-events3
413 files changed, 12573 insertions, 8197 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cd4c03372b..ed8067f5cf 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -59,7 +59,7 @@ build-user:
build-clang:
script:
- - apt-get install -y -qq clang libsdl2-dev
+ - apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-dev
xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev
- ./configure --cc=clang --cxx=clang++ --enable-werror
--target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu
diff --git a/.mailmap b/.mailmap
index b8e08297c9..0756a0bf66 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1,23 +1,29 @@
# This mailmap fixes up author names/addresses.
+#
+# If you are adding to this file consider if a similar change needs to
+# be made to contrib/gitdm/aliases. They are not however completely
+# analogous. .mailmap is concerned with fixing up damaged author
+# fields where as the gitdm equivalent is more concerned with making
+# sure multiple email addresses get mapped onto the same author.
+#
+# From man git-shortlog the forms are:
+#
+# Proper Name <commit@email.xx>
+# <proper@email.xx> <commit@email.xx>
+# Proper Name <proper@email.xx> <commit@email.xx>
+# Proper Name <proper@email.xx> Commit Name <commit@email.xx>
+#
# The first section translates weird addresses from the original git import
# into proper addresses so that they are counted properly by git shortlog.
Andrzej Zaborowski <balrogg@gmail.com> balrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Anthony Liguori <anthony@codemonkey.ws> aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
-Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
Aurelien Jarno <aurelien@aurel32.net> aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>
Blue Swirl <blauwirbel@gmail.com> blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
Edgar E. Iglesias <edgar.iglesias@gmail.com> edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>
Fabrice Bellard <fabrice@bellard.org> bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
-James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
Jocelyn Mayer <l_indien@magic.fr> j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Paul Brook <paul@codesourcery.com> pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>
-Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
-Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@mips.com>
-Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@imgtec.com>
-Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com>
-Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com>
-Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org>
Thiemo Seufer <ths@networkno.de> ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
@@ -32,8 +38,123 @@ Ian McKellar <ianloic@google.com> Ian McKellar via Qemu-devel <qemu-devel@nongnu
Julia Suvorova <jusual@mail.ru> Julia Suvorova via Qemu-devel <qemu-devel@nongnu.org>
Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu-devel@nongnu.org>
+# Next, replace old addresses by a more recent one.
+Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
+James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
+Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@mips.com>
+Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@imgtec.com>
+Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com>
+Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com>
+Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org>
+Philippe Mathieu-Daudé <philmd@redhat.com> <f4bug@amsat.org>
+Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
# Also list preferred name forms where people have changed their
# git author config, or had utf8/latin1 encoding issues.
+Aaron Lindsay <aaron@os.amperecomputing.com>
+Alexey Gerasimenko <x1917x@gmail.com>
+Alex Ivanov <void@aleksoft.net>
+Andreas Färber <afaerber@suse.de>
+Bandan Das <bsd@redhat.com>
+Benjamin MARSILI <mlspirat42@gmail.com>
+Benoît Canet <benoit.canet@gmail.com>
+Benoît Canet <benoit.canet@irqsave.net>
+Benoît Canet <benoit.canet@nodalink.com>
+Boqun Feng <boqun.feng@gmail.com>
+Boqun Feng <boqun.feng@intel.com>
+Brad Smith <brad@comstyle.com>
+Brijesh Singh <brijesh.singh@amd.com>
+Brilly Wu <brillywu@viatech.com.cn>
+Cédric Vincent <cedric.vincent@st.com>
+CheneyLin <linzc@zju.edu.cn>
+Chen Gang <chengang@emindsoft.com.cn>
+Chen Gang <gang.chen.5i5j@gmail.com>
+Chen Gang <gang.chen@sunrus.com.cn>
+Chen Wei-Ren <chenwj@iis.sinica.edu.tw>
+Christophe Lyon <christophe.lyon@st.com>
+Collin L. Walling <walling@linux.ibm.com>
Daniel P. Berrangé <berrange@redhat.com>
+Eduardo Otubo <otubo@redhat.com>
+Fabrice Desclaux <fabrice.desclaux@cea.fr>
+Fernando Luis Vázquez Cao <fernando_b1@lab.ntt.co.jp>
+Fernando Luis Vázquez Cao <fernando@oss.ntt.co.jp>
+Gautham R. Shenoy <ego@in.ibm.com>
+Gautham R. Shenoy <ego@linux.vnet.ibm.com>
+Gonglei (Arei) <arei.gonglei@huawei.com>
+Guang Wang <wang.guang55@zte.com.cn>
+Hailiang Zhang <zhang.zhanghailiang@huawei.com>
+Hervé Poussineau <hpoussin@reactos.org>
+Jakub Jermář <jakub@jermar.eu>
+Jakub Jermář <jakub.jermar@kernkonzept.com>
+Jean-Christophe Dubois <jcd@tribudubois.net>
+Jindřich Makovička <makovick@gmail.com>
+John Arbuckle <programmingkidx@gmail.com>
+Juha Riihimäki <juha.riihimaki@nokia.com>
+Juha Riihimäki <Juha.Riihimaki@nokia.com>
+Jun Li <junmuzi@gmail.com>
+Laurent Vivier <Laurent@lvivier.info>
+Leandro Lupori <leandro.lupori@gmail.com>
+Li Guang <lig.fnst@cn.fujitsu.com>
+Liming Wang <walimisdev@gmail.com>
+linzhecheng <linzc@zju.edu.cn>
+Liran Schour <lirans@il.ibm.com>
+Liu Yu <yu.liu@freescale.com>
+Liu Yu <Yu.Liu@freescale.com>
+Li Zhang <zhlcindy@gmail.com>
+Li Zhang <zhlcindy@linux.vnet.ibm.com>
+Lluís Vilanova <vilanova@ac.upc.edu>
+Lluís Vilanova <xscript@gmx.net>
+Longpeng (Mike) <longpeng2@huawei.com>
+Luc Michel <luc.michel@git.antfield.fr>
+Luc Michel <luc.michel@greensocs.com>
+Marc Marí <marc.mari.barcelo@gmail.com>
+Marc Marí <markmb@redhat.com>
+Michael Avdienko <whitearchey@gmail.com>
+Michael S. Tsirkin <mst@redhat.com>
+Munkyu Im <munkyu.im@samsung.com>
+Nicholas Bellinger <nab@linux-iscsi.org>
+Nicholas Thomas <nick@bytemark.co.uk>
+Nikunj A Dadhania <nikunj@linux.vnet.ibm.com>
+Orit Wasserman <owasserm@redhat.com>
+Paolo Bonzini <pbonzini@redhat.com>
+Pavel Dovgaluk <dovgaluk@ispras.ru>
+Pavel Dovgaluk <pavel.dovgaluk@gmail.com>
+Pavel Dovgaluk <Pavel.Dovgaluk@ispras.ru>
+Peter Crosthwaite <crosthwaite.peter@gmail.com>
+Peter Crosthwaite <peter.crosthwaite@petalogix.com>
+Peter Crosthwaite <peter.crosthwaite@xilinx.com>
+Prasad J Pandit <pjp@fedoraproject.org>
+Prasad J Pandit <ppandit@redhat.com>
+Qiao Nuohan <qiaonuohan@cn.fujitsu.com>
Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+Remy Noel <remy.noel@blade-group.com>
+Roger Pau Monné <roger.pau@citrix.com>
+Shin'ichiro Kawasaki <kawasaki@juno.dti.ne.jp>
+Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Sochin Jiang <sochin.jiang@huawei.com>
+Takashi Yoshii <takasi-y@ops.dti.ne.jp>
+Thomas Huth <thuth@redhat.com>
+Thomas Knych <thomaswk@google.com>
+Timothy Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
+Tony Nguyen <tony.nguyen@bt.com>
+Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
+Vibi Sreenivasan <vibi_sreenivasan@cms.com>
+Vijaya Kumar K <vijayak@cavium.com>
+Vijaya Kumar K <Vijaya.Kumar@cavium.com>
+Vijay Kumar <vijaykumar@bravegnu.org>
+Vijay Kumar <vijaykumar@zilogic.com>
+Wang Guang <wang.guang55@zte.com.cn>
+Wenchao Xia <xiawenc@linux.vnet.ibm.com>
+Wenshuang Ma <kevinnma@tencent.com>
+Xiaoqiang Zhao <zxq_yx_007@163.com>
+Xinhua Cao <caoxinhua@huawei.com>
+Xiong Zhang <xiong.y.zhang@intel.com>
+Yin Yin <yin.yin@cs2c.com.cn>
+yuchenlin <npes87184@gmail.com>
+YunQiang Su <syq@debian.org>
+YunQiang Su <ysu@wavecomp.com>
+Yuri Pudgorodskiy <yur@virtuozzo.com>
+Zhengui Li <lizhengui@huawei.com>
+Zhenwei Pi <pizhenwei@bytedance.com>
+Zhenwei Pi <zhenwei.pi@youruncloud.com>
+Zhuang Yanying <ann.zhuangyanying@huawei.com>
diff --git a/.shippable.yml b/.shippable.yml
index f74a3de3ff..bbc6f88510 100644
--- a/.shippable.yml
+++ b/.shippable.yml
@@ -27,6 +27,8 @@ env:
TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user
build:
pre_ci:
+ # usually host ARCH is set by configure
+ - echo "ARCH=$(uname -m)" > config-host.mak
- make docker-image-${IMAGE} V=1
pre_ci_boot:
image_name: qemu
diff --git a/.travis.yml b/.travis.yml
index caf0a1f8fa..d0b9e099b9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,18 @@ dist: xenial
language: c
compiler:
- gcc
-cache: ccache
+cache:
+ # There is one cache per branch and compiler version.
+ # characteristics of each job are used to identify the cache:
+ # - OS name (currently, linux, osx, or windows)
+ # - OS distribution (for Linux, xenial, trusty, or precise)
+ # - macOS image name (e.g., xcode7.2)
+ # - Names and values of visible environment variables set in .travis.yml or Settings panel
+ timeout: 1200
+ ccache: true
+ pip: true
+ directories:
+ - $HOME/avocado/data/cache
addons:
@@ -15,6 +26,7 @@ addons:
- libaio-dev
- libattr1-dev
- libbrlapi-dev
+ - libcap-dev
- libcap-ng-dev
- libgcc-4.8-dev
- libgnutls-dev
@@ -40,6 +52,7 @@ addons:
- gcovr
homebrew:
packages:
+ - ccache
- glib
- pixman
- gnu-sed
@@ -65,6 +78,9 @@ env:
- TEST_CMD="make check -j3 V=1"
# This is broadly a list of "mainline" softmmu targets which have support across the major distros
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
+ - CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
+ - CCACHE_MAXSIZE=1G
+
git:
# we want to do this ourselves
@@ -72,25 +88,32 @@ git:
before_script:
+ - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then export PATH="/usr/local/opt/ccache/libexec:$PATH" ; fi
+ - command -v ccache && ccache --zero-stats
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
script:
- make -j3 && travis_retry ${TEST_CMD}
+after_script:
+ - command -v ccache && ccache --show-stats
matrix:
include:
- env:
- CONFIG="--disable-system --static"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
# we split the system builds as it takes a while to build them all
- env:
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
- env:
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
# Just build tools and run minimal unit and softfloat checks
@@ -98,14 +121,18 @@ matrix:
- BASE_CONFIG="--enable-tools"
- CONFIG="--disable-user --disable-system"
- TEST_CMD="make check-unit check-softfloat -j3"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
+
- env:
- CONFIG="--enable-debug --enable-debug-tcg --disable-user"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug"
# TCG debug can be run just on it's own and is mostly agnostic to user/softmmu distinctions
- env:
- CONFIG="--enable-debug-tcg --disable-system"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug"
- env:
@@ -115,6 +142,7 @@ matrix:
# Module builds are mostly of interest to major distros
- env:
- CONFIG="--enable-modules --target-list=${MAIN_SOFTMMU_TARGETS}"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
# Alternate coroutines implementations are only really of interest to KVM users
@@ -134,6 +162,7 @@ matrix:
- BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
- BASE_CONFIG="--enable-tools --enable-docs"
- CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
addons:
apt:
packages:
@@ -145,11 +174,13 @@ matrix:
# Test with Clang for compile portability (Travis uses clang-5.0)
- env:
- CONFIG="--disable-system"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
compiler: clang
- env:
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
compiler: clang
@@ -162,6 +193,7 @@ matrix:
- env:
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
compiler: clang
@@ -175,6 +207,7 @@ matrix:
# We manually include builds which we disable "make check" for
- env:
- CONFIG="--without-default-devices --disable-user"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
- TEST_CMD=""
@@ -218,6 +251,7 @@ matrix:
# Python builds
- env:
- CONFIG="--target-list=x86_64-softmmu"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
language: python
python:
- "3.4"
@@ -225,6 +259,7 @@ matrix:
- env:
- CONFIG="--target-list=x86_64-softmmu"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
language: python
python:
- "3.6"
@@ -232,15 +267,20 @@ matrix:
# Acceptance (Functional) tests
- env:
- - CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu"
+ - CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu,ppc64-softmmu,m68k-softmmu"
- TEST_CMD="make check-acceptance"
after_failure:
- cat tests/results/latest/job.log
addons:
apt:
packages:
+ - python3-pil
- python3-pip
- python3.5-venv
+ - tesseract-ocr
+ - tesseract-ocr-eng
+
+
# Using newer GCC with sanitizers
- addons:
apt:
@@ -291,8 +331,11 @@ matrix:
- env:
- CONFIG="--disable-system"
- TEST_CMD="make -j3 check-tcg V=1"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
+
# Run check-tcg against softmmu targets
- env:
- CONFIG="--target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
- TEST_CMD="make -j3 check-tcg V=1"
+ - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
diff --git a/CODING_STYLE b/CODING_STYLE
deleted file mode 100644
index cb8edcbb36..0000000000
--- a/CODING_STYLE
+++ /dev/null
@@ -1,216 +0,0 @@
-QEMU Coding Style
-=================
-
-Please use the script checkpatch.pl in the scripts directory to check
-patches before submitting.
-
-1. Whitespace
-
-Of course, the most important aspect in any coding style is whitespace.
-Crusty old coders who have trouble spotting the glasses on their noses
-can tell the difference between a tab and eight spaces from a distance
-of approximately fifteen parsecs. Many a flamewar has been fought and
-lost on this issue.
-
-QEMU indents are four spaces. Tabs are never used, except in Makefiles
-where they have been irreversibly coded into the syntax.
-Spaces of course are superior to tabs because:
-
- - You have just one way to specify whitespace, not two. Ambiguity breeds
- mistakes.
- - The confusion surrounding 'use tabs to indent, spaces to justify' is gone.
- - Tab indents push your code to the right, making your screen seriously
- unbalanced.
- - Tabs will be rendered incorrectly on editors who are misconfigured not
- to use tab stops of eight positions.
- - Tabs are rendered badly in patches, causing off-by-one errors in almost
- every line.
- - It is the QEMU coding style.
-
-Do not leave whitespace dangling off the ends of lines.
-
-1.1 Multiline Indent
-
-There are several places where indent is necessary:
-
- - if/else
- - while/for
- - function definition & call
-
-When breaking up a long line to fit within line width, we need a proper indent
-for the following lines.
-
-In case of if/else, while/for, align the secondary lines just after the
-opening parenthesis of the first.
-
-For example:
-
- if (a == 1 &&
- b == 2) {
-
- while (a == 1 &&
- b == 2) {
-
-In case of function, there are several variants:
-
- * 4 spaces indent from the beginning
- * align the secondary lines just after the opening parenthesis of the
- first
-
-For example:
-
- do_something(x, y,
- z);
-
- do_something(x, y,
- z);
-
- do_something(x, do_another(y,
- z));
-
-2. Line width
-
-Lines should be 80 characters; try not to make them longer.
-
-Sometimes it is hard to do, especially when dealing with QEMU subsystems
-that use long function or symbol names. Even in that case, do not make
-lines much longer than 80 characters.
-
-Rationale:
- - Some people like to tile their 24" screens with a 6x4 matrix of 80x24
- xterms and use vi in all of them. The best way to punish them is to
- let them keep doing it.
- - Code and especially patches is much more readable if limited to a sane
- line length. Eighty is traditional.
- - The four-space indentation makes the most common excuse ("But look
- at all that white space on the left!") moot.
- - It is the QEMU coding style.
-
-3. Naming
-
-Variables are lower_case_with_underscores; easy to type and read. Structured
-type names are in CamelCase; harder to type but standing out. Enum type
-names and function type names should also be in CamelCase. Scalar type
-names are lower_case_with_underscores_ending_with_a_t, like the POSIX
-uint64_t and family. Note that this last convention contradicts POSIX
-and is therefore likely to be changed.
-
-When wrapping standard library functions, use the prefix qemu_ to alert
-readers that they are seeing a wrapped version; otherwise avoid this prefix.
-
-4. Block structure
-
-Every indented statement is braced; even if the block contains just one
-statement. The opening brace is on the line that contains the control
-flow statement that introduces the new block; the closing brace is on the
-same line as the else keyword, or on a line by itself if there is no else
-keyword. Example:
-
- if (a == 5) {
- printf("a was 5.\n");
- } else if (a == 6) {
- printf("a was 6.\n");
- } else {
- printf("a was something else entirely.\n");
- }
-
-Note that 'else if' is considered a single statement; otherwise a long if/
-else if/else if/.../else sequence would need an indent for every else
-statement.
-
-An exception is the opening brace for a function; for reasons of tradition
-and clarity it comes on a line by itself:
-
- void a_function(void)
- {
- do_something();
- }
-
-Rationale: a consistent (except for functions...) bracing style reduces
-ambiguity and avoids needless churn when lines are added or removed.
-Furthermore, it is the QEMU coding style.
-
-5. Declarations
-
-Mixed declarations (interleaving statements and declarations within
-blocks) are generally not allowed; declarations should be at the beginning
-of blocks.
-
-Every now and then, an exception is made for declarations inside a
-#ifdef or #ifndef block: if the code looks nicer, such declarations can
-be placed at the top of the block even if there are statements above.
-On the other hand, however, it's often best to move that #ifdef/#ifndef
-block to a separate function altogether.
-
-6. Conditional statements
-
-When comparing a variable for (in)equality with a constant, list the
-constant on the right, as in:
-
- if (a == 1) {
- /* Reads like: "If a equals 1" */
- do_something();
- }
-
-Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read.
-Besides, good compilers already warn users when '==' is mis-typed as '=',
-even when the constant is on the right.
-
-7. Comment style
-
-We use traditional C-style /* */ comments and avoid // comments.
-
-Rationale: The // form is valid in C99, so this is purely a matter of
-consistency of style. The checkpatch script will warn you about this.
-
-Multiline comment blocks should have a row of stars on the left,
-and the initial /* and terminating */ both on their own lines:
- /*
- * like
- * this
- */
-This is the same format required by the Linux kernel coding style.
-
-(Some of the existing comments in the codebase use the GNU Coding
-Standards form which does not have stars on the left, or other
-variations; avoid these when writing new comments, but don't worry
-about converting to the preferred form unless you're editing that
-comment anyway.)
-
-Rationale: Consistency, and ease of visually picking out a multiline
-comment from the surrounding code.
-
-8. trace-events style
-
-8.1 0x prefix
-
-In trace-events files, use a '0x' prefix to specify hex numbers, as in:
-
-some_trace(unsigned x, uint64_t y) "x 0x%x y 0x" PRIx64
-
-An exception is made for groups of numbers that are hexadecimal by
-convention and separated by the symbols '.', '/', ':', or ' ' (such as
-PCI bus id):
-
-another_trace(int cssid, int ssid, int dev_num) "bus id: %x.%x.%04x"
-
-However, you can use '0x' for such groups if you want. Anyway, be sure that
-it is obvious that numbers are in hex, ex.:
-
-data_dump(uint8_t c1, uint8_t c2, uint8_t c3) "bytes (in hex): %02x %02x %02x"
-
-Rationale: hex numbers are hard to read in logs when there is no 0x prefix,
-especially when (occasionally) the representation doesn't contain any letters
-and especially in one line with other decimal numbers. Number groups are allowed
-to not use '0x' because for some things notations like %x.%x.%x are used not
-only in Qemu. Also dumping raw data bytes with '0x' is less readable.
-
-8.2 '#' printf flag
-
-Do not use printf flag '#', like '%#x'.
-
-Rationale: there are two ways to add a '0x' prefix to printed number: '0x%...'
-and '%#...'. For consistency the only one way should be used. Arguments for
-'0x%' are:
- - it is more popular
- - '%#' omits the 0x for the value 0 which makes output inconsistent
diff --git a/CODING_STYLE.rst b/CODING_STYLE.rst
new file mode 100644
index 0000000000..427699e0e4
--- /dev/null
+++ b/CODING_STYLE.rst
@@ -0,0 +1,641 @@
+=================
+QEMU Coding Style
+=================
+
+.. contents:: Table of Contents
+
+Please use the script checkpatch.pl in the scripts directory to check
+patches before submitting.
+
+Formatting and style
+********************
+
+Whitespace
+==========
+
+Of course, the most important aspect in any coding style is whitespace.
+Crusty old coders who have trouble spotting the glasses on their noses
+can tell the difference between a tab and eight spaces from a distance
+of approximately fifteen parsecs. Many a flamewar has been fought and
+lost on this issue.
+
+QEMU indents are four spaces. Tabs are never used, except in Makefiles
+where they have been irreversibly coded into the syntax.
+Spaces of course are superior to tabs because:
+
+* You have just one way to specify whitespace, not two. Ambiguity breeds
+ mistakes.
+* The confusion surrounding 'use tabs to indent, spaces to justify' is gone.
+* Tab indents push your code to the right, making your screen seriously
+ unbalanced.
+* Tabs will be rendered incorrectly on editors who are misconfigured not
+ to use tab stops of eight positions.
+* Tabs are rendered badly in patches, causing off-by-one errors in almost
+ every line.
+* It is the QEMU coding style.
+
+Do not leave whitespace dangling off the ends of lines.
+
+Multiline Indent
+----------------
+
+There are several places where indent is necessary:
+
+* if/else
+* while/for
+* function definition & call
+
+When breaking up a long line to fit within line width, we need a proper indent
+for the following lines.
+
+In case of if/else, while/for, align the secondary lines just after the
+opening parenthesis of the first.
+
+For example:
+
+.. code-block:: c
+
+ if (a == 1 &&
+ b == 2) {
+
+ while (a == 1 &&
+ b == 2) {
+
+In case of function, there are several variants:
+
+* 4 spaces indent from the beginning
+* align the secondary lines just after the opening parenthesis of the first
+
+For example:
+
+.. code-block:: c
+
+ do_something(x, y,
+ z);
+
+ do_something(x, y,
+ z);
+
+ do_something(x, do_another(y,
+ z));
+
+Line width
+==========
+
+Lines should be 80 characters; try not to make them longer.
+
+Sometimes it is hard to do, especially when dealing with QEMU subsystems
+that use long function or symbol names. Even in that case, do not make
+lines much longer than 80 characters.
+
+Rationale:
+
+* Some people like to tile their 24" screens with a 6x4 matrix of 80x24
+ xterms and use vi in all of them. The best way to punish them is to
+ let them keep doing it.
+* Code and especially patches is much more readable if limited to a sane
+ line length. Eighty is traditional.
+* The four-space indentation makes the most common excuse ("But look
+ at all that white space on the left!") moot.
+* It is the QEMU coding style.
+
+Naming
+======
+
+Variables are lower_case_with_underscores; easy to type and read. Structured
+type names are in CamelCase; harder to type but standing out. Enum type
+names and function type names should also be in CamelCase. Scalar type
+names are lower_case_with_underscores_ending_with_a_t, like the POSIX
+uint64_t and family. Note that this last convention contradicts POSIX
+and is therefore likely to be changed.
+
+When wrapping standard library functions, use the prefix ``qemu_`` to alert
+readers that they are seeing a wrapped version; otherwise avoid this prefix.
+
+Block structure
+===============
+
+Every indented statement is braced; even if the block contains just one
+statement. The opening brace is on the line that contains the control
+flow statement that introduces the new block; the closing brace is on the
+same line as the else keyword, or on a line by itself if there is no else
+keyword. Example:
+
+.. code-block:: c
+
+ if (a == 5) {
+ printf("a was 5.\n");
+ } else if (a == 6) {
+ printf("a was 6.\n");
+ } else {
+ printf("a was something else entirely.\n");
+ }
+
+Note that 'else if' is considered a single statement; otherwise a long if/
+else if/else if/.../else sequence would need an indent for every else
+statement.
+
+An exception is the opening brace for a function; for reasons of tradition
+and clarity it comes on a line by itself:
+
+.. code-block:: c
+
+ void a_function(void)
+ {
+ do_something();
+ }
+
+Rationale: a consistent (except for functions...) bracing style reduces
+ambiguity and avoids needless churn when lines are added or removed.
+Furthermore, it is the QEMU coding style.
+
+Declarations
+============
+
+Mixed declarations (interleaving statements and declarations within
+blocks) are generally not allowed; declarations should be at the beginning
+of blocks.
+
+Every now and then, an exception is made for declarations inside a
+#ifdef or #ifndef block: if the code looks nicer, such declarations can
+be placed at the top of the block even if there are statements above.
+On the other hand, however, it's often best to move that #ifdef/#ifndef
+block to a separate function altogether.
+
+Conditional statements
+======================
+
+When comparing a variable for (in)equality with a constant, list the
+constant on the right, as in:
+
+.. code-block:: c
+
+ if (a == 1) {
+ /* Reads like: "If a equals 1" */
+ do_something();
+ }
+
+Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read.
+Besides, good compilers already warn users when '==' is mis-typed as '=',
+even when the constant is on the right.
+
+Comment style
+=============
+
+We use traditional C-style /``*`` ``*``/ comments and avoid // comments.
+
+Rationale: The // form is valid in C99, so this is purely a matter of
+consistency of style. The checkpatch script will warn you about this.
+
+Multiline comment blocks should have a row of stars on the left,
+and the initial /``*`` and terminating ``*``/ both on their own lines:
+
+.. code-block:: c
+
+ /*
+ * like
+ * this
+ */
+
+This is the same format required by the Linux kernel coding style.
+
+(Some of the existing comments in the codebase use the GNU Coding
+Standards form which does not have stars on the left, or other
+variations; avoid these when writing new comments, but don't worry
+about converting to the preferred form unless you're editing that
+comment anyway.)
+
+Rationale: Consistency, and ease of visually picking out a multiline
+comment from the surrounding code.
+
+Language usage
+**************
+
+Preprocessor
+============
+
+Variadic macros
+---------------
+
+For variadic macros, stick with this C99-like syntax:
+
+.. code-block:: c
+
+ #define DPRINTF(fmt, ...) \
+ do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0)
+
+Include directives
+------------------
+
+Order include directives as follows:
+
+.. code-block:: c
+
+ #include "qemu/osdep.h" /* Always first... */
+ #include <...> /* then system headers... */
+ #include "..." /* and finally QEMU headers. */
+
+The "qemu/osdep.h" header contains preprocessor macros that affect the behavior
+of core system headers like <stdint.h>. It must be the first include so that
+core system headers included by external libraries get the preprocessor macros
+that QEMU depends on.
+
+Do not include "qemu/osdep.h" from header files since the .c file will have
+already included it.
+
+C types
+=======
+
+It should be common sense to use the right type, but we have collected
+a few useful guidelines here.
+
+Scalars
+-------
+
+If you're using "int" or "long", odds are good that there's a better type.
+If a variable is counting something, it should be declared with an
+unsigned type.
+
+If it's host memory-size related, size_t should be a good choice (use
+ssize_t only if required). Guest RAM memory offsets must use ram_addr_t,
+but only for RAM, it may not cover whole guest address space.
+
+If it's file-size related, use off_t.
+If it's file-offset related (i.e., signed), use off_t.
+If it's just counting small numbers use "unsigned int";
+(on all but oddball embedded systems, you can assume that that
+type is at least four bytes wide).
+
+In the event that you require a specific width, use a standard type
+like int32_t, uint32_t, uint64_t, etc. The specific types are
+mandatory for VMState fields.
+
+Don't use Linux kernel internal types like u32, __u32 or __le32.
+
+Use hwaddr for guest physical addresses except pcibus_t
+for PCI addresses. In addition, ram_addr_t is a QEMU internal address
+space that maps guest RAM physical addresses into an intermediate
+address space that can map to host virtual address spaces. Generally
+speaking, the size of guest memory can always fit into ram_addr_t but
+it would not be correct to store an actual guest physical address in a
+ram_addr_t.
+
+For CPU virtual addresses there are several possible types.
+vaddr is the best type to use to hold a CPU virtual address in
+target-independent code. It is guaranteed to be large enough to hold a
+virtual address for any target, and it does not change size from target
+to target. It is always unsigned.
+target_ulong is a type the size of a virtual address on the CPU; this means
+it may be 32 or 64 bits depending on which target is being built. It should
+therefore be used only in target-specific code, and in some
+performance-critical built-per-target core code such as the TLB code.
+There is also a signed version, target_long.
+abi_ulong is for the ``*``-user targets, and represents a type the size of
+'void ``*``' in that target's ABI. (This may not be the same as the size of a
+full CPU virtual address in the case of target ABIs which use 32 bit pointers
+on 64 bit CPUs, like sparc32plus.) Definitions of structures that must match
+the target's ABI must use this type for anything that on the target is defined
+to be an 'unsigned long' or a pointer type.
+There is also a signed version, abi_long.
+
+Of course, take all of the above with a grain of salt. If you're about
+to use some system interface that requires a type like size_t, pid_t or
+off_t, use matching types for any corresponding variables.
+
+Also, if you try to use e.g., "unsigned int" as a type, and that
+conflicts with the signedness of a related variable, sometimes
+it's best just to use the *wrong* type, if "pulling the thread"
+and fixing all related variables would be too invasive.
+
+Finally, while using descriptive types is important, be careful not to
+go overboard. If whatever you're doing causes warnings, or requires
+casts, then reconsider or ask for help.
+
+Pointers
+--------
+
+Ensure that all of your pointers are "const-correct".
+Unless a pointer is used to modify the pointed-to storage,
+give it the "const" attribute. That way, the reader knows
+up-front that this is a read-only pointer. Perhaps more
+importantly, if we're diligent about this, when you see a non-const
+pointer, you're guaranteed that it is used to modify the storage
+it points to, or it is aliased to another pointer that is.
+
+Typedefs
+--------
+
+Typedefs are used to eliminate the redundant 'struct' keyword, since type
+names have a different style than other identifiers ("CamelCase" versus
+"snake_case"). Each named struct type should have a CamelCase name and a
+corresponding typedef.
+
+Since certain C compilers choke on duplicated typedefs, you should avoid
+them and declare a typedef only in one header file. For common types,
+you can use "include/qemu/typedefs.h" for example. However, as a matter
+of convenience it is also perfectly fine to use forward struct
+definitions instead of typedefs in headers and function prototypes; this
+avoids problems with duplicated typedefs and reduces the need to include
+headers from other headers.
+
+Reserved namespaces in C and POSIX
+----------------------------------
+
+Underscore capital, double underscore, and underscore 't' suffixes should be
+avoided.
+
+Low level memory management
+===========================
+
+Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
+APIs is not allowed in the QEMU codebase. Instead of these routines,
+use the GLib memory allocation routines g_malloc/g_malloc0/g_new/
+g_new0/g_realloc/g_free or QEMU's qemu_memalign/qemu_blockalign/qemu_vfree
+APIs.
+
+Please note that g_malloc will exit on allocation failure, so there
+is no need to test for failure (as you would have to with malloc).
+Calling g_malloc with a zero size is valid and will return NULL.
+
+Prefer g_new(T, n) instead of g_malloc(sizeof(T) ``*`` n) for the following
+reasons:
+
+* It catches multiplication overflowing size_t;
+* It returns T ``*`` instead of void ``*``, letting compiler catch more type errors.
+
+Declarations like
+
+.. code-block:: c
+
+ T *v = g_malloc(sizeof(*v))
+
+are acceptable, though.
+
+Memory allocated by qemu_memalign or qemu_blockalign must be freed with
+qemu_vfree, since breaking this will cause problems on Win32.
+
+String manipulation
+===================
+
+Do not use the strncpy function. As mentioned in the man page, it does *not*
+guarantee a NULL-terminated buffer, which makes it extremely dangerous to use.
+It also zeros trailing destination bytes out to the specified length. Instead,
+use this similar function when possible, but note its different signature:
+
+.. code-block:: c
+
+ void pstrcpy(char *dest, int dest_buf_size, const char *src)
+
+Don't use strcat because it can't check for buffer overflows, but:
+
+.. code-block:: c
+
+ char *pstrcat(char *buf, int buf_size, const char *s)
+
+The same limitation exists with sprintf and vsprintf, so use snprintf and
+vsnprintf.
+
+QEMU provides other useful string functions:
+
+.. code-block:: c
+
+ int strstart(const char *str, const char *val, const char **ptr)
+ int stristart(const char *str, const char *val, const char **ptr)
+ int qemu_strnlen(const char *s, int max_len)
+
+There are also replacement character processing macros for isxyz and toxyz,
+so instead of e.g. isalnum you should use qemu_isalnum.
+
+Because of the memory management rules, you must use g_strdup/g_strndup
+instead of plain strdup/strndup.
+
+Printf-style functions
+======================
+
+Whenever you add a new printf-style function, i.e., one with a format
+string argument and following "..." in its prototype, be sure to use
+gcc's printf attribute directive in the prototype.
+
+This makes it so gcc's -Wformat and -Wformat-security options can do
+their jobs and cross-check format strings with the number and types
+of arguments.
+
+C standard, implementation defined and undefined behaviors
+==========================================================
+
+C code in QEMU should be written to the C99 language specification. A copy
+of the final version of the C99 standard with corrigenda TC1, TC2, and TC3
+included, formatted as a draft, can be downloaded from:
+
+ `<http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf>`_
+
+The C language specification defines regions of undefined behavior and
+implementation defined behavior (to give compiler authors enough leeway to
+produce better code). In general, code in QEMU should follow the language
+specification and avoid both undefined and implementation defined
+constructs. ("It works fine on the gcc I tested it with" is not a valid
+argument...) However there are a few areas where we allow ourselves to
+assume certain behaviors because in practice all the platforms we care about
+behave in the same way and writing strictly conformant code would be
+painful. These are:
+
+* you may assume that integers are 2s complement representation
+* you may assume that right shift of a signed integer duplicates
+ the sign bit (ie it is an arithmetic shift, not a logical shift)
+
+In addition, QEMU assumes that the compiler does not use the latitude
+given in C99 and C11 to treat aspects of signed '<<' as undefined, as
+documented in the GNU Compiler Collection manual starting at version 4.0.
+
+Automatic memory deallocation
+=============================
+
+QEMU has a mandatory dependency either the GCC or CLang compiler. As
+such it has the freedom to make use of a C language extension for
+automatically running a cleanup function when a stack variable goes
+out of scope. This can be used to simplify function cleanup paths,
+often allowing many goto jumps to be eliminated, through automatic
+free'ing of memory.
+
+The GLib2 library provides a number of functions/macros for enabling
+automatic cleanup:
+
+ `<https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html>`_
+
+Most notably:
+
+* g_autofree - will invoke g_free() on the variable going out of scope
+
+* g_autoptr - for structs / objects, will invoke the cleanup func created
+ by a previous use of G_DEFINE_AUTOPTR_CLEANUP_FUNC. This is
+ supported for most GLib data types and GObjects
+
+For example, instead of
+
+.. code-block:: c
+
+ int somefunc(void) {
+ int ret = -1;
+ char *foo = g_strdup_printf("foo%", "wibble");
+ GList *bar = .....
+
+ if (eek) {
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ g_free(foo);
+ g_list_free(bar);
+ return ret;
+ }
+
+Using g_autofree/g_autoptr enables the code to be written as:
+
+.. code-block:: c
+
+ int somefunc(void) {
+ g_autofree char *foo = g_strdup_printf("foo%", "wibble");
+ g_autoptr (GList) bar = .....
+
+ if (eek) {
+ return -1;
+ }
+
+ return 0;
+ }
+
+While this generally results in simpler, less leak-prone code, there
+are still some caveats to beware of
+
+* Variables declared with g_auto* MUST always be initialized,
+ otherwise the cleanup function will use uninitialized stack memory
+
+* If a variable declared with g_auto* holds a value which must
+ live beyond the life of the function, that value must be saved
+ and the original variable NULL'd out. This can be simpler using
+ g_steal_pointer
+
+
+.. code-block:: c
+
+ char *somefunc(void) {
+ g_autofree char *foo = g_strdup_printf("foo%", "wibble");
+ g_autoptr (GList) bar = .....
+
+ if (eek) {
+ return NULL;
+ }
+
+ return g_steal_pointer(&foo);
+ }
+
+
+QEMU Specific Idioms
+********************
+
+Error handling and reporting
+============================
+
+Reporting errors to the human user
+----------------------------------
+
+Do not use printf(), fprintf() or monitor_printf(). Instead, use
+error_report() or error_vreport() from error-report.h. This ensures the
+error is reported in the right place (current monitor or stderr), and in
+a uniform format.
+
+Use error_printf() & friends to print additional information.
+
+error_report() prints the current location. In certain common cases
+like command line parsing, the current location is tracked
+automatically. To manipulate it manually, use the loc_``*``() from
+error-report.h.
+
+Propagating errors
+------------------
+
+An error can't always be reported to the user right where it's detected,
+but often needs to be propagated up the call chain to a place that can
+handle it. This can be done in various ways.
+
+The most flexible one is Error objects. See error.h for usage
+information.
+
+Use the simplest suitable method to communicate success / failure to
+callers. Stick to common methods: non-negative on success / -1 on
+error, non-negative / -errno, non-null / null, or Error objects.
+
+Example: when a function returns a non-null pointer on success, and it
+can fail only in one way (as far as the caller is concerned), returning
+null on failure is just fine, and certainly simpler and a lot easier on
+the eyes than propagating an Error object through an Error ``*````*`` parameter.
+
+Example: when a function's callers need to report details on failure
+only the function really knows, use Error ``*````*``, and set suitable errors.
+
+Do not report an error to the user when you're also returning an error
+for somebody else to handle. Leave the reporting to the place that
+consumes the error returned.
+
+Handling errors
+---------------
+
+Calling exit() is fine when handling configuration errors during
+startup. It's problematic during normal operation. In particular,
+monitor commands should never exit().
+
+Do not call exit() or abort() to handle an error that can be triggered
+by the guest (e.g., some unimplemented corner case in guest code
+translation or device emulation). Guests should not be able to
+terminate QEMU.
+
+Note that &error_fatal is just another way to exit(1), and &error_abort
+is just another way to abort().
+
+
+trace-events style
+==================
+
+0x prefix
+---------
+
+In trace-events files, use a '0x' prefix to specify hex numbers, as in:
+
+.. code-block::
+
+ some_trace(unsigned x, uint64_t y) "x 0x%x y 0x" PRIx64
+
+An exception is made for groups of numbers that are hexadecimal by
+convention and separated by the symbols '.', '/', ':', or ' ' (such as
+PCI bus id):
+
+.. code-block::
+
+ another_trace(int cssid, int ssid, int dev_num) "bus id: %x.%x.%04x"
+
+However, you can use '0x' for such groups if you want. Anyway, be sure that
+it is obvious that numbers are in hex, ex.:
+
+.. code-block::
+
+ data_dump(uint8_t c1, uint8_t c2, uint8_t c3) "bytes (in hex): %02x %02x %02x"
+
+Rationale: hex numbers are hard to read in logs when there is no 0x prefix,
+especially when (occasionally) the representation doesn't contain any letters
+and especially in one line with other decimal numbers. Number groups are allowed
+to not use '0x' because for some things notations like %x.%x.%x are used not
+only in Qemu. Also dumping raw data bytes with '0x' is less readable.
+
+'#' printf flag
+---------------
+
+Do not use printf flag '#', like '%#x'.
+
+Rationale: there are two ways to add a '0x' prefix to printed number: '0x%...'
+and '%#...'. For consistency the only one way should be used. Arguments for
+'0x%' are:
+
+* it is more popular
+* '%#' omits the 0x for the value 0 which makes output inconsistent
diff --git a/HACKING b/HACKING
deleted file mode 100644
index 097d482603..0000000000
--- a/HACKING
+++ /dev/null
@@ -1,257 +0,0 @@
-1. Preprocessor
-
-1.1. Variadic macros
-
-For variadic macros, stick with this C99-like syntax:
-
-#define DPRINTF(fmt, ...) \
- do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0)
-
-1.2. Include directives
-
-Order include directives as follows:
-
-#include "qemu/osdep.h" /* Always first... */
-#include <...> /* then system headers... */
-#include "..." /* and finally QEMU headers. */
-
-The "qemu/osdep.h" header contains preprocessor macros that affect the behavior
-of core system headers like <stdint.h>. It must be the first include so that
-core system headers included by external libraries get the preprocessor macros
-that QEMU depends on.
-
-Do not include "qemu/osdep.h" from header files since the .c file will have
-already included it.
-
-2. C types
-
-It should be common sense to use the right type, but we have collected
-a few useful guidelines here.
-
-2.1. Scalars
-
-If you're using "int" or "long", odds are good that there's a better type.
-If a variable is counting something, it should be declared with an
-unsigned type.
-
-If it's host memory-size related, size_t should be a good choice (use
-ssize_t only if required). Guest RAM memory offsets must use ram_addr_t,
-but only for RAM, it may not cover whole guest address space.
-
-If it's file-size related, use off_t.
-If it's file-offset related (i.e., signed), use off_t.
-If it's just counting small numbers use "unsigned int";
-(on all but oddball embedded systems, you can assume that that
-type is at least four bytes wide).
-
-In the event that you require a specific width, use a standard type
-like int32_t, uint32_t, uint64_t, etc. The specific types are
-mandatory for VMState fields.
-
-Don't use Linux kernel internal types like u32, __u32 or __le32.
-
-Use hwaddr for guest physical addresses except pcibus_t
-for PCI addresses. In addition, ram_addr_t is a QEMU internal address
-space that maps guest RAM physical addresses into an intermediate
-address space that can map to host virtual address spaces. Generally
-speaking, the size of guest memory can always fit into ram_addr_t but
-it would not be correct to store an actual guest physical address in a
-ram_addr_t.
-
-For CPU virtual addresses there are several possible types.
-vaddr is the best type to use to hold a CPU virtual address in
-target-independent code. It is guaranteed to be large enough to hold a
-virtual address for any target, and it does not change size from target
-to target. It is always unsigned.
-target_ulong is a type the size of a virtual address on the CPU; this means
-it may be 32 or 64 bits depending on which target is being built. It should
-therefore be used only in target-specific code, and in some
-performance-critical built-per-target core code such as the TLB code.
-There is also a signed version, target_long.
-abi_ulong is for the *-user targets, and represents a type the size of
-'void *' in that target's ABI. (This may not be the same as the size of a
-full CPU virtual address in the case of target ABIs which use 32 bit pointers
-on 64 bit CPUs, like sparc32plus.) Definitions of structures that must match
-the target's ABI must use this type for anything that on the target is defined
-to be an 'unsigned long' or a pointer type.
-There is also a signed version, abi_long.
-
-Of course, take all of the above with a grain of salt. If you're about
-to use some system interface that requires a type like size_t, pid_t or
-off_t, use matching types for any corresponding variables.
-
-Also, if you try to use e.g., "unsigned int" as a type, and that
-conflicts with the signedness of a related variable, sometimes
-it's best just to use the *wrong* type, if "pulling the thread"
-and fixing all related variables would be too invasive.
-
-Finally, while using descriptive types is important, be careful not to
-go overboard. If whatever you're doing causes warnings, or requires
-casts, then reconsider or ask for help.
-
-2.2. Pointers
-
-Ensure that all of your pointers are "const-correct".
-Unless a pointer is used to modify the pointed-to storage,
-give it the "const" attribute. That way, the reader knows
-up-front that this is a read-only pointer. Perhaps more
-importantly, if we're diligent about this, when you see a non-const
-pointer, you're guaranteed that it is used to modify the storage
-it points to, or it is aliased to another pointer that is.
-
-2.3. Typedefs
-
-Typedefs are used to eliminate the redundant 'struct' keyword, since type
-names have a different style than other identifiers ("CamelCase" versus
-"snake_case"). Each named struct type should have a CamelCase name and a
-corresponding typedef.
-
-Since certain C compilers choke on duplicated typedefs, you should avoid
-them and declare a typedef only in one header file. For common types,
-you can use "include/qemu/typedefs.h" for example. However, as a matter
-of convenience it is also perfectly fine to use forward struct
-definitions instead of typedefs in headers and function prototypes; this
-avoids problems with duplicated typedefs and reduces the need to include
-headers from other headers.
-
-2.4. Reserved namespaces in C and POSIX
-Underscore capital, double underscore, and underscore 't' suffixes should be
-avoided.
-
-3. Low level memory management
-
-Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
-APIs is not allowed in the QEMU codebase. Instead of these routines,
-use the GLib memory allocation routines g_malloc/g_malloc0/g_new/
-g_new0/g_realloc/g_free or QEMU's qemu_memalign/qemu_blockalign/qemu_vfree
-APIs.
-
-Please note that g_malloc will exit on allocation failure, so there
-is no need to test for failure (as you would have to with malloc).
-Calling g_malloc with a zero size is valid and will return NULL.
-
-Prefer g_new(T, n) instead of g_malloc(sizeof(T) * n) for the following
-reasons:
-
- a. It catches multiplication overflowing size_t;
- b. It returns T * instead of void *, letting compiler catch more type
- errors.
-
-Declarations like T *v = g_malloc(sizeof(*v)) are acceptable, though.
-
-Memory allocated by qemu_memalign or qemu_blockalign must be freed with
-qemu_vfree, since breaking this will cause problems on Win32.
-
-4. String manipulation
-
-Do not use the strncpy function. As mentioned in the man page, it does *not*
-guarantee a NULL-terminated buffer, which makes it extremely dangerous to use.
-It also zeros trailing destination bytes out to the specified length. Instead,
-use this similar function when possible, but note its different signature:
-void pstrcpy(char *dest, int dest_buf_size, const char *src)
-
-Don't use strcat because it can't check for buffer overflows, but:
-char *pstrcat(char *buf, int buf_size, const char *s)
-
-The same limitation exists with sprintf and vsprintf, so use snprintf and
-vsnprintf.
-
-QEMU provides other useful string functions:
-int strstart(const char *str, const char *val, const char **ptr)
-int stristart(const char *str, const char *val, const char **ptr)
-int qemu_strnlen(const char *s, int max_len)
-
-There are also replacement character processing macros for isxyz and toxyz,
-so instead of e.g. isalnum you should use qemu_isalnum.
-
-Because of the memory management rules, you must use g_strdup/g_strndup
-instead of plain strdup/strndup.
-
-5. Printf-style functions
-
-Whenever you add a new printf-style function, i.e., one with a format
-string argument and following "..." in its prototype, be sure to use
-gcc's printf attribute directive in the prototype.
-
-This makes it so gcc's -Wformat and -Wformat-security options can do
-their jobs and cross-check format strings with the number and types
-of arguments.
-
-6. C standard, implementation defined and undefined behaviors
-
-C code in QEMU should be written to the C99 language specification. A copy
-of the final version of the C99 standard with corrigenda TC1, TC2, and TC3
-included, formatted as a draft, can be downloaded from:
- http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
-
-The C language specification defines regions of undefined behavior and
-implementation defined behavior (to give compiler authors enough leeway to
-produce better code). In general, code in QEMU should follow the language
-specification and avoid both undefined and implementation defined
-constructs. ("It works fine on the gcc I tested it with" is not a valid
-argument...) However there are a few areas where we allow ourselves to
-assume certain behaviors because in practice all the platforms we care about
-behave in the same way and writing strictly conformant code would be
-painful. These are:
- * you may assume that integers are 2s complement representation
- * you may assume that right shift of a signed integer duplicates
- the sign bit (ie it is an arithmetic shift, not a logical shift)
-
-In addition, QEMU assumes that the compiler does not use the latitude
-given in C99 and C11 to treat aspects of signed '<<' as undefined, as
-documented in the GNU Compiler Collection manual starting at version 4.0.
-
-7. Error handling and reporting
-
-7.1 Reporting errors to the human user
-
-Do not use printf(), fprintf() or monitor_printf(). Instead, use
-error_report() or error_vreport() from error-report.h. This ensures the
-error is reported in the right place (current monitor or stderr), and in
-a uniform format.
-
-Use error_printf() & friends to print additional information.
-
-error_report() prints the current location. In certain common cases
-like command line parsing, the current location is tracked
-automatically. To manipulate it manually, use the loc_*() from
-error-report.h.
-
-7.2 Propagating errors
-
-An error can't always be reported to the user right where it's detected,
-but often needs to be propagated up the call chain to a place that can
-handle it. This can be done in various ways.
-
-The most flexible one is Error objects. See error.h for usage
-information.
-
-Use the simplest suitable method to communicate success / failure to
-callers. Stick to common methods: non-negative on success / -1 on
-error, non-negative / -errno, non-null / null, or Error objects.
-
-Example: when a function returns a non-null pointer on success, and it
-can fail only in one way (as far as the caller is concerned), returning
-null on failure is just fine, and certainly simpler and a lot easier on
-the eyes than propagating an Error object through an Error ** parameter.
-
-Example: when a function's callers need to report details on failure
-only the function really knows, use Error **, and set suitable errors.
-
-Do not report an error to the user when you're also returning an error
-for somebody else to handle. Leave the reporting to the place that
-consumes the error returned.
-
-7.3 Handling errors
-
-Calling exit() is fine when handling configuration errors during
-startup. It's problematic during normal operation. In particular,
-monitor commands should never exit().
-
-Do not call exit() or abort() to handle an error that can be triggered
-by the guest (e.g., some unimplemented corner case in guest code
-translation or device emulation). Guests should not be able to
-terminate QEMU.
-
-Note that &error_fatal is just another way to exit(1), and &error_abort
-is just another way to abort().
diff --git a/MAINTAINERS b/MAINTAINERS
index ef6c01084b..50eaf005f4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -910,6 +910,13 @@ F: hw/char/mcf_uart.c
F: hw/net/mcf_fec.c
F: include/hw/m68k/mcf*.h
+NeXTcube
+M: Thomas Huth <huth@tuxfamily.org>
+S: Odd Fixes
+F: hw/m68k/next-*.c
+F: hw/display/next-fb.c
+F: include/hw/m68k/next-cube.h
+
MicroBlaze Machines
-------------------
petalogix_s3adsp1800
@@ -1890,6 +1897,7 @@ M: Paolo Bonzini <pbonzini@redhat.com>
S: Supported
F: include/exec/ioport.h
F: ioport.c
+F: include/exec/memop.h
F: include/exec/memory.h
F: include/exec/ram_addr.h
F: memory.c
@@ -2078,7 +2086,7 @@ R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
F: qtest.c
F: accel/qtest.c
-F: tests/libqtest.*
+F: tests/libqtest*
F: tests/libqos/
F: tests/*-test.c
diff --git a/Makefile b/Makefile
index ae17a83067..b3528617e4 100644
--- a/Makefile
+++ b/Makefile
@@ -717,6 +717,7 @@ endef
distclean: clean
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi qemu-monitor-info.texi
+ rm -f tests/tcg/config-*.mak
rm -f config-all-devices.mak config-all-disas.mak config.status
rm -f $(SUBDIR_DEVICES_MAK)
rm -f po/*.mo tests/qemu-iotests/common.env
diff --git a/Makefile.target b/Makefile.target
index 933b27453a..5e916230c4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -39,9 +39,6 @@ endif
PROGS=$(QEMU_PROG) $(QEMU_PROGW)
STPFILES=
-# Makefile Tests
-include $(SRC_PATH)/tests/tcg/Makefile.include
-
config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
diff --git a/README b/README.rst
index 441c33eb2f..7497709291 100644
--- a/README
+++ b/README.rst
@@ -1,5 +1,6 @@
- QEMU README
- ===========
+===========
+QEMU README
+===========
QEMU is a generic and open source machine & userspace emulator and
virtualizer.
@@ -37,6 +38,9 @@ QEMU is multi-platform software intended to be buildable on all modern
Linux platforms, OS-X, Win32 (via the Mingw64 toolchain) and a variety
of other UNIX targets. The simple steps to build QEMU are:
+
+.. code-block:: shell
+
mkdir build
cd build
../configure
@@ -44,9 +48,9 @@ of other UNIX targets. The simple steps to build QEMU are:
Additional information can also be found online via the QEMU website:
- https://qemu.org/Hosts/Linux
- https://qemu.org/Hosts/Mac
- https://qemu.org/Hosts/W32
+* `<https://qemu.org/Hosts/Linux>`_
+* `<https://qemu.org/Hosts/Mac>`_
+* `<https://qemu.org/Hosts/W32>`_
Submitting patches
@@ -54,24 +58,29 @@ Submitting patches
The QEMU source code is maintained under the GIT version control system.
+.. code-block:: shell
+
git clone https://git.qemu.org/git/qemu.git
When submitting patches, one common approach is to use 'git
format-patch' and/or 'git send-email' to format & send the mail to the
qemu-devel@nongnu.org mailing list. All patches submitted must contain
a 'Signed-off-by' line from the author. Patches should follow the
-guidelines set out in the HACKING and CODING_STYLE files.
+guidelines set out in the CODING_STYLE.rst file.
Additional information on submitting patches can be found online via
the QEMU website
- https://qemu.org/Contribute/SubmitAPatch
- https://qemu.org/Contribute/TrivialPatches
+* `<https://qemu.org/Contribute/SubmitAPatch>`_
+* `<https://qemu.org/Contribute/TrivialPatches>`_
The QEMU website is also maintained under source control.
+.. code-block:: shell
+
git clone https://git.qemu.org/git/qemu-web.git
- https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/
+
+* `<https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/>`_
A 'git-publish' utility was created to make above process less
cumbersome, and is highly recommended for making regular contributions,
@@ -82,10 +91,12 @@ manually for once.
For installation instructions, please go to
- https://github.com/stefanha/git-publish
+* `<https://github.com/stefanha/git-publish>`_
The workflow with 'git-publish' is:
+.. code-block:: shell
+
$ git checkout master -b my-feature
$ # work on new commits, add your 'Signed-off-by' lines to each
$ git publish
@@ -95,6 +106,8 @@ back to it in the future.
Sending v2:
+.. code-block:: shell
+
$ git checkout my-feature # same topic branch
$ # making changes to the commits (using 'git rebase', for example)
$ git publish
@@ -109,7 +122,7 @@ The QEMU project uses Launchpad as its primary upstream bug tracker. Bugs
found when running code built from QEMU git or upstream released sources
should be reported via:
- https://bugs.launchpad.net/qemu/
+* `<https://bugs.launchpad.net/qemu/>`_
If using QEMU via an operating system vendor pre-built binary package, it
is preferable to report bugs to the vendor's own bug tracker first. If
@@ -118,7 +131,7 @@ reported via launchpad.
For additional information on bug reporting consult:
- https://qemu.org/Contribute/ReportABug
+* `<https://qemu.org/Contribute/ReportABug>`_
Contact
@@ -127,13 +140,11 @@ Contact
The QEMU community can be contacted in a number of ways, with the two
main methods being email and IRC
- - qemu-devel@nongnu.org
- https://lists.nongnu.org/mailman/listinfo/qemu-devel
- - #qemu on irc.oftc.net
+* `<mailto:qemu-devel@nongnu.org>`_
+* `<https://lists.nongnu.org/mailman/listinfo/qemu-devel>`_
+* #qemu on irc.oftc.net
Information on additional methods of contacting the community can be
found online via the QEMU website:
- https://qemu.org/Contribute/StartHere
-
--- End
+* `<https://qemu.org/Contribute/StartHere>`_
diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h
index 5aaf186253..df9c838817 100644
--- a/accel/tcg/atomic_template.h
+++ b/accel/tcg/atomic_template.h
@@ -284,7 +284,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
#define GEN_ATOMIC_HELPER(X) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
- ABI_TYPE val EXTRA_ARGS) \
+ ABI_TYPE val EXTRA_ARGS) \
{ \
ATOMIC_MMU_DECLS; \
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index bb9897b25a..abae79650c 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -710,6 +710,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
hwaddr iotlb, xlat, sz, paddr_page;
target_ulong vaddr_page;
int asidx = cpu_asidx_from_attrs(cpu, attrs);
+ int wp_flags;
assert_cpu_is_self(cpu);
@@ -732,11 +733,12 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
address = vaddr_page;
if (size < TARGET_PAGE_SIZE) {
- /*
- * Slow-path the TLB entries; we will repeat the MMU check and TLB
- * fill on every access.
- */
- address |= TLB_RECHECK;
+ /* Repeat the MMU check and TLB fill on every access. */
+ address |= TLB_INVALID_MASK;
+ }
+ if (attrs.byte_swap) {
+ /* Force the access through the I/O slow path. */
+ address |= TLB_MMIO;
}
if (!memory_region_is_ram(section->mr) &&
!memory_region_is_romd(section->mr)) {
@@ -751,6 +753,8 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
code_address = address;
iotlb = memory_region_section_get_iotlb(cpu, section, vaddr_page,
paddr_page, xlat, prot, &address);
+ wp_flags = cpu_watchpoint_address_matches(cpu, vaddr_page,
+ TARGET_PAGE_SIZE);
index = tlb_index(env, mmu_idx, vaddr_page);
te = tlb_entry(env, mmu_idx, vaddr_page);
@@ -804,6 +808,9 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
tn.addend = addend - vaddr_page;
if (prot & PAGE_READ) {
tn.addr_read = address;
+ if (wp_flags & BP_MEM_READ) {
+ tn.addr_read |= TLB_WATCHPOINT;
+ }
} else {
tn.addr_read = -1;
}
@@ -830,6 +837,9 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
if (prot & PAGE_WRITE_INV) {
tn.addr_write |= TLB_INVALID_MASK;
}
+ if (wp_flags & BP_MEM_WRITE) {
+ tn.addr_write |= TLB_WATCHPOINT;
+ }
}
copy_tlb_helper_locked(te, &tn);
@@ -881,7 +891,7 @@ static void tlb_fill(CPUState *cpu, target_ulong addr, int size,
static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
int mmu_idx, target_ulong addr, uintptr_t retaddr,
- MMUAccessType access_type, int size)
+ MMUAccessType access_type, MemOp op)
{
CPUState *cpu = env_cpu(env);
hwaddr mr_offset;
@@ -891,6 +901,10 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
bool locked = false;
MemTxResult r;
+ if (iotlbentry->attrs.byte_swap) {
+ op ^= MO_BSWAP;
+ }
+
section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs);
mr = section->mr;
mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr;
@@ -906,14 +920,13 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
qemu_mutex_lock_iothread();
locked = true;
}
- r = memory_region_dispatch_read(mr, mr_offset,
- &val, size, iotlbentry->attrs);
+ r = memory_region_dispatch_read(mr, mr_offset, &val, op, iotlbentry->attrs);
if (r != MEMTX_OK) {
hwaddr physaddr = mr_offset +
section->offset_within_address_space -
section->offset_within_region;
- cpu_transaction_failed(cpu, physaddr, addr, size, access_type,
+ cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), access_type,
mmu_idx, iotlbentry->attrs, r, retaddr);
}
if (locked) {
@@ -925,7 +938,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
int mmu_idx, uint64_t val, target_ulong addr,
- uintptr_t retaddr, int size)
+ uintptr_t retaddr, MemOp op)
{
CPUState *cpu = env_cpu(env);
hwaddr mr_offset;
@@ -934,6 +947,10 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
bool locked = false;
MemTxResult r;
+ if (iotlbentry->attrs.byte_swap) {
+ op ^= MO_BSWAP;
+ }
+
section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs);
mr = section->mr;
mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr;
@@ -947,15 +964,15 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
qemu_mutex_lock_iothread();
locked = true;
}
- r = memory_region_dispatch_write(mr, mr_offset,
- val, size, iotlbentry->attrs);
+ r = memory_region_dispatch_write(mr, mr_offset, val, op, iotlbentry->attrs);
if (r != MEMTX_OK) {
hwaddr physaddr = mr_offset +
section->offset_within_address_space -
section->offset_within_region;
- cpu_transaction_failed(cpu, physaddr, addr, size, MMU_DATA_STORE,
- mmu_idx, iotlbentry->attrs, r, retaddr);
+ cpu_transaction_failed(cpu, physaddr, addr, memop_size(op),
+ MMU_DATA_STORE, mmu_idx, iotlbentry->attrs, r,
+ retaddr);
}
if (locked) {
qemu_mutex_unlock_iothread();
@@ -1015,10 +1032,15 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \
(ADDR) & TARGET_PAGE_MASK)
-/* NOTE: this function can trigger an exception */
-/* NOTE2: the returned address is not exactly the physical address: it
- * is actually a ram_addr_t (in system mode; the user mode emulation
- * version of this function returns a guest virtual address).
+/*
+ * Return a ram_addr_t for the virtual address for execution.
+ *
+ * Return -1 if we can't translate and execute from an entire page
+ * of RAM. This will force us to execute by loading and translating
+ * one insn at a time, without caching.
+ *
+ * NOTE: This function will trigger an exception if the page is
+ * not executable.
*/
tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
{
@@ -1032,19 +1054,20 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
tlb_fill(env_cpu(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0);
index = tlb_index(env, mmu_idx, addr);
entry = tlb_entry(env, mmu_idx, addr);
+
+ if (unlikely(entry->addr_code & TLB_INVALID_MASK)) {
+ /*
+ * The MMU protection covers a smaller range than a target
+ * page, so we must redo the MMU check for every insn.
+ */
+ return -1;
+ }
}
assert(tlb_hit(entry->addr_code, addr));
}
- if (unlikely(entry->addr_code & (TLB_RECHECK | TLB_MMIO))) {
- /*
- * Return -1 if we can't translate and execute from an entire
- * page of RAM here, which will cause us to execute by loading
- * and translating one insn at a time, without caching:
- * - TLB_RECHECK: means the MMU protection covers a smaller range
- * than a target page, so we must redo the MMU check every insn
- * - TLB_MMIO: region is not backed by RAM
- */
+ if (unlikely(entry->addr_code & TLB_MMIO)) {
+ /* The region is not backed by RAM. */
return -1;
}
@@ -1052,25 +1075,70 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
return qemu_ram_addr_from_host_nofail(p);
}
-/* Probe for whether the specified guest write access is permitted.
- * If it is not permitted then an exception will be taken in the same
- * way as if this were a real write access (and we will not return).
- * Otherwise the function will return, and there will be a valid
- * entry in the TLB for this access.
+/*
+ * Probe for whether the specified guest access is permitted. If it is not
+ * permitted then an exception will be taken in the same way as if this
+ * were a real access (and we will not return).
+ * If the size is 0 or the page requires I/O access, returns NULL; otherwise,
+ * returns the address of the host page similar to tlb_vaddr_to_host().
*/
-void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
- uintptr_t retaddr)
+void *probe_access(CPUArchState *env, target_ulong addr, int size,
+ MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
{
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
+ target_ulong tlb_addr;
+ size_t elt_ofs;
+ int wp_access;
- if (!tlb_hit(tlb_addr_write(entry), addr)) {
- /* TLB entry is for a different page */
- if (!VICTIM_TLB_HIT(addr_write, addr)) {
- tlb_fill(env_cpu(env), addr, size, MMU_DATA_STORE,
- mmu_idx, retaddr);
+ g_assert(-(addr | TARGET_PAGE_MASK) >= size);
+
+ switch (access_type) {
+ case MMU_DATA_LOAD:
+ elt_ofs = offsetof(CPUTLBEntry, addr_read);
+ wp_access = BP_MEM_READ;
+ break;
+ case MMU_DATA_STORE:
+ elt_ofs = offsetof(CPUTLBEntry, addr_write);
+ wp_access = BP_MEM_WRITE;
+ break;
+ case MMU_INST_FETCH:
+ elt_ofs = offsetof(CPUTLBEntry, addr_code);
+ wp_access = BP_MEM_READ;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ tlb_addr = tlb_read_ofs(entry, elt_ofs);
+
+ if (unlikely(!tlb_hit(tlb_addr, addr))) {
+ if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs,
+ addr & TARGET_PAGE_MASK)) {
+ tlb_fill(env_cpu(env), addr, size, access_type, mmu_idx, retaddr);
+ /* TLB resize via tlb_fill may have moved the entry. */
+ index = tlb_index(env, mmu_idx, addr);
+ entry = tlb_entry(env, mmu_idx, addr);
}
+ tlb_addr = tlb_read_ofs(entry, elt_ofs);
+ }
+
+ if (!size) {
+ return NULL;
}
+
+ /* Handle watchpoints. */
+ if (tlb_addr & TLB_WATCHPOINT) {
+ cpu_check_watchpoint(env_cpu(env), addr, size,
+ env_tlb(env)->d[mmu_idx].iotlb[index].attrs,
+ wp_access, retaddr);
+ }
+
+ if (tlb_addr & (TLB_NOTDIRTY | TLB_MMIO)) {
+ /* I/O access */
+ return NULL;
+ }
+
+ return (void *)((uintptr_t)addr + entry->addend);
}
void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
@@ -1133,7 +1201,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr);
target_ulong tlb_addr = tlb_addr_write(tlbe);
- TCGMemOp mop = get_memop(oi);
+ MemOp mop = get_memop(oi);
int a_bits = get_alignment_bits(mop);
int s_bits = mop & MO_SIZE;
void *hostaddr;
@@ -1169,7 +1237,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
}
/* Notice an IO access or a needs-MMU-lookup access */
- if (unlikely(tlb_addr & (TLB_MMIO | TLB_RECHECK))) {
+ if (unlikely(tlb_addr & TLB_MMIO)) {
/* There's really nothing that can be done to
support this apart from stop-the-world. */
goto stop_the_world;
@@ -1201,37 +1269,6 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
cpu_loop_exit_atomic(env_cpu(env), retaddr);
}
-#ifdef TARGET_WORDS_BIGENDIAN
-#define NEED_BE_BSWAP 0
-#define NEED_LE_BSWAP 1
-#else
-#define NEED_BE_BSWAP 1
-#define NEED_LE_BSWAP 0
-#endif
-
-/*
- * Byte Swap Helper
- *
- * This should all dead code away depending on the build host and
- * access type.
- */
-
-static inline uint64_t handle_bswap(uint64_t val, int size, bool big_endian)
-{
- if ((big_endian && NEED_BE_BSWAP) || (!big_endian && NEED_LE_BSWAP)) {
- switch (size) {
- case 1: return val;
- case 2: return bswap16(val);
- case 4: return bswap32(val);
- case 8: return bswap64(val);
- default:
- g_assert_not_reached();
- }
- } else {
- return val;
- }
-}
-
/*
* Load Helpers
*
@@ -1246,7 +1283,7 @@ typedef uint64_t FullLoadHelper(CPUArchState *env, target_ulong addr,
static inline uint64_t __attribute__((always_inline))
load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
- uintptr_t retaddr, size_t size, bool big_endian, bool code_read,
+ uintptr_t retaddr, MemOp op, bool code_read,
FullLoadHelper *full_load)
{
uintptr_t mmu_idx = get_mmuidx(oi);
@@ -1260,6 +1297,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
unsigned a_bits = get_alignment_bits(get_memop(oi));
void *haddr;
uint64_t res;
+ size_t size = memop_size(op);
/* Handle CPU specific unaligned behaviour */
if (addr & ((1 << a_bits) - 1)) {
@@ -1277,37 +1315,36 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
entry = tlb_entry(env, mmu_idx, addr);
}
tlb_addr = code_read ? entry->addr_code : entry->addr_read;
+ tlb_addr &= ~TLB_INVALID_MASK;
}
- /* Handle an IO access. */
+ /* Handle anything that isn't just a straight memory access. */
if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) {
+ CPUIOTLBEntry *iotlbentry;
+
+ /* For anything that is unaligned, recurse through full_load. */
if ((addr & (size - 1)) != 0) {
goto do_unaligned_access;
}
- if (tlb_addr & TLB_RECHECK) {
- /*
- * This is a TLB_RECHECK access, where the MMU protection
- * covers a smaller range than a target page, and we must
- * repeat the MMU check here. This tlb_fill() call might
- * longjump out if this access should cause a guest exception.
- */
- tlb_fill(env_cpu(env), addr, size,
- access_type, mmu_idx, retaddr);
- index = tlb_index(env, mmu_idx, addr);
- entry = tlb_entry(env, mmu_idx, addr);
+ iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index];
+
+ /* Handle watchpoints. */
+ if (unlikely(tlb_addr & TLB_WATCHPOINT)) {
+ /* On watchpoint hit, this will longjmp out. */
+ cpu_check_watchpoint(env_cpu(env), addr, size,
+ iotlbentry->attrs, BP_MEM_READ, retaddr);
- tlb_addr = code_read ? entry->addr_code : entry->addr_read;
- tlb_addr &= ~TLB_RECHECK;
- if (!(tlb_addr & ~TARGET_PAGE_MASK)) {
- /* RAM access */
+ /* The backing page may or may not require I/O. */
+ tlb_addr &= ~TLB_WATCHPOINT;
+ if ((tlb_addr & ~TARGET_PAGE_MASK) == 0) {
goto do_aligned_access;
}
}
- res = io_readx(env, &env_tlb(env)->d[mmu_idx].iotlb[index],
- mmu_idx, addr, retaddr, access_type, size);
- return handle_bswap(res, size, big_endian);
+ /* Handle I/O access. */
+ return io_readx(env, iotlbentry, mmu_idx, addr,
+ retaddr, access_type, op);
}
/* Handle slow unaligned access (it spans two pages or IO). */
@@ -1324,7 +1361,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
r2 = full_load(env, addr2, oi, retaddr);
shift = (addr & (size - 1)) * 8;
- if (big_endian) {
+ if (memop_big_endian(op)) {
/* Big-endian combine. */
res = (r1 << shift) | (r2 >> ((size * 8) - shift));
} else {
@@ -1336,30 +1373,27 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
do_aligned_access:
haddr = (void *)((uintptr_t)addr + entry->addend);
- switch (size) {
- case 1:
+ switch (op) {
+ case MO_UB:
res = ldub_p(haddr);
break;
- case 2:
- if (big_endian) {
- res = lduw_be_p(haddr);
- } else {
- res = lduw_le_p(haddr);
- }
+ case MO_BEUW:
+ res = lduw_be_p(haddr);
break;
- case 4:
- if (big_endian) {
- res = (uint32_t)ldl_be_p(haddr);
- } else {
- res = (uint32_t)ldl_le_p(haddr);
- }
+ case MO_LEUW:
+ res = lduw_le_p(haddr);
break;
- case 8:
- if (big_endian) {
- res = ldq_be_p(haddr);
- } else {
- res = ldq_le_p(haddr);
- }
+ case MO_BEUL:
+ res = (uint32_t)ldl_be_p(haddr);
+ break;
+ case MO_LEUL:
+ res = (uint32_t)ldl_le_p(haddr);
+ break;
+ case MO_BEQ:
+ res = ldq_be_p(haddr);
+ break;
+ case MO_LEQ:
+ res = ldq_le_p(haddr);
break;
default:
g_assert_not_reached();
@@ -1381,8 +1415,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
static uint64_t full_ldub_mmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 1, false, false,
- full_ldub_mmu);
+ return load_helper(env, addr, oi, retaddr, MO_UB, false, full_ldub_mmu);
}
tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr,
@@ -1394,7 +1427,7 @@ tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr,
static uint64_t full_le_lduw_mmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 2, false, false,
+ return load_helper(env, addr, oi, retaddr, MO_LEUW, false,
full_le_lduw_mmu);
}
@@ -1407,7 +1440,7 @@ tcg_target_ulong helper_le_lduw_mmu(CPUArchState *env, target_ulong addr,
static uint64_t full_be_lduw_mmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 2, true, false,
+ return load_helper(env, addr, oi, retaddr, MO_BEUW, false,
full_be_lduw_mmu);
}
@@ -1420,7 +1453,7 @@ tcg_target_ulong helper_be_lduw_mmu(CPUArchState *env, target_ulong addr,
static uint64_t full_le_ldul_mmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 4, false, false,
+ return load_helper(env, addr, oi, retaddr, MO_LEUL, false,
full_le_ldul_mmu);
}
@@ -1433,7 +1466,7 @@ tcg_target_ulong helper_le_ldul_mmu(CPUArchState *env, target_ulong addr,
static uint64_t full_be_ldul_mmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 4, true, false,
+ return load_helper(env, addr, oi, retaddr, MO_BEUL, false,
full_be_ldul_mmu);
}
@@ -1446,14 +1479,14 @@ tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr,
uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 8, false, false,
+ return load_helper(env, addr, oi, retaddr, MO_LEQ, false,
helper_le_ldq_mmu);
}
uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 8, true, false,
+ return load_helper(env, addr, oi, retaddr, MO_BEQ, false,
helper_be_ldq_mmu);
}
@@ -1499,7 +1532,7 @@ tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr,
static inline void __attribute__((always_inline))
store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
- TCGMemOpIdx oi, uintptr_t retaddr, size_t size, bool big_endian)
+ TCGMemOpIdx oi, uintptr_t retaddr, MemOp op)
{
uintptr_t mmu_idx = get_mmuidx(oi);
uintptr_t index = tlb_index(env, mmu_idx, addr);
@@ -1508,6 +1541,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
const size_t tlb_off = offsetof(CPUTLBEntry, addr_write);
unsigned a_bits = get_alignment_bits(get_memop(oi));
void *haddr;
+ size_t size = memop_size(op);
/* Handle CPU specific unaligned behaviour */
if (addr & ((1 << a_bits) - 1)) {
@@ -1527,35 +1561,32 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
tlb_addr = tlb_addr_write(entry) & ~TLB_INVALID_MASK;
}
- /* Handle an IO access. */
+ /* Handle anything that isn't just a straight memory access. */
if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) {
+ CPUIOTLBEntry *iotlbentry;
+
+ /* For anything that is unaligned, recurse through byte stores. */
if ((addr & (size - 1)) != 0) {
goto do_unaligned_access;
}
- if (tlb_addr & TLB_RECHECK) {
- /*
- * This is a TLB_RECHECK access, where the MMU protection
- * covers a smaller range than a target page, and we must
- * repeat the MMU check here. This tlb_fill() call might
- * longjump out if this access should cause a guest exception.
- */
- tlb_fill(env_cpu(env), addr, size, MMU_DATA_STORE,
- mmu_idx, retaddr);
- index = tlb_index(env, mmu_idx, addr);
- entry = tlb_entry(env, mmu_idx, addr);
+ iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index];
+
+ /* Handle watchpoints. */
+ if (unlikely(tlb_addr & TLB_WATCHPOINT)) {
+ /* On watchpoint hit, this will longjmp out. */
+ cpu_check_watchpoint(env_cpu(env), addr, size,
+ iotlbentry->attrs, BP_MEM_WRITE, retaddr);
- tlb_addr = tlb_addr_write(entry);
- tlb_addr &= ~TLB_RECHECK;
- if (!(tlb_addr & ~TARGET_PAGE_MASK)) {
- /* RAM access */
+ /* The backing page may or may not require I/O. */
+ tlb_addr &= ~TLB_WATCHPOINT;
+ if ((tlb_addr & ~TARGET_PAGE_MASK) == 0) {
goto do_aligned_access;
}
}
- io_writex(env, &env_tlb(env)->d[mmu_idx].iotlb[index], mmu_idx,
- handle_bswap(val, size, big_endian),
- addr, retaddr, size);
+ /* Handle I/O access. */
+ io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, op);
return;
}
@@ -1567,6 +1598,8 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
uintptr_t index2;
CPUTLBEntry *entry2;
target_ulong page2, tlb_addr2;
+ size_t size2;
+
do_unaligned_access:
/*
* Ensure the second page is in the TLB. Note that the first page
@@ -1574,14 +1607,33 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
* cannot evict the first.
*/
page2 = (addr + size) & TARGET_PAGE_MASK;
+ size2 = (addr + size) & ~TARGET_PAGE_MASK;
index2 = tlb_index(env, mmu_idx, page2);
entry2 = tlb_entry(env, mmu_idx, page2);
tlb_addr2 = tlb_addr_write(entry2);
- if (!tlb_hit_page(tlb_addr2, page2)
- && !victim_tlb_hit(env, mmu_idx, index2, tlb_off,
- page2 & TARGET_PAGE_MASK)) {
- tlb_fill(env_cpu(env), page2, size, MMU_DATA_STORE,
- mmu_idx, retaddr);
+ if (!tlb_hit_page(tlb_addr2, page2)) {
+ if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) {
+ tlb_fill(env_cpu(env), page2, size2, MMU_DATA_STORE,
+ mmu_idx, retaddr);
+ index2 = tlb_index(env, mmu_idx, page2);
+ entry2 = tlb_entry(env, mmu_idx, page2);
+ }
+ tlb_addr2 = tlb_addr_write(entry2);
+ }
+
+ /*
+ * Handle watchpoints. Since this may trap, all checks
+ * must happen before any store.
+ */
+ if (unlikely(tlb_addr & TLB_WATCHPOINT)) {
+ cpu_check_watchpoint(env_cpu(env), addr, size - size2,
+ env_tlb(env)->d[mmu_idx].iotlb[index].attrs,
+ BP_MEM_WRITE, retaddr);
+ }
+ if (unlikely(tlb_addr2 & TLB_WATCHPOINT)) {
+ cpu_check_watchpoint(env_cpu(env), page2, size2,
+ env_tlb(env)->d[mmu_idx].iotlb[index2].attrs,
+ BP_MEM_WRITE, retaddr);
}
/*
@@ -1591,7 +1643,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
*/
for (i = 0; i < size; ++i) {
uint8_t val8;
- if (big_endian) {
+ if (memop_big_endian(op)) {
/* Big-endian extract. */
val8 = val >> (((size - 1) * 8) - (i * 8));
} else {
@@ -1605,30 +1657,27 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
do_aligned_access:
haddr = (void *)((uintptr_t)addr + entry->addend);
- switch (size) {
- case 1:
+ switch (op) {
+ case MO_UB:
stb_p(haddr, val);
break;
- case 2:
- if (big_endian) {
- stw_be_p(haddr, val);
- } else {
- stw_le_p(haddr, val);
- }
+ case MO_BEUW:
+ stw_be_p(haddr, val);
break;
- case 4:
- if (big_endian) {
- stl_be_p(haddr, val);
- } else {
- stl_le_p(haddr, val);
- }
+ case MO_LEUW:
+ stw_le_p(haddr, val);
break;
- case 8:
- if (big_endian) {
- stq_be_p(haddr, val);
- } else {
- stq_le_p(haddr, val);
- }
+ case MO_BEUL:
+ stl_be_p(haddr, val);
+ break;
+ case MO_LEUL:
+ stl_le_p(haddr, val);
+ break;
+ case MO_BEQ:
+ stq_be_p(haddr, val);
+ break;
+ case MO_LEQ:
+ stq_le_p(haddr, val);
break;
default:
g_assert_not_reached();
@@ -1639,43 +1688,43 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- store_helper(env, addr, val, oi, retaddr, 1, false);
+ store_helper(env, addr, val, oi, retaddr, MO_UB);
}
void helper_le_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- store_helper(env, addr, val, oi, retaddr, 2, false);
+ store_helper(env, addr, val, oi, retaddr, MO_LEUW);
}
void helper_be_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- store_helper(env, addr, val, oi, retaddr, 2, true);
+ store_helper(env, addr, val, oi, retaddr, MO_BEUW);
}
void helper_le_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- store_helper(env, addr, val, oi, retaddr, 4, false);
+ store_helper(env, addr, val, oi, retaddr, MO_LEUL);
}
void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- store_helper(env, addr, val, oi, retaddr, 4, true);
+ store_helper(env, addr, val, oi, retaddr, MO_BEUL);
}
void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- store_helper(env, addr, val, oi, retaddr, 8, false);
+ store_helper(env, addr, val, oi, retaddr, MO_LEQ);
}
void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- store_helper(env, addr, val, oi, retaddr, 8, true);
+ store_helper(env, addr, val, oi, retaddr, MO_BEQ);
}
/* First set of helpers allows passing in of OI and RETADDR. This makes
@@ -1740,8 +1789,7 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
static uint64_t full_ldub_cmmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 1, false, true,
- full_ldub_cmmu);
+ return load_helper(env, addr, oi, retaddr, MO_8, true, full_ldub_cmmu);
}
uint8_t helper_ret_ldb_cmmu(CPUArchState *env, target_ulong addr,
@@ -1753,7 +1801,7 @@ uint8_t helper_ret_ldb_cmmu(CPUArchState *env, target_ulong addr,
static uint64_t full_le_lduw_cmmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 2, false, true,
+ return load_helper(env, addr, oi, retaddr, MO_LEUW, true,
full_le_lduw_cmmu);
}
@@ -1766,7 +1814,7 @@ uint16_t helper_le_ldw_cmmu(CPUArchState *env, target_ulong addr,
static uint64_t full_be_lduw_cmmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 2, true, true,
+ return load_helper(env, addr, oi, retaddr, MO_BEUW, true,
full_be_lduw_cmmu);
}
@@ -1779,7 +1827,7 @@ uint16_t helper_be_ldw_cmmu(CPUArchState *env, target_ulong addr,
static uint64_t full_le_ldul_cmmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 4, false, true,
+ return load_helper(env, addr, oi, retaddr, MO_LEUL, true,
full_le_ldul_cmmu);
}
@@ -1792,7 +1840,7 @@ uint32_t helper_le_ldl_cmmu(CPUArchState *env, target_ulong addr,
static uint64_t full_be_ldul_cmmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 4, true, true,
+ return load_helper(env, addr, oi, retaddr, MO_BEUL, true,
full_be_ldul_cmmu);
}
@@ -1805,13 +1853,13 @@ uint32_t helper_be_ldl_cmmu(CPUArchState *env, target_ulong addr,
uint64_t helper_le_ldq_cmmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 8, false, true,
+ return load_helper(env, addr, oi, retaddr, MO_LEQ, true,
helper_le_ldq_cmmu);
}
uint64_t helper_be_ldq_cmmu(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
- return load_helper(env, addr, oi, retaddr, 8, true, true,
+ return load_helper(env, addr, oi, retaddr, MO_BEQ, true,
helper_be_ldq_cmmu);
}
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 897d1571c4..71c4bf6477 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -188,6 +188,38 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
g_assert_not_reached();
}
+void *probe_access(CPUArchState *env, target_ulong addr, int size,
+ MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
+{
+ int flags;
+
+ g_assert(-(addr | TARGET_PAGE_MASK) >= size);
+
+ switch (access_type) {
+ case MMU_DATA_STORE:
+ flags = PAGE_WRITE;
+ break;
+ case MMU_DATA_LOAD:
+ flags = PAGE_READ;
+ break;
+ case MMU_INST_FETCH:
+ flags = PAGE_EXEC;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!guest_addr_valid(addr) || page_check_range(addr, size, flags) < 0) {
+ CPUState *cpu = env_cpu(env);
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ cc->tlb_fill(cpu, addr, size, access_type, MMU_USER_IDX, false,
+ retaddr);
+ g_assert_not_reached();
+ }
+
+ return size ? g2h(addr) : NULL;
+}
+
#if defined(__i386__)
#if defined(__NetBSD__)
diff --git a/audio/audio.c b/audio/audio.c
index 7d715332c9..e99fcd0694 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1412,8 +1412,9 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
drvname = AudiodevDriver_str(dev->driver);
} else if (!QTAILQ_EMPTY(&audio_states)) {
if (!legacy_config) {
- dolog("You must specify an audiodev= for the device %s\n", name);
- exit(1);
+ dolog("Device %s: audiodev default parameter is deprecated, please "
+ "specify audiodev=%s\n", name,
+ QTAILQ_FIRST(&audio_states)->dev->id);
}
return QTAILQ_FIRST(&audio_states);
} else {
@@ -1548,8 +1549,7 @@ CaptureVoiceOut *AUD_add_capture(
if (!s) {
if (!legacy_config) {
- dolog("You must specify audiodev when trying to capture\n");
- return NULL;
+ dolog("Capturing without setting an audiodev is deprecated\n");
}
s = audio_init(NULL, NULL);
}
@@ -1685,7 +1685,7 @@ void audio_create_pdos(Audiodev *dev)
} \
if (!dev->u.driver.has_out) { \
dev->u.driver.out = g_malloc0( \
- sizeof(AudiodevAlsaPerDirectionOptions)); \
+ sizeof(Audiodev##pdo_name##PerDirectionOptions)); \
dev->u.driver.has_out = true; \
} \
break
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 981e8e122f..f0691116e8 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-y += rng.o rng-egd.o
+common-obj-y += rng.o rng-egd.o rng-builtin.o
common-obj-$(CONFIG_POSIX) += rng-random.o
common-obj-$(CONFIG_TPM) += tpm.o
diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index 29e55c9195..ecc15e3eb0 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -67,12 +67,12 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
uint64_t size;
size = qemu_get_pmem_size(fb->mem_path, &local_err);
- if (!size) {
+ if (local_err) {
error_propagate(errp, local_err);
return;
}
- if (backend->size > size) {
+ if (size && backend->size > size) {
error_setg(errp, "size property %" PRIu64 " is larger than "
"pmem file \"%s\" size %" PRIu64, backend->size,
fb->mem_path, size);
diff --git a/backends/rng-builtin.c b/backends/rng-builtin.c
new file mode 100644
index 0000000000..ba1b8d66b8
--- /dev/null
+++ b/backends/rng-builtin.c
@@ -0,0 +1,77 @@
+/*
+ * QEMU Builtin Random Number Generator Backend
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/rng.h"
+#include "qemu/main-loop.h"
+#include "qemu/guest-random.h"
+
+#define RNG_BUILTIN(obj) OBJECT_CHECK(RngBuiltin, (obj), TYPE_RNG_BUILTIN)
+
+typedef struct RngBuiltin {
+ RngBackend parent;
+ QEMUBH *bh;
+} RngBuiltin;
+
+static void rng_builtin_receive_entropy_bh(void *opaque)
+{
+ RngBuiltin *s = opaque;
+
+ while (!QSIMPLEQ_EMPTY(&s->parent.requests)) {
+ RngRequest *req = QSIMPLEQ_FIRST(&s->parent.requests);
+
+ qemu_guest_getrandom_nofail(req->data, req->size);
+
+ req->receive_entropy(req->opaque, req->data, req->size);
+
+ rng_backend_finalize_request(&s->parent, req);
+ }
+}
+
+static void rng_builtin_request_entropy(RngBackend *b, RngRequest *req)
+{
+ RngBuiltin *s = RNG_BUILTIN(b);
+
+ qemu_bh_schedule(s->bh);
+}
+
+static void rng_builtin_init(Object *obj)
+{
+ RngBuiltin *s = RNG_BUILTIN(obj);
+
+ s->bh = qemu_bh_new(rng_builtin_receive_entropy_bh, s);
+}
+
+static void rng_builtin_finalize(Object *obj)
+{
+ RngBuiltin *s = RNG_BUILTIN(obj);
+
+ qemu_bh_delete(s->bh);
+}
+
+static void rng_builtin_class_init(ObjectClass *klass, void *data)
+{
+ RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
+
+ rbc->request_entropy = rng_builtin_request_entropy;
+}
+
+static const TypeInfo rng_builtin_info = {
+ .name = TYPE_RNG_BUILTIN,
+ .parent = TYPE_RNG_BACKEND,
+ .instance_size = sizeof(RngBuiltin),
+ .instance_init = rng_builtin_init,
+ .instance_finalize = rng_builtin_finalize,
+ .class_init = rng_builtin_class_init,
+};
+
+static void register_types(void)
+{
+ type_register_static(&rng_builtin_info);
+}
+
+type_init(register_types);
diff --git a/block.c b/block.c
index 874a29a983..5944124845 100644
--- a/block.c
+++ b/block.c
@@ -4165,7 +4165,6 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
{
BdrvChild *c, *next;
GSList *list = NULL, *p;
- uint64_t old_perm, old_shared;
uint64_t perm = 0, shared = BLK_PERM_ALL;
int ret;
@@ -4211,8 +4210,8 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
bdrv_unref(from);
}
- bdrv_get_cumulative_perm(to, &old_perm, &old_shared);
- bdrv_set_perm(to, old_perm | perm, old_shared | shared);
+ bdrv_get_cumulative_perm(to, &perm, &shared);
+ bdrv_set_perm(to, perm, shared);
out:
g_slist_free(list);
diff --git a/block/file-posix.c b/block/file-posix.c
index fbeb0068db..87c5a4ccbd 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -380,7 +380,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
for (i = 0; i < ARRAY_SIZE(alignments); i++) {
align = alignments[i];
if (raw_is_io_aligned(fd, buf + align, max_align)) {
- /* Fallback to request_aligment. */
+ /* Fallback to request_alignment. */
s->buf_align = (align != 1) ? align : bs->bl.request_alignment;
break;
}
@@ -1588,6 +1588,13 @@ static int handle_aiocb_write_zeroes(void *opaque)
if (s->has_write_zeroes) {
int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE,
aiocb->aio_offset, aiocb->aio_nbytes);
+ if (ret == -EINVAL) {
+ /*
+ * Allow falling back to pwrite for file systems that
+ * do not support fallocate() for an unaligned byte range.
+ */
+ return -ENOTSUP;
+ }
if (ret == 0 || ret != -ENOTSUP) {
return ret;
}
@@ -1749,6 +1756,43 @@ static int handle_aiocb_discard(void *opaque)
return ret;
}
+/*
+ * Help alignment probing by allocating the first block.
+ *
+ * When reading with direct I/O from unallocated area on Gluster backed by XFS,
+ * reading succeeds regardless of request length. In this case we fallback to
+ * safe alignment which is not optimal. Allocating the first block avoids this
+ * fallback.
+ *
+ * fd may be opened with O_DIRECT, but we don't know the buffer alignment or
+ * request alignment, so we use safe values.
+ *
+ * Returns: 0 on success, -errno on failure. Since this is an optimization,
+ * caller may ignore failures.
+ */
+static int allocate_first_block(int fd, size_t max_size)
+{
+ size_t write_size = (max_size < MAX_BLOCKSIZE)
+ ? BDRV_SECTOR_SIZE
+ : MAX_BLOCKSIZE;
+ size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize());
+ void *buf;
+ ssize_t n;
+ int ret;
+
+ buf = qemu_memalign(max_align, write_size);
+ memset(buf, 0, write_size);
+
+ do {
+ n = pwrite(fd, buf, write_size, 0);
+ } while (n == -1 && errno == EINTR);
+
+ ret = (n == -1) ? -errno : 0;
+
+ qemu_vfree(buf);
+ return ret;
+}
+
static int handle_aiocb_truncate(void *opaque)
{
RawPosixAIOData *aiocb = opaque;
@@ -1788,6 +1832,17 @@ static int handle_aiocb_truncate(void *opaque)
/* posix_fallocate() doesn't set errno. */
error_setg_errno(errp, -result,
"Could not preallocate new data");
+ } else if (current_length == 0) {
+ /*
+ * posix_fallocate() uses fallocate() if the filesystem
+ * supports it, or fallback to manually writing zeroes. If
+ * fallocate() was used, unaligned reads from the fallocated
+ * area in raw_probe_alignment() will succeed, hence we need to
+ * allocate the first block.
+ *
+ * Optimize future alignment probing; ignore failures.
+ */
+ allocate_first_block(fd, offset);
}
} else {
result = 0;
@@ -1849,6 +1904,9 @@ static int handle_aiocb_truncate(void *opaque)
if (ftruncate(fd, offset) != 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not resize file");
+ } else if (current_length == 0 && offset > current_length) {
+ /* Optimize future alignment probing; ignore failures. */
+ allocate_first_block(fd, offset);
}
return result;
default:
diff --git a/block/io.c b/block/io.c
index 0fa10831ed..16a598fd08 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1746,7 +1746,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
assert(!bs->supported_zero_flags);
}
- if (ret < 0 && !(flags & BDRV_REQ_NO_FALLBACK)) {
+ if (ret == -ENOTSUP && !(flags & BDRV_REQ_NO_FALLBACK)) {
/* Fall back to bounce buffer if write zeroes is unsupported */
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
diff --git a/block/nbd.c b/block/nbd.c
index beed46fb34..813c40d8f0 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -1044,6 +1044,10 @@ static int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
request.flags |= NBD_CMD_FLAG_NO_HOLE;
}
+ if (flags & BDRV_REQ_NO_FALLBACK) {
+ assert(s->info.flags & NBD_FLAG_SEND_FAST_ZERO);
+ request.flags |= NBD_CMD_FLAG_FAST_ZERO;
+ }
if (!bytes) {
return 0;
@@ -1239,6 +1243,9 @@ static int nbd_client_connect(BlockDriverState *bs, Error **errp)
}
if (s->info.flags & NBD_FLAG_SEND_WRITE_ZEROES) {
bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP;
+ if (s->info.flags & NBD_FLAG_SEND_FAST_ZERO) {
+ bs->supported_zero_flags |= BDRV_REQ_NO_FALLBACK;
+ }
}
s->sioc = sioc;
@@ -1374,7 +1381,7 @@ static bool nbd_has_filename_options_conflict(QDict *options, Error **errp)
static void nbd_parse_filename(const char *filename, QDict *options,
Error **errp)
{
- char *file;
+ g_autofree char *file = NULL;
char *export_name;
const char *host_spec;
const char *unixpath;
@@ -1396,7 +1403,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
export_name = strstr(file, EN_OPTSTR);
if (export_name) {
if (export_name[strlen(EN_OPTSTR)] == 0) {
- goto out;
+ return;
}
export_name[0] = 0; /* truncate 'file' */
export_name += strlen(EN_OPTSTR);
@@ -1407,11 +1414,11 @@ static void nbd_parse_filename(const char *filename, QDict *options,
/* extract the host_spec - fail if it's not nbd:... */
if (!strstart(file, "nbd:", &host_spec)) {
error_setg(errp, "File name string for NBD must start with 'nbd:'");
- goto out;
+ return;
}
if (!*host_spec) {
- goto out;
+ return;
}
/* are we a UNIX or TCP socket? */
@@ -1431,9 +1438,6 @@ static void nbd_parse_filename(const char *filename, QDict *options,
out_inet:
qapi_free_InetSocketAddress(addr);
}
-
-out:
- g_free(file);
}
static bool nbd_process_legacy_socket_options(QDict *output_options,
diff --git a/block/vmdk.c b/block/vmdk.c
index fd78fd0ccf..fed3b50c8a 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1076,8 +1076,7 @@ static const char *next_line(const char *s)
}
static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
- const char *desc_file_path, QDict *options,
- Error **errp)
+ QDict *options, Error **errp)
{
int ret;
int matches;
@@ -1087,6 +1086,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
const char *p, *np;
int64_t sectors = 0;
int64_t flat_offset;
+ char *desc_file_dir = NULL;
char *extent_path;
BdrvChild *extent_file;
BDRVVmdkState *s = bs->opaque;
@@ -1130,16 +1130,23 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
continue;
}
- if (!path_is_absolute(fname) && !path_has_protocol(fname) &&
- !desc_file_path[0])
- {
- bdrv_refresh_filename(bs->file->bs);
- error_setg(errp, "Cannot use relative extent paths with VMDK "
- "descriptor file '%s'", bs->file->bs->filename);
- return -EINVAL;
- }
+ if (path_is_absolute(fname)) {
+ extent_path = g_strdup(fname);
+ } else {
+ if (!desc_file_dir) {
+ desc_file_dir = bdrv_dirname(bs->file->bs, errp);
+ if (!desc_file_dir) {
+ bdrv_refresh_filename(bs->file->bs);
+ error_prepend(errp, "Cannot use relative paths with VMDK "
+ "descriptor file '%s': ",
+ bs->file->bs->filename);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
- extent_path = path_combine(desc_file_path, fname);
+ extent_path = g_strconcat(desc_file_dir, fname, NULL);
+ }
ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
assert(ret < 32);
@@ -1149,7 +1156,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
g_free(extent_path);
if (local_err) {
error_propagate(errp, local_err);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
/* save to extents array */
@@ -1160,7 +1168,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
0, 0, 0, 0, 0, &extent, errp);
if (ret < 0) {
bdrv_unref_child(bs, extent_file);
- return ret;
+ goto out;
}
extent->flat_start_offset = flat_offset << 9;
} else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) {
@@ -1175,24 +1183,27 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
g_free(buf);
if (ret) {
bdrv_unref_child(bs, extent_file);
- return ret;
+ goto out;
}
extent = &s->extents[s->num_extents - 1];
} else if (!strcmp(type, "SESPARSE")) {
ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
if (ret) {
bdrv_unref_child(bs, extent_file);
- return ret;
+ goto out;
}
extent = &s->extents[s->num_extents - 1];
} else {
error_setg(errp, "Unsupported extent type '%s'", type);
bdrv_unref_child(bs, extent_file);
- return -ENOTSUP;
+ ret = -ENOTSUP;
+ goto out;
}
extent->type = g_strdup(type);
}
- return 0;
+
+ ret = 0;
+ goto out;
invalid:
np = next_line(p);
@@ -1201,7 +1212,11 @@ invalid:
np--;
}
error_setg(errp, "Invalid extent line: %.*s", (int)(np - p), p);
- return -EINVAL;
+ ret = -EINVAL;
+
+out:
+ g_free(desc_file_dir);
+ return ret;
}
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
@@ -1228,8 +1243,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
}
s->create_type = g_strdup(ct);
s->desc_offset = 0;
- ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options,
- errp);
+ ret = vmdk_parse_extents(buf, bs, options, errp);
exit:
return ret;
}
@@ -1720,6 +1734,16 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
if (extent->compressed) {
void *compressed_data;
+ /* Only whole clusters */
+ if (offset_in_cluster ||
+ n_bytes > (extent->cluster_sectors * SECTOR_SIZE) ||
+ (n_bytes < (extent->cluster_sectors * SECTOR_SIZE) &&
+ offset + n_bytes != extent->end_sector * SECTOR_SIZE))
+ {
+ ret = -EINVAL;
+ goto out;
+ }
+
if (!extent->has_marker) {
ret = -EINVAL;
goto out;
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 7a71da447f..213f226ac1 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -101,7 +101,7 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
qio_net_listener_set_name(nbd_server->listener,
"nbd-listener");
- if (qio_net_listener_open_sync(nbd_server->listener, addr, errp) < 0) {
+ if (qio_net_listener_open_sync(nbd_server->listener, addr, 1, errp) < 0) {
goto error;
}
@@ -187,8 +187,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
writable = false;
}
- exp = nbd_export_new(bs, 0, len, name, NULL, bitmap,
- writable ? 0 : NBD_FLAG_READ_ONLY,
+ exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, !writable, !writable,
NULL, false, on_eject_blk, errp);
if (!exp) {
return;
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 03f03407b0..185fe38dda 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -1170,7 +1170,7 @@ static int qmp_chardev_open_socket_server(Chardev *chr,
qio_net_listener_set_name(s->listener, name);
g_free(name);
- if (qio_net_listener_open_sync(s->listener, s->addr, errp) < 0) {
+ if (qio_net_listener_open_sync(s->listener, s->addr, 1, errp) < 0) {
object_unref(OBJECT(s->listener));
s->listener = NULL;
return -1;
diff --git a/configure b/configure
index e44e454c43..30aad233d1 100755
--- a/configure
+++ b/configure
@@ -495,27 +495,10 @@ qed="yes"
parallels="yes"
sheepdog="yes"
libxml2=""
-docker="no"
debug_mutex="no"
libpmem=""
default_devices="yes"
-# cross compilers defaults, can be overridden with --cross-cc-ARCH
-cross_cc_aarch64="aarch64-linux-gnu-gcc"
-cross_cc_aarch64_be="$cross_cc_aarch64"
-cross_cc_cflags_aarch64_be="-mbig-endian"
-cross_cc_arm="arm-linux-gnueabihf-gcc"
-cross_cc_cflags_armeb="-mbig-endian"
-cross_cc_i386="i386-pc-linux-gnu-gcc"
-cross_cc_cflags_i386=""
-cross_cc_ppc="powerpc-linux-gnu-gcc"
-cross_cc_cflags_ppc="-m32"
-cross_cc_ppc64="powerpc-linux-gnu-gcc"
-cross_cc_cflags_ppc64="-m64"
-cross_cc_ppc64le="powerpc64le-linux-gnu-gcc"
-
-enabled_cross_compilers=""
-
supported_cpu="no"
supported_os="no"
bogus_os="no"
@@ -548,9 +531,12 @@ for opt do
;;
--cross-cc-cflags-*) cc_arch=${opt#--cross-cc-flags-}; cc_arch=${cc_arch%%=*}
eval "cross_cc_cflags_${cc_arch}=\$optarg"
+ cross_cc_vars="$cross_cc_vars cross_cc_cflags_${cc_arch}"
;;
--cross-cc-*) cc_arch=${opt#--cross-cc-}; cc_arch=${cc_arch%%=*}
+ cc_archs="$cc_archs $cc_arch"
eval "cross_cc_${cc_arch}=\$optarg"
+ cross_cc_vars="$cross_cc_vars cross_cc_${cc_arch}"
;;
esac
done
@@ -745,42 +731,34 @@ ARCH=
case "$cpu" in
ppc|ppc64|s390|s390x|sparc64|x32|riscv32|riscv64)
supported_cpu="yes"
- eval "cross_cc_${cpu}=\$host_cc"
;;
ppc64le)
ARCH="ppc64"
supported_cpu="yes"
- cross_cc_ppc64le=$host_cc
;;
i386|i486|i586|i686|i86pc|BePC)
cpu="i386"
supported_cpu="yes"
- cross_cc_i386=$host_cc
;;
x86_64|amd64)
cpu="x86_64"
supported_cpu="yes"
- cross_cc_x86_64=$host_cc
;;
armv*b|armv*l|arm)
cpu="arm"
supported_cpu="yes"
- cross_cc_arm=$host_cc
;;
aarch64)
cpu="aarch64"
supported_cpu="yes"
- cross_cc_aarch64=$host_cc
;;
mips*)
cpu="mips"
supported_cpu="yes"
- cross_cc_mips=$host_cc
;;
sparc|sun4[cdmuv])
cpu="sparc"
supported_cpu="yes"
- cross_cc_sparc=$host_cc
;;
*)
# This will result in either an error or falling back to TCI later
@@ -1555,44 +1533,30 @@ case "$cpu" in
ppc)
CPU_CFLAGS="-m32"
LDFLAGS="-m32 $LDFLAGS"
- cross_cc_ppc=$cc
- cross_cc_cflags_ppc="$CPU_CFLAGS"
;;
ppc64)
CPU_CFLAGS="-m64"
LDFLAGS="-m64 $LDFLAGS"
- cross_cc_ppc64=$cc
- cross_cc_cflags_ppc64="$CPU_CFLAGS"
;;
sparc)
CPU_CFLAGS="-m32 -mv8plus -mcpu=ultrasparc"
LDFLAGS="-m32 -mv8plus $LDFLAGS"
- cross_cc_sparc=$cc
- cross_cc_cflags_sparc="$CPU_CFLAGS"
;;
sparc64)
CPU_CFLAGS="-m64 -mcpu=ultrasparc"
LDFLAGS="-m64 $LDFLAGS"
- cross_cc_sparc64=$cc
- cross_cc_cflags_sparc64="$CPU_CFLAGS"
;;
s390)
CPU_CFLAGS="-m31"
LDFLAGS="-m31 $LDFLAGS"
- cross_cc_s390=$cc
- cross_cc_cflags_s390="$CPU_CFLAGS"
;;
s390x)
CPU_CFLAGS="-m64"
LDFLAGS="-m64 $LDFLAGS"
- cross_cc_s390x=$cc
- cross_cc_cflags_s390x="$CPU_CFLAGS"
;;
i386)
CPU_CFLAGS="-m32"
LDFLAGS="-m32 $LDFLAGS"
- cross_cc_i386=$cc
- cross_cc_cflags_i386="$CPU_CFLAGS"
;;
x86_64)
# ??? Only extremely old AMD cpus do not have cmpxchg16b.
@@ -1600,18 +1564,16 @@ case "$cpu" in
# runtime and generate the fallback to serial emulation.
CPU_CFLAGS="-m64 -mcx16"
LDFLAGS="-m64 $LDFLAGS"
- cross_cc_x86_64=$cc
- cross_cc_cflags_x86_64="$CPU_CFLAGS"
;;
x32)
CPU_CFLAGS="-mx32"
LDFLAGS="-mx32 $LDFLAGS"
- cross_cc_i386=$cc
- cross_cc_cflags_i386="$CPU_CFLAGS"
;;
# No special flags required for other host CPUs
esac
+eval "cross_cc_${cpu}=\$host_cc"
+cross_cc_vars="$cross_cc_vars cross_cc_${cpu}"
QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS"
# For user-mode emulation the host arch has to be one we explicitly
@@ -1864,7 +1826,7 @@ if ! $python -c 'import sys; sys.exit(sys.version_info < (2,7))'; then
fi
# Preserve python version since some functionality is dependent on it
-python_version=$($python -V 2>&1 | sed -e 's/Python\ //')
+python_version=$($python -c 'import sys; print("%d.%d.%d" % (sys.version_info[0], sys.version_info[1], sys.version_info[2]))' 2>/dev/null)
# Suppress writing compiled files
python="$python -B"
@@ -2059,6 +2021,12 @@ static THREAD int tls_var;
int main(void) { return tls_var; }
EOF
+ # check we support --no-pie first...
+ if compile_prog "-Werror -fno-pie" "-no-pie"; then
+ CFLAGS_NOPIE="-fno-pie"
+ LDFLAGS_NOPIE="-nopie"
+ fi
+
if compile_prog "-fPIE -DPIE" "-pie"; then
QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS"
LDFLAGS="-pie $LDFLAGS"
@@ -2074,11 +2042,6 @@ EOF
pie="no"
fi
fi
-
- if compile_prog "-Werror -fno-pie" "-nopie"; then
- CFLAGS_NOPIE="-fno-pie"
- LDFLAGS_NOPIE="-nopie"
- fi
fi
##########################################
@@ -5894,17 +5857,6 @@ EOF
fi
##########################################
-# Docker and cross-compiler support
-#
-# This is specifically for building test
-# cases for foreign architectures, not
-# cross-compiling QEMU itself.
-
-if has "docker"; then
- docker=$($python $source_path/tests/docker/docker.py probe)
-fi
-
-##########################################
# check for libpmem
if test "$libpmem" != "no"; then
@@ -6474,7 +6426,6 @@ echo "qed support $qed"
echo "parallels support $parallels"
echo "sheepdog support $sheepdog"
echo "capstone $capstone"
-echo "docker $docker"
echo "libpmem support $libpmem"
echo "libudev $libudev"
echo "default devices $default_devices"
@@ -6511,6 +6462,7 @@ if ! $python -c 'import sys; sys.exit(sys.version_info < (3,0))'; then
echo
echo "warning: Python 2 support is deprecated" >&2
echo "warning: Python 3 will be required for building future versions of QEMU" >&2
+ python2="y"
fi
config_host_mak="config-host.mak"
@@ -7333,7 +7285,7 @@ echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak
echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak
echo "INSTALL_LIB=$install -c -m 0644" >> $config_host_mak
echo "PYTHON=$python" >> $config_host_mak
-echo "PYTHON_VERSION=$python_version" >> $config_host_mak
+echo "PYTHON2=$python2" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
if $iasl -h > /dev/null 2>&1; then
echo "IASL=$iasl" >> $config_host_mak
@@ -7383,10 +7335,6 @@ if test "$gcov" = "yes" ; then
echo "GCOV=$gcov_tool" >> $config_host_mak
fi
-if test "$docker" != "no"; then
- echo "HAVE_USER_DOCKER=y" >> $config_host_mak
-fi
-
if test "$libudev" != "no"; then
echo "CONFIG_LIBUDEV=y" >> $config_host_mak
echo "LIBUDEV_LIBS=$libudev_libs" >> $config_host_mak
@@ -7460,10 +7408,6 @@ case "$target" in
;;
esac
-target_compiler=""
-target_compiler_static=""
-target_compiler_cflags=""
-
mkdir -p $target_dir
echo "# Automatically generated by configure - do not modify" > $config_target_mak
@@ -7480,26 +7424,20 @@ case "$target_name" in
i386)
mttcg="yes"
gdb_xml_files="i386-32bit.xml"
- target_compiler=$cross_cc_i386
- target_compiler_cflags=$cross_cc_ccflags_i386
;;
x86_64)
TARGET_BASE_ARCH=i386
mttcg="yes"
gdb_xml_files="i386-64bit.xml"
- target_compiler=$cross_cc_x86_64
;;
alpha)
mttcg="yes"
- target_compiler=$cross_cc_alpha
;;
arm|armeb)
TARGET_ARCH=arm
bflt="yes"
mttcg="yes"
gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
- target_compiler=$cross_cc_arm
- eval "target_compiler_cflags=\$cross_cc_cflags_${target_name}"
;;
aarch64|aarch64_be)
TARGET_ARCH=aarch64
@@ -7507,41 +7445,32 @@ case "$target_name" in
bflt="yes"
mttcg="yes"
gdb_xml_files="aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
- target_compiler=$cross_cc_aarch64
- eval "target_compiler_cflags=\$cross_cc_cflags_${target_name}"
;;
cris)
- target_compiler=$cross_cc_cris
;;
hppa)
mttcg="yes"
- target_compiler=$cross_cc_hppa
;;
lm32)
- target_compiler=$cross_cc_lm32
;;
m68k)
bflt="yes"
gdb_xml_files="cf-core.xml cf-fp.xml m68k-fp.xml"
- target_compiler=$cross_cc_m68k
;;
microblaze|microblazeel)
TARGET_ARCH=microblaze
bflt="yes"
echo "TARGET_ABI32=y" >> $config_target_mak
- target_compiler=$cross_cc_microblaze
;;
mips|mipsel)
mttcg="yes"
TARGET_ARCH=mips
- target_compiler=$cross_cc_mips
echo "TARGET_ABI_MIPSO32=y" >> $config_target_mak
;;
mipsn32|mipsn32el)
mttcg="yes"
TARGET_ARCH=mips64
TARGET_BASE_ARCH=mips
- target_compiler=$cross_cc_mipsn32
echo "TARGET_ABI_MIPSN32=y" >> $config_target_mak
echo "TARGET_ABI32=y" >> $config_target_mak
;;
@@ -7549,32 +7478,24 @@ case "$target_name" in
mttcg="yes"
TARGET_ARCH=mips64
TARGET_BASE_ARCH=mips
- target_compiler=$cross_cc_mips64
echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
;;
moxie)
- target_compiler=$cross_cc_moxie
;;
nios2)
- target_compiler=$cross_cc_nios2
;;
or1k)
- target_compiler=$cross_cc_or1k
TARGET_ARCH=openrisc
TARGET_BASE_ARCH=openrisc
;;
ppc)
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
- target_compiler=$cross_cc_ppc
- target_compiler_cflags="$cross_cc_cflags_ppc"
;;
ppc64)
TARGET_BASE_ARCH=ppc
TARGET_ABI_DIR=ppc
mttcg=yes
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml"
- target_compiler=$cross_cc_ppc64
- target_compiler_cflags="$cross_cc_cflags_ppc64"
;;
ppc64le)
TARGET_ARCH=ppc64
@@ -7582,7 +7503,6 @@ case "$target_name" in
TARGET_ABI_DIR=ppc
mttcg=yes
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml"
- target_compiler=$cross_cc_ppc64le
;;
ppc64abi32)
TARGET_ARCH=ppc64
@@ -7590,60 +7510,48 @@ case "$target_name" in
TARGET_ABI_DIR=ppc
echo "TARGET_ABI32=y" >> $config_target_mak
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml"
- target_compiler=$cross_cc_ppc64abi32
;;
riscv32)
TARGET_BASE_ARCH=riscv
TARGET_ABI_DIR=riscv
mttcg=yes
gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-32bit-csr.xml"
- target_compiler=$cross_cc_riscv32
;;
riscv64)
TARGET_BASE_ARCH=riscv
TARGET_ABI_DIR=riscv
mttcg=yes
gdb_xml_files="riscv-64bit-cpu.xml riscv-64bit-fpu.xml riscv-64bit-csr.xml"
- target_compiler=$cross_cc_riscv64
;;
sh4|sh4eb)
TARGET_ARCH=sh4
bflt="yes"
- target_compiler=$cross_cc_sh4
;;
sparc)
- target_compiler=$cross_cc_sparc
;;
sparc64)
TARGET_BASE_ARCH=sparc
- target_compiler=$cross_cc_sparc64
;;
sparc32plus)
TARGET_ARCH=sparc64
TARGET_BASE_ARCH=sparc
TARGET_ABI_DIR=sparc
- target_compiler=$cross_cc_sparc32plus
echo "TARGET_ABI32=y" >> $config_target_mak
;;
s390x)
mttcg=yes
gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml s390-virt.xml s390-gs.xml"
- target_compiler=$cross_cc_s390x
;;
tilegx)
- target_compiler=$cross_cc_tilegx
;;
tricore)
- target_compiler=$cross_cc_tricore
;;
unicore32)
- target_compiler=$cross_cc_unicore32
;;
xtensa|xtensaeb)
TARGET_ARCH=xtensa
bflt="yes"
mttcg="yes"
- target_compiler=$cross_cc_xtensa
;;
*)
error_exit "Unsupported target CPU"
@@ -7654,27 +7562,6 @@ if [ "$TARGET_BASE_ARCH" = "" ]; then
TARGET_BASE_ARCH=$TARGET_ARCH
fi
-# Do we have a cross compiler for this target?
-if has $target_compiler; then
-
- write_c_skeleton
-
- if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC -static ; then
- # For host systems we might get away with building without -static
- if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC ; then
- target_compiler=""
- else
- enabled_cross_compilers="${enabled_cross_compilers} '${target_compiler}'"
- target_compiler_static="n"
- fi
- else
- enabled_cross_compilers="${enabled_cross_compilers} '${target_compiler}'"
- target_compiler_static="y"
- fi
-else
- target_compiler=""
-fi
-
symlink "$source_path/Makefile.target" "$target_dir/Makefile"
upper() {
@@ -7751,18 +7638,6 @@ if test "$target_bsd_user" = "yes" ; then
echo "CONFIG_BSD_USER=y" >> $config_target_mak
fi
-if test -n "$target_compiler"; then
- echo "CROSS_CC_GUEST=\"$target_compiler\"" >> $config_target_mak
-
- if test -n "$target_compiler_static"; then
- echo "CROSS_CC_GUEST_STATIC=$target_compiler_static" >> $config_target_mak
- fi
-
- if test -n "$target_compiler_cflags"; then
- echo "CROSS_CC_GUEST_CFLAGS=$target_compiler_cflags" >> $config_target_mak
- fi
-fi
-
# generate QEMU_CFLAGS/LDFLAGS for targets
@@ -7893,11 +7768,6 @@ done # for target in $targets
echo "PIXMAN_CFLAGS=$pixman_cflags" >> $config_host_mak
echo "PIXMAN_LIBS=$pixman_libs" >> $config_host_mak
-if test -n "$enabled_cross_compilers"; then
- echo
- echo "NOTE: cross-compilers enabled: $enabled_cross_compilers"
-fi
-
if [ "$fdt" = "git" ]; then
echo "config-host.h: dtc/all" >> $config_host_mak
fi
@@ -7926,15 +7796,14 @@ fi
# so the build tree will be missing the link back to the new file, and
# tests might fail. Prefer to keep the relevant files in their own
# directory and symlink the directory instead.
-DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm"
+DIRS="tests tests/tcg tests/tcg/lm32 tests/libqos tests/qapi-schema tests/qemu-iotests tests/vm"
DIRS="$DIRS tests/fp tests/qgraph"
DIRS="$DIRS docs docs/interop fsdev scsi"
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
DIRS="$DIRS roms/seabios roms/vgabios"
-LINKS="Makefile tests/tcg/Makefile"
-LINKS="$LINKS tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
-LINKS="$LINKS tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makefile"
-LINKS="$LINKS tests/fp/Makefile"
+LINKS="Makefile"
+LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile"
+LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile"
LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps"
LINKS="$LINKS pc-bios/spapr-rtas/Makefile"
LINKS="$LINKS pc-bios/s390-ccw/Makefile"
@@ -7964,6 +7833,12 @@ for f in $LINKS ; do
fi
done
+(for i in $cross_cc_vars; do
+ export $i
+done
+export target_list source_path
+$source_path/tests/tcg/configure.sh)
+
# temporary config to build submodules
for rom in seabios vgabios ; do
config_mak=roms/$rom/config.mak
diff --git a/contrib/gitdm/aliases b/contrib/gitdm/aliases
index 07fd3391a5..c1e744312f 100644
--- a/contrib/gitdm/aliases
+++ b/contrib/gitdm/aliases
@@ -1,6 +1,22 @@
#
-# This is the email aliases file, mapping secondary addresses
-# onto a single, canonical address. Duplicates some info from .mailmap
+# This is the email aliases file, mapping secondary addresses onto a
+# single, canonical address. It duplicates some info from .mailmap so
+# if you are adding something here also consider if the .mailmap needs
+# updating.
+#
+# If you just want to avoid gitdm complaining about author fields
+# which are actually email addresses with the message:
+#
+# "...is an author name, probably not what you want"
+#
+# you can just apply --use-mailmap to you git-log command, e.g:
+#
+# git log --use-mailmap --numstat --since "last 2 years" | $GITDM
+#
+# however that will have the effect of squashing multiple addresses to
+# a canonical address which will distort the stats of those who
+# contribute in both personal and professional capacities from
+# different addresses.
#
# weird commits
diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map
index fa9d454473..9efe066ec9 100644
--- a/contrib/gitdm/domain-map
+++ b/contrib/gitdm/domain-map
@@ -18,6 +18,7 @@ nokia.com Nokia
oracle.com Oracle
proxmox.com Proxmox
redhat.com Red Hat
+rt-rk.com RT-RK
siemens.com Siemens
sifive.com SiFive
suse.de SUSE
diff --git a/contrib/gitdm/filetypes.txt b/contrib/gitdm/filetypes.txt
index 165b71b3f9..2d5002fea0 100644
--- a/contrib/gitdm/filetypes.txt
+++ b/contrib/gitdm/filetypes.txt
@@ -34,7 +34,7 @@
# If there is an filetype which is not in order but has values, it will
# be added at the end.
#
-order build,tests,code,documentation,devel-doc,blobs
+order build,interface,tests,code,documentation,devel-doc,blobs
#
#
diff --git a/contrib/gitdm/group-map-individuals b/contrib/gitdm/group-map-individuals
index 05e355d30e..1c84717438 100644
--- a/contrib/gitdm/group-map-individuals
+++ b/contrib/gitdm/group-map-individuals
@@ -2,7 +2,8 @@
# Individual and personal contributors
#
# This is simply to allow prolific developers with no company
-# affiliations to be grouped together in the summary stats.
+# affiliations (or non-company related personal work) to be grouped
+# together in the summary stats.
#
f4bug@amsat.org
diff --git a/contrib/gitdm/group-map-redhat b/contrib/gitdm/group-map-redhat
index 6d05c6b54f..d15db2d35e 100644
--- a/contrib/gitdm/group-map-redhat
+++ b/contrib/gitdm/group-map-redhat
@@ -5,3 +5,4 @@
david@gibson.dropbear.id.au
laurent@vivier.eu
pjp@fedoraproject.org
+armbru@pond.sub.org
diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
index 4b36e35a82..68c27136ae 100644
--- a/contrib/libvhost-user/libvhost-user.c
+++ b/contrib/libvhost-user/libvhost-user.c
@@ -94,6 +94,11 @@ bool vu_has_feature(VuDev *dev,
return has_feature(dev->features, fbit);
}
+static inline bool vu_has_protocol_feature(VuDev *dev, unsigned int fbit)
+{
+ return has_feature(dev->protocol_features, fbit);
+}
+
static const char *
vu_request_to_string(unsigned int req)
{
@@ -951,8 +956,7 @@ vu_check_queue_inflights(VuDev *dev, VuVirtq *vq)
{
int i = 0;
- if (!has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
return 0;
}
@@ -1097,7 +1101,7 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd,
vmsg.fd_num = fd_num;
- if ((dev->protocol_features & VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD) == 0) {
+ if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD)) {
return false;
}
@@ -2190,8 +2194,7 @@ vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz)
static int
vu_queue_inflight_get(VuDev *dev, VuVirtq *vq, int desc_idx)
{
- if (!has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
return 0;
}
@@ -2208,8 +2211,7 @@ vu_queue_inflight_get(VuDev *dev, VuVirtq *vq, int desc_idx)
static int
vu_queue_inflight_pre_put(VuDev *dev, VuVirtq *vq, int desc_idx)
{
- if (!has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
return 0;
}
@@ -2225,8 +2227,7 @@ vu_queue_inflight_pre_put(VuDev *dev, VuVirtq *vq, int desc_idx)
static int
vu_queue_inflight_post_put(VuDev *dev, VuVirtq *vq, int desc_idx)
{
- if (!has_feature(dev->protocol_features,
- VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
+ if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
return 0;
}
diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
index 4049a8f2ba..d67ab8b96d 100644
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -6,3 +6,4 @@ CONFIG_SEMIHOSTING=y
#
CONFIG_AN5206=y
CONFIG_MCF5208=y
+CONFIG_NEXTCUBE=y
diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt
index fc64473e02..4511880961 100644
--- a/docs/interop/nbd.txt
+++ b/docs/interop/nbd.txt
@@ -53,3 +53,5 @@ the operation of that feature.
* 2.12: NBD_CMD_BLOCK_STATUS for "base:allocation"
* 3.0: NBD_OPT_STARTTLS with TLS Pre-Shared Keys (PSK),
NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE
+* 4.2: NBD_FLAG_CAN_MULTI_CONN for sharable read-only exports,
+NBD_CMD_FLAG_FAST_ZERO
diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi
index c02547e28c..2c7ea49c32 100644
--- a/docs/qemu-block-drivers.texi
+++ b/docs/qemu-block-drivers.texi
@@ -2,6 +2,8 @@
QEMU block driver reference manual
@c man end
+@set qemu_system qemu-system-x86_64
+
@c man begin DESCRIPTION
@node disk_images_formats
@@ -405,7 +407,7 @@ QEMU can automatically create a virtual FAT disk image from a
directory tree. In order to use it, just type:
@example
-qemu-system-i386 linux.img -hdb fat:/my_directory
+@value{qemu_system} linux.img -hdb fat:/my_directory
@end example
Then you access access to all the files in the @file{/my_directory}
@@ -415,14 +417,14 @@ them via SAMBA or NFS. The default access is @emph{read-only}.
Floppies can be emulated with the @code{:floppy:} option:
@example
-qemu-system-i386 linux.img -fda fat:floppy:/my_directory
+@value{qemu_system} linux.img -fda fat:floppy:/my_directory
@end example
A read/write support is available for testing (beta stage) with the
@code{:rw:} option:
@example
-qemu-system-i386 linux.img -fda fat:floppy:rw:/my_directory
+@value{qemu_system} linux.img -fda fat:floppy:rw:/my_directory
@end example
What you should @emph{never} do:
@@ -440,14 +442,14 @@ QEMU can access directly to block device exported using the Network Block Device
protocol.
@example
-qemu-system-i386 linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/
+@value{qemu_system} linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/
@end example
If the NBD server is located on the same host, you can use an unix socket instead
of an inet socket:
@example
-qemu-system-i386 linux.img -hdb nbd+unix://?socket=/tmp/my_socket
+@value{qemu_system} linux.img -hdb nbd+unix://?socket=/tmp/my_socket
@end example
In this case, the block device must be exported using qemu-nbd:
@@ -464,23 +466,23 @@ qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
@noindent
and then you can use it with two guests:
@example
-qemu-system-i386 linux1.img -hdb nbd+unix://?socket=/tmp/my_socket
-qemu-system-i386 linux2.img -hdb nbd+unix://?socket=/tmp/my_socket
+@value{qemu_system} linux1.img -hdb nbd+unix://?socket=/tmp/my_socket
+@value{qemu_system} linux2.img -hdb nbd+unix://?socket=/tmp/my_socket
@end example
If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's
own embedded NBD server), you must specify an export name in the URI:
@example
-qemu-system-i386 -cdrom nbd://localhost/debian-500-ppc-netinst
-qemu-system-i386 -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst
+@value{qemu_system} -cdrom nbd://localhost/debian-500-ppc-netinst
+@value{qemu_system} -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst
@end example
The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is
also available. Here are some example of the older syntax:
@example
-qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
-qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket
-qemu-system-i386 -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst
+@value{qemu_system} linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
+@value{qemu_system} linux2.img -hdb nbd:unix:/tmp/my_socket
+@value{qemu_system} -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst
@end example
@node disk_images_sheepdog
@@ -505,7 +507,7 @@ qemu-img convert @var{filename} sheepdog:///@var{image}
You can boot from the Sheepdog disk image with the command:
@example
-qemu-system-i386 sheepdog:///@var{image}
+@value{qemu_system} sheepdog:///@var{image}
@end example
You can also create a snapshot of the Sheepdog image like qcow2.
@@ -517,7 +519,7 @@ where @var{tag} is a tag name of the newly created snapshot.
To boot from the Sheepdog snapshot, specify the tag name of the
snapshot.
@example
-qemu-system-i386 sheepdog:///@var{image}#@var{tag}
+@value{qemu_system} sheepdog:///@var{image}#@var{tag}
@end example
You can create a cloned image from the existing snapshot.
@@ -530,14 +532,14 @@ is its tag name.
You can use an unix socket instead of an inet socket:
@example
-qemu-system-i386 sheepdog+unix:///@var{image}?socket=@var{path}
+@value{qemu_system} sheepdog+unix:///@var{image}?socket=@var{path}
@end example
If the Sheepdog daemon doesn't run on the local host, you need to
specify one of the Sheepdog servers to connect to.
@example
qemu-img create sheepdog://@var{hostname}:@var{port}/@var{image} @var{size}
-qemu-system-i386 sheepdog://@var{hostname}:@var{port}/@var{image}
+@value{qemu_system} sheepdog://@var{hostname}:@var{port}/@var{image}
@end example
@node disk_images_iscsi
@@ -627,7 +629,7 @@ cat >iscsi.conf <<EOF
header-digest = "CRC32C"
EOF
-qemu-system-i386 -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
+@value{qemu_system} -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
-readconfig iscsi.conf
@end example
@@ -646,7 +648,7 @@ tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 2 \
-b /IMAGES/cd.iso --device-type=cd
tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
-qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \
+@value{qemu_system} -iscsi initiator-name=iqn.qemu.test:my-initiator \
-boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
-cdrom iscsi://127.0.0.1/iqn.qemu.test/2
@end example
@@ -659,11 +661,11 @@ GlusterFS is a user space distributed file system.
You can boot from the GlusterFS disk image with the command:
@example
URI:
-qemu-system-x86_64 -drive file=gluster[+@var{type}]://[@var{host}[:@var{port}]]/@var{volume}/@var{path}
+@value{qemu_system} -drive file=gluster[+@var{type}]://[@var{host}[:@var{port}]]/@var{volume}/@var{path}
[?socket=...][,file.debug=9][,file.logfile=...]
JSON:
-qemu-system-x86_64 'json:@{"driver":"qcow2",
+@value{qemu_system} 'json:@{"driver":"qcow2",
"file":@{"driver":"gluster",
"volume":"testvol","path":"a.img","debug":9,"logfile":"...",
"server":[@{"type":"tcp","host":"...","port":"..."@},
@@ -711,22 +713,22 @@ qemu-img create gluster://@var{host}/@var{volume}/@var{path} @var{size}
Examples
@example
-qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img
-qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4/testvol/a.img
-qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
-qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img
-qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img
-qemu-system-x86_64 -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img
-qemu-system-x86_64 -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket
-qemu-system-x86_64 -drive file=gluster+rdma://1.2.3.4:24007/testvol/a.img
-qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img,file.debug=9,file.logfile=/var/log/qemu-gluster.log
-qemu-system-x86_64 'json:@{"driver":"qcow2",
+@value{qemu_system} -drive file=gluster://1.2.3.4/testvol/a.img
+@value{qemu_system} -drive file=gluster+tcp://1.2.3.4/testvol/a.img
+@value{qemu_system} -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
+@value{qemu_system} -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img
+@value{qemu_system} -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img
+@value{qemu_system} -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img
+@value{qemu_system} -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket
+@value{qemu_system} -drive file=gluster+rdma://1.2.3.4:24007/testvol/a.img
+@value{qemu_system} -drive file=gluster://1.2.3.4/testvol/a.img,file.debug=9,file.logfile=/var/log/qemu-gluster.log
+@value{qemu_system} 'json:@{"driver":"qcow2",
"file":@{"driver":"gluster",
"volume":"testvol","path":"a.img",
"debug":9,"logfile":"/var/log/qemu-gluster.log",
"server":[@{"type":"tcp","host":"1.2.3.4","port":24007@},
@{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}'
-qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img,
+@value{qemu_system} -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img,
file.debug=9,file.logfile=/var/log/qemu-gluster.log,
file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007,
file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket
@@ -739,13 +741,13 @@ You can access disk images located on a remote ssh server
by using the ssh protocol:
@example
-qemu-system-x86_64 -drive file=ssh://[@var{user}@@]@var{server}[:@var{port}]/@var{path}[?host_key_check=@var{host_key_check}]
+@value{qemu_system} -drive file=ssh://[@var{user}@@]@var{server}[:@var{port}]/@var{path}[?host_key_check=@var{host_key_check}]
@end example
Alternative syntax using properties:
@example
-qemu-system-x86_64 -drive file.driver=ssh[,file.user=@var{user}],file.host=@var{server}[,file.port=@var{port}],file.path=@var{path}[,file.host_key_check=@var{host_key_check}]
+@value{qemu_system} -drive file.driver=ssh[,file.user=@var{user}],file.host=@var{server}[,file.port=@var{port}],file.path=@var{path}[,file.host_key_check=@var{host_key_check}]
@end example
@var{ssh} is the protocol.
@@ -808,13 +810,13 @@ driver. For example:
# echo 0000:06:0d.0 > /sys/bus/pci/devices/0000:06:0d.0/driver/unbind
# echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id
-# qemu-system-x86_64 -drive file=nvme://@var{host}:@var{bus}:@var{slot}.@var{func}/@var{namespace}
+# @value{qemu_system} -drive file=nvme://@var{host}:@var{bus}:@var{slot}.@var{func}/@var{namespace}
@end example
Alternative syntax using properties:
@example
-qemu-system-x86_64 -drive file.driver=nvme,file.device=@var{host}:@var{bus}:@var{slot}.@var{func},file.namespace=@var{namespace}
+@value{qemu_system} -drive file.driver=nvme,file.device=@var{host}:@var{bus}:@var{slot}.@var{func},file.namespace=@var{namespace}
@end example
@var{host}:@var{bus}:@var{slot}.@var{func} is the NVMe controller's PCI device
diff --git a/docs/qemu-cpu-models.texi b/docs/qemu-cpu-models.texi
index ad040cfc98..f88a1def0d 100644
--- a/docs/qemu-cpu-models.texi
+++ b/docs/qemu-cpu-models.texi
@@ -2,6 +2,8 @@
QEMU / KVM CPU model configuration
@c man end
+@set qemu_system_x86 qemu-system-x86_64
+
@c man begin DESCRIPTION
@menu
@@ -578,25 +580,25 @@ CPU models / features in QEMU and libvirt
@item Host passthrough
@example
- $ qemu-system-x86_64 -cpu host
+ $ @value{qemu_system_x86} -cpu host
@end example
With feature customization:
@example
- $ qemu-system-x86_64 -cpu host,-vmx,...
+ $ @value{qemu_system_x86} -cpu host,-vmx,...
@end example
@item Named CPU models
@example
- $ qemu-system-x86_64 -cpu Westmere
+ $ @value{qemu_system_x86} -cpu Westmere
@end example
With feature customization:
@example
- $ qemu-system-x86_64 -cpu Westmere,+pcid,...
+ $ @value{qemu_system_x86} -cpu Westmere,+pcid,...
@end example
@end table
diff --git a/exec.c b/exec.c
index 1df966d17a..235d6bc883 100644
--- a/exec.c
+++ b/exec.c
@@ -193,15 +193,12 @@ typedef struct subpage_t {
#define PHYS_SECTION_UNASSIGNED 0
#define PHYS_SECTION_NOTDIRTY 1
#define PHYS_SECTION_ROM 2
-#define PHYS_SECTION_WATCH 3
static void io_mem_init(void);
static void memory_map_init(void);
static void tcg_log_global_after_sync(MemoryListener *listener);
static void tcg_commit(MemoryListener *listener);
-static MemoryRegion io_mem_watch;
-
/**
* CPUAddressSpace: all the information a CPU needs about an AddressSpace
* @cpu: the CPU whose AddressSpace this is
@@ -1062,28 +1059,7 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
}
#endif
-#if defined(CONFIG_USER_ONLY)
-void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
-
-{
-}
-
-int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len,
- int flags)
-{
- return -ENOSYS;
-}
-
-void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint)
-{
-}
-
-int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
- int flags, CPUWatchpoint **watchpoint)
-{
- return -ENOSYS;
-}
-#else
+#ifndef CONFIG_USER_ONLY
/* Add a watchpoint. */
int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
int flags, CPUWatchpoint **watchpoint)
@@ -1159,9 +1135,8 @@ void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
* partially or completely with the address range covered by the
* access).
*/
-static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
- vaddr addr,
- vaddr len)
+static inline bool watchpoint_address_matches(CPUWatchpoint *wp,
+ vaddr addr, vaddr len)
{
/* We know the lengths are non-zero, but a little caution is
* required to avoid errors in the case where the range ends
@@ -1174,7 +1149,20 @@ static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
return !(addr > wpend || wp->vaddr > addrend);
}
-#endif
+/* Return flags for watchpoints that match addr + prot. */
+int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len)
+{
+ CPUWatchpoint *wp;
+ int ret = 0;
+
+ QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
+ if (watchpoint_address_matches(wp, addr, TARGET_PAGE_SIZE)) {
+ ret |= wp->flags;
+ }
+ }
+ return ret;
+}
+#endif /* !CONFIG_USER_ONLY */
/* Add a breakpoint. */
int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
@@ -1481,7 +1469,6 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
target_ulong *address)
{
hwaddr iotlb;
- CPUWatchpoint *wp;
if (memory_region_is_ram(section->mr)) {
/* Normal RAM. */
@@ -1499,19 +1486,6 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
iotlb += xlat;
}
- /* Make accesses to pages with watchpoints go via the
- watchpoint trap routines. */
- QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
- if (cpu_watchpoint_address_matches(wp, vaddr, TARGET_PAGE_SIZE)) {
- /* Avoid trapping reads of pages with a write breakpoint. */
- if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
- iotlb = PHYS_SECTION_WATCH + paddr;
- *address |= TLB_MMIO;
- break;
- }
- }
- }
-
return iotlb;
}
#endif /* defined(CONFIG_USER_ONLY) */
@@ -1750,6 +1724,7 @@ long qemu_minrampagesize(void)
long hpsize = LONG_MAX;
long mainrampagesize;
Object *memdev_root;
+ MachineState *ms = MACHINE(qdev_get_machine());
mainrampagesize = qemu_mempath_getpagesize(mem_path);
@@ -1777,7 +1752,9 @@ long qemu_minrampagesize(void)
* so if its page size is smaller we have got to report that size instead.
*/
if (hpsize > mainrampagesize &&
- (nb_numa_nodes == 0 || numa_info[0].node_memdev == NULL)) {
+ (ms->numa_state == NULL ||
+ ms->numa_state->num_nodes == 0 ||
+ ms->numa_state->nodes[0].node_memdev == NULL)) {
static bool warned;
if (!warned) {
error_report("Huge page support disabled (n/a for main memory).");
@@ -2811,32 +2788,35 @@ static const MemoryRegionOps notdirty_mem_ops = {
};
/* Generate a debug exception if a watchpoint has been hit. */
-static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
+void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
+ MemTxAttrs attrs, int flags, uintptr_t ra)
{
- CPUState *cpu = current_cpu;
CPUClass *cc = CPU_GET_CLASS(cpu);
- target_ulong vaddr;
CPUWatchpoint *wp;
assert(tcg_enabled());
if (cpu->watchpoint_hit) {
- /* We re-entered the check after replacing the TB. Now raise
- * the debug interrupt so that is will trigger after the
- * current instruction. */
+ /*
+ * We re-entered the check after replacing the TB.
+ * Now raise the debug interrupt so that it will
+ * trigger after the current instruction.
+ */
+ qemu_mutex_lock_iothread();
cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
+ qemu_mutex_unlock_iothread();
return;
}
- vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
- vaddr = cc->adjust_watchpoint_address(cpu, vaddr, len);
+
+ addr = cc->adjust_watchpoint_address(cpu, addr, len);
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
- if (cpu_watchpoint_address_matches(wp, vaddr, len)
+ if (watchpoint_address_matches(wp, addr, len)
&& (wp->flags & flags)) {
if (flags == BP_MEM_READ) {
wp->flags |= BP_WATCHPOINT_HIT_READ;
} else {
wp->flags |= BP_WATCHPOINT_HIT_WRITE;
}
- wp->hitaddr = vaddr;
+ wp->hitaddr = MAX(addr, wp->vaddr);
wp->hitattrs = attrs;
if (!cpu->watchpoint_hit) {
if (wp->flags & BP_CPU &&
@@ -2851,11 +2831,14 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
if (wp->flags & BP_STOP_BEFORE_ACCESS) {
cpu->exception_index = EXCP_DEBUG;
mmap_unlock();
- cpu_loop_exit(cpu);
+ cpu_loop_exit_restore(cpu, ra);
} else {
/* Force execution of one insn next time. */
cpu->cflags_next_tb = 1 | curr_cflags();
mmap_unlock();
+ if (ra) {
+ cpu_restore_state(cpu, ra, true);
+ }
cpu_loop_exit_noexc(cpu);
}
}
@@ -2865,80 +2848,6 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
}
}
-/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
- so these check for a hit then pass through to the normal out-of-line
- phys routines. */
-static MemTxResult watch_mem_read(void *opaque, hwaddr addr, uint64_t *pdata,
- unsigned size, MemTxAttrs attrs)
-{
- MemTxResult res;
- uint64_t data;
- int asidx = cpu_asidx_from_attrs(current_cpu, attrs);
- AddressSpace *as = current_cpu->cpu_ases[asidx].as;
-
- check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_READ);
- switch (size) {
- case 1:
- data = address_space_ldub(as, addr, attrs, &res);
- break;
- case 2:
- data = address_space_lduw(as, addr, attrs, &res);
- break;
- case 4:
- data = address_space_ldl(as, addr, attrs, &res);
- break;
- case 8:
- data = address_space_ldq(as, addr, attrs, &res);
- break;
- default: abort();
- }
- *pdata = data;
- return res;
-}
-
-static MemTxResult watch_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size,
- MemTxAttrs attrs)
-{
- MemTxResult res;
- int asidx = cpu_asidx_from_attrs(current_cpu, attrs);
- AddressSpace *as = current_cpu->cpu_ases[asidx].as;
-
- check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_WRITE);
- switch (size) {
- case 1:
- address_space_stb(as, addr, val, attrs, &res);
- break;
- case 2:
- address_space_stw(as, addr, val, attrs, &res);
- break;
- case 4:
- address_space_stl(as, addr, val, attrs, &res);
- break;
- case 8:
- address_space_stq(as, addr, val, attrs, &res);
- break;
- default: abort();
- }
- return res;
-}
-
-static const MemoryRegionOps watch_mem_ops = {
- .read_with_attrs = watch_mem_read,
- .write_with_attrs = watch_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 8,
- .unaligned = false,
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 8,
- .unaligned = false,
- },
-};
-
static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf, hwaddr len);
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
@@ -3114,9 +3023,6 @@ static void io_mem_init(void)
memory_region_init_io(&io_mem_notdirty, NULL, &notdirty_mem_ops, NULL,
NULL, UINT64_MAX);
memory_region_clear_global_locking(&io_mem_notdirty);
-
- memory_region_init_io(&io_mem_watch, NULL, &watch_mem_ops, NULL,
- NULL, UINT64_MAX);
}
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
@@ -3130,8 +3036,6 @@ AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
assert(n == PHYS_SECTION_NOTDIRTY);
n = dummy_section(&d->map, fv, &io_mem_rom);
assert(n == PHYS_SECTION_ROM);
- n = dummy_section(&d->map, fv, &io_mem_watch);
- assert(n == PHYS_SECTION_WATCH);
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 };
@@ -3363,8 +3267,9 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
l = memory_access_size(mr, l, addr1);
/* XXX: could force current_cpu to NULL to avoid
potential bugs */
- val = ldn_p(buf, l);
- result |= memory_region_dispatch_write(mr, addr1, val, l, attrs);
+ val = ldn_he_p(buf, l);
+ result |= memory_region_dispatch_write(mr, addr1, val,
+ size_memop(l), attrs);
} else {
/* RAM case */
ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
@@ -3425,8 +3330,9 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
/* I/O case */
release_lock |= prepare_mmio_access(mr);
l = memory_access_size(mr, l, addr1);
- result |= memory_region_dispatch_read(mr, addr1, &val, l, attrs);
- stn_p(buf, l, val);
+ result |= memory_region_dispatch_read(mr, addr1, &val,
+ size_memop(l), attrs);
+ stn_he_p(buf, l, val);
} else {
/* RAM case */
ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
diff --git a/gdbstub.c b/gdbstub.c
index b92ba59e4d..4cf8af365e 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1820,11 +1820,15 @@ static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- if (gdb_ctx->num_params >= 2 && gdb_ctx->s->current_syscall_cb) {
+ if (gdb_ctx->num_params >= 1 && gdb_ctx->s->current_syscall_cb) {
target_ulong ret, err;
ret = (target_ulong)gdb_ctx->params[0].val_ull;
- err = (target_ulong)gdb_ctx->params[1].val_ull;
+ if (gdb_ctx->num_params >= 2) {
+ err = (target_ulong)gdb_ctx->params[1].val_ull;
+ } else {
+ err = 0;
+ }
gdb_ctx->s->current_syscall_cb(gdb_ctx->s->c_cpu, ret, err);
gdb_ctx->s->current_syscall_cb = NULL;
}
@@ -2588,7 +2592,9 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
break;
}
- run_cmd_parser(s, line_buf, cmd_parser);
+ if (cmd_parser) {
+ run_cmd_parser(s, line_buf, cmd_parser);
+ }
return RS_IDLE;
}
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 555c24f21d..78aee1a2f9 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -25,6 +25,7 @@
#include "qemu/bswap.h"
#include "qemu/bitops.h"
#include "sysemu/numa.h"
+#include "hw/boards.h"
static GArray *build_alloc_array(void)
{
@@ -1726,18 +1727,21 @@ void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
* ACPI spec 5.2.17 System Locality Distance Information Table
* (Revision 2.0 or later)
*/
-void build_slit(GArray *table_data, BIOSLinker *linker)
+void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms)
{
int slit_start, i, j;
slit_start = table_data->len;
+ int nb_numa_nodes = ms->numa_state->num_nodes;
acpi_data_push(table_data, sizeof(AcpiTableHeader));
build_append_int_noprefix(table_data, nb_numa_nodes, 8);
for (i = 0; i < nb_numa_nodes; i++) {
for (j = 0; j < nb_numa_nodes; j++) {
- assert(numa_info[i].distance[j]);
- build_append_int_noprefix(table_data, numa_info[i].distance[j], 1);
+ assert(ms->numa_state->nodes[i].distance[j]);
+ build_append_int_noprefix(table_data,
+ ms->numa_state->nodes[i].distance[j],
+ 1);
}
}
diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
index 73810a4440..118032c8c7 100644
--- a/hw/arm/allwinner-a10.c
+++ b/hw/arm/allwinner-a10.c
@@ -30,7 +30,8 @@ static void aw_a10_init(Object *obj)
AwA10State *s = AW_A10(obj);
object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
- "cortex-a8-" TYPE_ARM_CPU, &error_abort, NULL);
+ ARM_CPU_TYPE_NAME("cortex-a8"),
+ &error_abort, NULL);
sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc),
TYPE_AW_A10_PIC);
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 7a2e885e0b..13e208c78c 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -242,9 +242,6 @@ static void aspeed_board_init(MachineState *machine,
write_boot_rom(drive0, FIRMWARE_ADDR, fl->size, &error_abort);
}
- aspeed_board_binfo.kernel_filename = machine->kernel_filename;
- aspeed_board_binfo.initrd_filename = machine->initrd_filename;
- aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
aspeed_board_binfo.ram_size = ram_size;
aspeed_board_binfo.loader_start = sc->info->memmap[ASPEED_SDRAM];
aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus;
@@ -253,7 +250,7 @@ static void aspeed_board_init(MachineState *machine,
cfg->i2c_init(bmc);
}
- arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo);
}
static void palmetto_bmc_i2c_init(AspeedBoardState *bmc)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index eff89ab80e..bf97ef3e33 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -17,6 +17,7 @@
#include "sysemu/kvm.h"
#include "sysemu/sysemu.h"
#include "sysemu/numa.h"
+#include "hw/boards.h"
#include "sysemu/reset.h"
#include "hw/loader.h"
#include "elf.h"
@@ -523,7 +524,7 @@ static void fdt_add_psci_node(void *fdt)
}
int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
- hwaddr addr_limit, AddressSpace *as)
+ hwaddr addr_limit, AddressSpace *as, MachineState *ms)
{
void *fdt = NULL;
int size, rc, n = 0;
@@ -597,10 +598,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
}
g_strfreev(node_path);
- if (nb_numa_nodes > 0) {
+ if (ms->numa_state != NULL && ms->numa_state->num_nodes > 0) {
mem_base = binfo->loader_start;
- for (i = 0; i < nb_numa_nodes; i++) {
- mem_len = numa_info[i].node_mem;
+ for (i = 0; i < ms->numa_state->num_nodes; i++) {
+ mem_len = ms->numa_state->nodes[i].node_mem;
rc = fdt_add_memory_node(fdt, acells, mem_base,
scells, mem_len, i);
if (rc < 0) {
@@ -626,9 +627,9 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
qemu_fdt_add_subnode(fdt, "/chosen");
}
- if (binfo->kernel_cmdline && *binfo->kernel_cmdline) {
+ if (ms->kernel_cmdline && *ms->kernel_cmdline) {
rc = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
- binfo->kernel_cmdline);
+ ms->kernel_cmdline);
if (rc < 0) {
fprintf(stderr, "couldn't set /chosen/bootargs\n");
goto fail;
@@ -1260,7 +1261,7 @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info)
*/
}
-void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
+void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
{
CPUState *cs;
AddressSpace *as = arm_boot_address_space(cpu, info);
@@ -1281,7 +1282,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
* doesn't support secure.
*/
assert(!(info->secure_board_setup && kvm_enabled()));
-
+ info->kernel_filename = ms->kernel_filename;
+ info->kernel_cmdline = ms->kernel_cmdline;
+ info->initrd_filename = ms->initrd_filename;
info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
info->dtb_limit = 0;
@@ -1293,7 +1296,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
}
if (!info->skip_dtb_autoload && have_dtb(info)) {
- if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as) < 0) {
+ if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) {
exit(1);
}
}
diff --git a/hw/arm/collie.c b/hw/arm/collie.c
index 219643c633..b1288ccea8 100644
--- a/hw/arm/collie.c
+++ b/hw/arm/collie.c
@@ -25,9 +25,6 @@ static struct arm_boot_info collie_binfo = {
static void collie_init(MachineState *machine)
{
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
StrongARMState *s;
DriveInfo *dinfo;
MemoryRegion *sysmem = get_system_memory();
@@ -46,11 +43,8 @@ static void collie_init(MachineState *machine)
sysbus_create_simple("scoop", 0x40800000, NULL);
- collie_binfo.kernel_filename = kernel_filename;
- collie_binfo.kernel_cmdline = kernel_cmdline;
- collie_binfo.initrd_filename = initrd_filename;
collie_binfo.board_id = 0x208;
- arm_load_kernel(s->cpu, &collie_binfo);
+ arm_load_kernel(s->cpu, machine, &collie_binfo);
}
static void collie_machine_init(MachineClass *mc)
diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c
index 38e0ca0f53..6dc2f1d6b6 100644
--- a/hw/arm/cubieboard.c
+++ b/hw/arm/cubieboard.c
@@ -73,15 +73,13 @@ static void cubieboard_init(MachineState *machine)
/* TODO create and connect IDE devices for ide_drive_get() */
cubieboard_binfo.ram_size = machine->ram_size;
- cubieboard_binfo.kernel_filename = machine->kernel_filename;
- cubieboard_binfo.kernel_cmdline = machine->kernel_cmdline;
- cubieboard_binfo.initrd_filename = machine->initrd_filename;
- arm_load_kernel(&s->a10->cpu, &cubieboard_binfo);
+ arm_load_kernel(&s->a10->cpu, machine, &cubieboard_binfo);
}
static void cubieboard_machine_init(MachineClass *mc)
{
- mc->desc = "cubietech cubieboard";
+ mc->desc = "cubietech cubieboard (Cortex-A9)";
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
mc->init = cubieboard_init;
mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1;
diff --git a/hw/arm/digic.c b/hw/arm/digic.c
index 4f52465875..22434a65a2 100644
--- a/hw/arm/digic.c
+++ b/hw/arm/digic.c
@@ -37,7 +37,8 @@ static void digic_init(Object *obj)
int i;
object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
- "arm946-" TYPE_ARM_CPU, &error_abort, NULL);
+ ARM_CPU_TYPE_NAME("arm946"),
+ &error_abort, NULL);
for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
#define DIGIC_TIMER_NAME_MLEN 11
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
index f69358a5ba..09da52876d 100644
--- a/hw/arm/exynos4_boards.c
+++ b/hw/arm/exynos4_boards.c
@@ -122,17 +122,14 @@ exynos4_boards_init_common(MachineState *machine,
exynos4_board_binfo.board_id = exynos4_board_id[board_type];
exynos4_board_binfo.smp_bootreg_addr =
exynos4_board_smp_bootreg_addr[board_type];
- exynos4_board_binfo.kernel_filename = machine->kernel_filename;
- exynos4_board_binfo.initrd_filename = machine->initrd_filename;
- exynos4_board_binfo.kernel_cmdline = machine->kernel_cmdline;
exynos4_board_binfo.gic_cpu_if_addr =
EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
exynos4_boards_init_ram(s, get_system_memory(),
exynos4_board_ram_size[board_type]);
- object_initialize(&s->soc, sizeof(s->soc), TYPE_EXYNOS4210_SOC);
- qdev_set_parent_bus(DEVICE(&s->soc), sysbus_get_default());
+ sysbus_init_child_obj(OBJECT(machine), "soc",
+ &s->soc, sizeof(s->soc), TYPE_EXYNOS4210_SOC);
object_property_set_bool(OBJECT(&s->soc), true, "realized",
&error_fatal);
@@ -143,7 +140,7 @@ static void nuri_init(MachineState *machine)
{
exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI);
- arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &exynos4_board_binfo);
}
static void smdkc210_init(MachineState *machine)
@@ -153,7 +150,7 @@ static void smdkc210_init(MachineState *machine)
lan9215_init(SMDK_LAN9118_BASE_ADDR,
qemu_irq_invert(s->soc.irq_table[exynos4210_get_irq(37, 1)]));
- arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &exynos4_board_binfo);
}
static void nuri_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 532d088298..3cb5a8fdfd 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -36,7 +36,9 @@ static void fsl_imx25_init(Object *obj)
FslIMX25State *s = FSL_IMX25(obj);
int i;
- object_initialize(&s->cpu, sizeof(s->cpu), "arm926-" TYPE_ARM_CPU);
+ object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
+ ARM_CPU_TYPE_NAME("arm926"),
+ &error_abort, NULL);
sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic),
TYPE_IMX_AVIC);
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index 1a37a7b997..55e90d104b 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -33,7 +33,9 @@ static void fsl_imx31_init(Object *obj)
FslIMX31State *s = FSL_IMX31(obj);
int i;
- object_initialize(&s->cpu, sizeof(s->cpu), "arm1136-" TYPE_ARM_CPU);
+ object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
+ ARM_CPU_TYPE_NAME("arm1136"),
+ &error_abort, NULL);
sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic),
TYPE_IMX_AVIC);
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index 8c397ef04b..552145b24e 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -43,7 +43,8 @@ static void fsl_imx6_init(Object *obj)
for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX6_NUM_CPUS); i++) {
snprintf(name, NAME_SIZE, "cpu%d", i);
object_initialize_child(obj, name, &s->cpu[i], sizeof(s->cpu[i]),
- "cortex-a9-" TYPE_ARM_CPU, &error_abort, NULL);
+ ARM_CPU_TYPE_NAME("cortex-a9"),
+ &error_abort, NULL);
}
sysbus_init_child_obj(obj, "a9mpcore", &s->a9mpcore, sizeof(s->a9mpcore),
diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c
index b074177a71..c405b68d1d 100644
--- a/hw/arm/fsl-imx6ul.c
+++ b/hw/arm/fsl-imx6ul.c
@@ -34,7 +34,7 @@ static void fsl_imx6ul_init(Object *obj)
int i;
object_initialize_child(obj, "cpu0", &s->cpu, sizeof(s->cpu),
- "cortex-a7-" TYPE_ARM_CPU, &error_abort, NULL);
+ ARM_CPU_TYPE_NAME("cortex-a7"), &error_abort, NULL);
/*
* A7MPCORE
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index 362e5ba044..f1724d6929 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -236,9 +236,6 @@ enum cxmachines {
static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
{
ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
DeviceState *dev = NULL;
SysBusDevice *busdev;
qemu_irq pic[128];
@@ -390,9 +387,6 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
/* TODO create and connect IDE devices for ide_drive_get() */
highbank_binfo.ram_size = ram_size;
- highbank_binfo.kernel_filename = kernel_filename;
- highbank_binfo.kernel_cmdline = kernel_cmdline;
- highbank_binfo.initrd_filename = initrd_filename;
/* highbank requires a dtb in order to boot, and the dtb will override
* the board ID. The following value is ignored, so set it to -1 to be
* clear that the value is meaningless.
@@ -412,7 +406,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
"may not boot.");
}
- arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &highbank_binfo);
}
static void highbank_init(MachineState *machine)
diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c
index 5d673e47bc..c76fc2bd94 100644
--- a/hw/arm/imx25_pdk.c
+++ b/hw/arm/imx25_pdk.c
@@ -116,9 +116,6 @@ static void imx25_pdk_init(MachineState *machine)
}
imx25_pdk_binfo.ram_size = machine->ram_size;
- imx25_pdk_binfo.kernel_filename = machine->kernel_filename;
- imx25_pdk_binfo.kernel_cmdline = machine->kernel_cmdline;
- imx25_pdk_binfo.initrd_filename = machine->initrd_filename;
imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR;
imx25_pdk_binfo.board_id = 1771,
imx25_pdk_binfo.nb_cpus = 1;
@@ -129,7 +126,7 @@ static void imx25_pdk_init(MachineState *machine)
* fail.
*/
if (!qtest_enabled()) {
- arm_load_kernel(&s->soc.cpu, &imx25_pdk_binfo);
+ arm_load_kernel(&s->soc.cpu, machine, &imx25_pdk_binfo);
}
}
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index 200568b42a..524970840d 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -582,9 +582,6 @@ static struct arm_boot_info integrator_binfo = {
static void integratorcp_init(MachineState *machine)
{
ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
Object *cpuobj;
ARMCPU *cpu;
MemoryRegion *address_space_mem = get_system_memory();
@@ -654,10 +651,7 @@ static void integratorcp_init(MachineState *machine)
sysbus_create_simple("pl110", 0xc0000000, pic[22]);
integrator_binfo.ram_size = ram_size;
- integrator_binfo.kernel_filename = kernel_filename;
- integrator_binfo.kernel_cmdline = kernel_cmdline;
- integrator_binfo.initrd_filename = initrd_filename;
- arm_load_kernel(cpu, &integrator_binfo);
+ arm_load_kernel(cpu, machine, &integrator_binfo);
}
static void integratorcp_machine_init(MachineClass *mc)
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
index 2f052e1f8c..1d5ef289d5 100644
--- a/hw/arm/kzm.c
+++ b/hw/arm/kzm.c
@@ -127,13 +127,10 @@ static void kzm_init(MachineState *machine)
}
kzm_binfo.ram_size = machine->ram_size;
- kzm_binfo.kernel_filename = machine->kernel_filename;
- kzm_binfo.kernel_cmdline = machine->kernel_cmdline;
- kzm_binfo.initrd_filename = machine->initrd_filename;
kzm_binfo.nb_cpus = 1;
if (!qtest_enabled()) {
- arm_load_kernel(&s->soc.cpu, &kzm_binfo);
+ arm_load_kernel(&s->soc.cpu, machine, &kzm_binfo);
}
}
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
index 1bad1aea76..b01ce3ce08 100644
--- a/hw/arm/mainstone.c
+++ b/hw/arm/mainstone.c
@@ -176,11 +176,8 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
smc91c111_init(&nd_table[0], MST_ETH_PHYS,
qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
- mainstone_binfo.kernel_filename = machine->kernel_filename;
- mainstone_binfo.kernel_cmdline = machine->kernel_cmdline;
- mainstone_binfo.initrd_filename = machine->initrd_filename;
mainstone_binfo.board_id = arm_id;
- arm_load_kernel(mpu->cpu, &mainstone_binfo);
+ arm_load_kernel(mpu->cpu, machine, &mainstone_binfo);
}
static void mainstone_init(MachineState *machine)
diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c
index 0276875f02..e90b393a44 100644
--- a/hw/arm/mcimx6ul-evk.c
+++ b/hw/arm/mcimx6ul-evk.c
@@ -40,9 +40,6 @@ static void mcimx6ul_evk_init(MachineState *machine)
.loader_start = FSL_IMX6UL_MMDC_ADDR,
.board_id = -1,
.ram_size = machine->ram_size,
- .kernel_filename = machine->kernel_filename,
- .kernel_cmdline = machine->kernel_cmdline,
- .initrd_filename = machine->initrd_filename,
.nb_cpus = machine->smp.cpus,
};
@@ -72,7 +69,7 @@ static void mcimx6ul_evk_init(MachineState *machine)
}
if (!qtest_enabled()) {
- arm_load_kernel(&s->soc.cpu, &boot_info);
+ arm_load_kernel(&s->soc.cpu, machine, &boot_info);
}
}
diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c
index 97b8bb788a..0d1f62d30a 100644
--- a/hw/arm/mcimx7d-sabre.c
+++ b/hw/arm/mcimx7d-sabre.c
@@ -30,7 +30,6 @@ static void mcimx7d_sabre_init(MachineState *machine)
{
static struct arm_boot_info boot_info;
MCIMX7Sabre *s = g_new0(MCIMX7Sabre, 1);
- Object *soc;
int i;
if (machine->ram_size > FSL_IMX7_MMDC_SIZE) {
@@ -43,16 +42,13 @@ static void mcimx7d_sabre_init(MachineState *machine)
.loader_start = FSL_IMX7_MMDC_ADDR,
.board_id = -1,
.ram_size = machine->ram_size,
- .kernel_filename = machine->kernel_filename,
- .kernel_cmdline = machine->kernel_cmdline,
- .initrd_filename = machine->initrd_filename,
.nb_cpus = machine->smp.cpus,
};
- object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX7);
- soc = OBJECT(&s->soc);
- object_property_add_child(OBJECT(machine), "soc", soc, &error_fatal);
- object_property_set_bool(soc, true, "realized", &error_fatal);
+ object_initialize_child(OBJECT(machine), "soc",
+ &s->soc, sizeof(s->soc),
+ TYPE_FSL_IMX7, &error_fatal, NULL);
+ object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal);
memory_region_allocate_system_memory(&s->ram, NULL, "mcimx7d-sabre.ram",
machine->ram_size);
@@ -75,7 +71,7 @@ static void mcimx7d_sabre_init(MachineState *machine)
}
if (!qtest_enabled()) {
- arm_load_kernel(&s->soc.cpu[0], &boot_info);
+ arm_load_kernel(&s->soc.cpu[0], machine, &boot_info);
}
}
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index d85dc2c4bd..6b24aaacde 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -427,10 +427,10 @@ static void mps2tz_common_init(MachineState *machine)
/* The sec_resp_cfg output from the IoTKit must be split into multiple
* lines, one for each of the PPCs we create here, plus one per MSC.
*/
- object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
- TYPE_SPLIT_IRQ);
- object_property_add_child(OBJECT(machine), "sec-resp-splitter",
- OBJECT(&mms->sec_resp_splitter), &error_abort);
+ object_initialize_child(OBJECT(machine), "sec-resp-splitter",
+ &mms->sec_resp_splitter,
+ sizeof(mms->sec_resp_splitter),
+ TYPE_SPLIT_IRQ, &error_abort, NULL);
object_property_set_int(OBJECT(&mms->sec_resp_splitter),
ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc),
"num-lines", &error_fatal);
@@ -465,10 +465,9 @@ static void mps2tz_common_init(MachineState *machine)
* Tx, Rx and "combined" IRQs are sent to the NVIC separately.
* Create the OR gate for this.
*/
- object_initialize(&mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate),
- TYPE_OR_IRQ);
- object_property_add_child(OBJECT(mms), "uart-irq-orgate",
- OBJECT(&mms->uart_irq_orgate), &error_abort);
+ object_initialize_child(OBJECT(mms), "uart-irq-orgate",
+ &mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate),
+ TYPE_OR_IRQ, &error_abort, NULL);
object_property_set_int(OBJECT(&mms->uart_irq_orgate), 10, "num-lines",
&error_fatal);
object_property_set_bool(OBJECT(&mms->uart_irq_orgate), true,
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
index ddd8842732..68db4b5b38 100644
--- a/hw/arm/musca.c
+++ b/hw/arm/musca.c
@@ -424,10 +424,11 @@ static void musca_init(MachineState *machine)
* The sec_resp_cfg output from the SSE-200 must be split into multiple
* lines, one for each of the PPCs we create here.
*/
- object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
- TYPE_SPLIT_IRQ);
- object_property_add_child(OBJECT(machine), "sec-resp-splitter",
- OBJECT(&mms->sec_resp_splitter), &error_fatal);
+ object_initialize_child(OBJECT(machine), "sec-resp-splitter",
+ &mms->sec_resp_splitter,
+ sizeof(mms->sec_resp_splitter),
+ TYPE_SPLIT_IRQ, &error_fatal, NULL);
+
object_property_set_int(OBJECT(&mms->sec_resp_splitter),
ARRAY_SIZE(mms->ppc), "num-lines", &error_fatal);
object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 8ae4751d75..246cbb1336 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1573,9 +1573,6 @@ static struct arm_boot_info musicpal_binfo = {
static void musicpal_init(MachineState *machine)
{
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
ARMCPU *cpu;
qemu_irq pic[32];
DeviceState *dev;
@@ -1704,10 +1701,7 @@ static void musicpal_init(MachineState *machine)
sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
- musicpal_binfo.kernel_filename = kernel_filename;
- musicpal_binfo.kernel_cmdline = kernel_cmdline;
- musicpal_binfo.initrd_filename = initrd_filename;
- arm_load_kernel(cpu, &musicpal_binfo);
+ arm_load_kernel(cpu, machine, &musicpal_binfo);
}
static void musicpal_machine_init(MachineClass *mc)
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index a6c4085337..a36971d39a 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -1361,10 +1361,7 @@ static void n8x0_init(MachineState *machine,
if (machine->kernel_filename) {
/* Or at the linux loader. */
- binfo->kernel_filename = machine->kernel_filename;
- binfo->kernel_cmdline = machine->kernel_cmdline;
- binfo->initrd_filename = machine->initrd_filename;
- arm_load_kernel(s->mpu->cpu, binfo);
+ arm_load_kernel(s->mpu->cpu, machine, binfo);
qemu_register_reset(n8x0_boot_init, s);
}
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
index 75a05c36b0..c071197be7 100644
--- a/hw/arm/omap_sx1.c
+++ b/hw/arm/omap_sx1.c
@@ -195,10 +195,7 @@ static void sx1_init(MachineState *machine, const int version)
}
/* Load the kernel. */
- sx1_binfo.kernel_filename = machine->kernel_filename;
- sx1_binfo.kernel_cmdline = machine->kernel_cmdline;
- sx1_binfo.initrd_filename = machine->initrd_filename;
- arm_load_kernel(mpu->cpu, &sx1_binfo);
+ arm_load_kernel(mpu->cpu, machine, &sx1_binfo);
/* TODO: fix next line */
//~ qemu_console_resize(ds, 640, 480);
diff --git a/hw/arm/palm.c b/hw/arm/palm.c
index bea47b917d..02a3a82b9b 100644
--- a/hw/arm/palm.c
+++ b/hw/arm/palm.c
@@ -187,9 +187,6 @@ static struct arm_boot_info palmte_binfo = {
static void palmte_init(MachineState *machine)
{
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
MemoryRegion *address_space_mem = get_system_memory();
struct omap_mpu_state_s *mpu;
int flash_size = 0x00800000;
@@ -249,16 +246,13 @@ static void palmte_init(MachineState *machine)
}
}
- if (!rom_loaded && !kernel_filename && !qtest_enabled()) {
+ if (!rom_loaded && !machine->kernel_filename && !qtest_enabled()) {
fprintf(stderr, "Kernel or ROM image must be specified\n");
exit(1);
}
/* Load the kernel. */
- palmte_binfo.kernel_filename = kernel_filename;
- palmte_binfo.kernel_cmdline = kernel_cmdline;
- palmte_binfo.initrd_filename = initrd_filename;
- arm_load_kernel(mpu->cpu, &palmte_binfo);
+ arm_load_kernel(mpu->cpu, machine, &palmte_binfo);
}
static void palmte_machine_init(MachineClass *mc)
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index 5b2620acb4..74c062d05e 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -157,13 +157,9 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
binfo.entry = firmware_addr;
binfo.firmware_loaded = true;
- } else {
- binfo.kernel_filename = machine->kernel_filename;
- binfo.kernel_cmdline = machine->kernel_cmdline;
- binfo.initrd_filename = machine->initrd_filename;
}
- arm_load_kernel(ARM_CPU(first_cpu), &binfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &binfo);
}
static void raspi_init(MachineState *machine, int version)
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index b108a9ab26..8fcdf75a2b 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -351,13 +351,10 @@ static void realview_init(MachineState *machine,
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
realview_binfo.ram_size = ram_size;
- realview_binfo.kernel_filename = machine->kernel_filename;
- realview_binfo.kernel_cmdline = machine->kernel_cmdline;
- realview_binfo.initrd_filename = machine->initrd_filename;
realview_binfo.nb_cpus = smp_cpus;
realview_binfo.board_id = realview_board_id[board_type];
realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
- arm_load_kernel(ARM_CPU(first_cpu), &realview_binfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &realview_binfo);
}
static void realview_eb_init(MachineState *machine)
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
index a6185c169e..96cc455c5c 100644
--- a/hw/arm/sabrelite.c
+++ b/hw/arm/sabrelite.c
@@ -103,16 +103,13 @@ static void sabrelite_init(MachineState *machine)
}
sabrelite_binfo.ram_size = machine->ram_size;
- sabrelite_binfo.kernel_filename = machine->kernel_filename;
- sabrelite_binfo.kernel_cmdline = machine->kernel_cmdline;
- sabrelite_binfo.initrd_filename = machine->initrd_filename;
sabrelite_binfo.nb_cpus = machine->smp.cpus;
sabrelite_binfo.secure_boot = true;
sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary;
sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary;
if (!qtest_enabled()) {
- arm_load_kernel(&s->soc.cpu[0], &sabrelite_binfo);
+ arm_load_kernel(&s->soc.cpu[0], machine, &sabrelite_binfo);
}
}
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index e98e9a5170..27046cc284 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -146,6 +146,7 @@ static void create_fdt(SBSAMachineState *sms)
{
void *fdt = create_device_tree(&sms->fdt_size);
const MachineState *ms = MACHINE(sms);
+ int nb_numa_nodes = ms->numa_state->num_nodes;
int cpu;
if (!fdt) {
@@ -159,7 +160,7 @@ static void create_fdt(SBSAMachineState *sms)
qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
- if (have_numa_distance) {
+ if (ms->numa_state->have_numa_distance) {
int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t);
uint32_t *matrix = g_malloc0(size);
int idx, i, j;
@@ -169,7 +170,8 @@ static void create_fdt(SBSAMachineState *sms)
idx = (i * nb_numa_nodes + j) * 3;
matrix[idx + 0] = cpu_to_be32(i);
matrix[idx + 1] = cpu_to_be32(j);
- matrix[idx + 2] = cpu_to_be32(numa_info[i].distance[j]);
+ matrix[idx + 2] =
+ cpu_to_be32(ms->numa_state->nodes[i].distance[j]);
}
}
@@ -711,13 +713,12 @@ static void sbsa_ref_init(MachineState *machine)
create_pcie(sms, pic);
sms->bootinfo.ram_size = machine->ram_size;
- sms->bootinfo.kernel_filename = machine->kernel_filename;
sms->bootinfo.nb_cpus = smp_cpus;
sms->bootinfo.board_id = -1;
sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base;
sms->bootinfo.get_dtb = sbsa_ref_dtb;
sms->bootinfo.firmware_loaded = firmware_loaded;
- arm_load_kernel(ARM_CPU(first_cpu), &sms->bootinfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &sms->bootinfo);
}
static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
@@ -763,7 +764,7 @@ sbsa_ref_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
static int64_t
sbsa_ref_get_default_cpu_node_id(const MachineState *ms, int idx)
{
- return idx % nb_numa_nodes;
+ return idx % ms->numa_state->num_nodes;
}
static void sbsa_ref_instance_init(Object *obj)
@@ -790,6 +791,7 @@ static void sbsa_ref_class_init(ObjectClass *oc, void *data)
mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids;
mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props;
mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id;
+ mc->numa_mem_supported = true;
}
static const TypeInfo sbsa_ref_info = {
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index b160289cd1..d190181ef1 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -381,6 +381,7 @@ typedef struct SMMUEventInfo {
uint32_t sid;
bool recorded;
bool record_trans_faults;
+ bool inval_ste_allowed;
union {
struct {
uint32_t ssid;
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 2eaf07fb5f..db051dcac8 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -320,6 +320,9 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
uint32_t config;
if (!STE_VALID(ste)) {
+ if (!event->inval_ste_allowed) {
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid STE\n");
+ }
goto bad_ste;
}
@@ -406,8 +409,10 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
if (!span) {
/* l2ptr is not valid */
- qemu_log_mask(LOG_GUEST_ERROR,
- "invalid sid=%d (L1STD span=0)\n", sid);
+ if (!event->inval_ste_allowed) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "invalid sid=%d (L1STD span=0)\n", sid);
+ }
event->type = SMMU_EVT_C_BAD_STREAMID;
return -EINVAL;
}
@@ -602,7 +607,9 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
SMMUv3State *s = sdev->smmu;
uint32_t sid = smmu_get_sid(sdev);
- SMMUEventInfo event = {.type = SMMU_EVT_NONE, .sid = sid};
+ SMMUEventInfo event = {.type = SMMU_EVT_NONE,
+ .sid = sid,
+ .inval_ste_allowed = false};
SMMUPTWEventInfo ptw_info = {};
SMMUTranslationStatus status;
SMMUState *bs = ARM_SMMU(s);
@@ -795,16 +802,13 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
dma_addr_t iova)
{
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
- SMMUEventInfo event = {};
+ SMMUEventInfo event = {.inval_ste_allowed = true};
SMMUTransTableInfo *tt;
SMMUTransCfg *cfg;
IOMMUTLBEntry entry;
cfg = smmuv3_get_config(sdev, &event);
if (!cfg) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s error decoding the configuration for iommu mr=%s\n",
- __func__, mr->parent_obj.name);
return;
}
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index 59348123b5..25bd0f5d9d 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -954,11 +954,8 @@ static void spitz_common_init(MachineState *machine,
/* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
spitz_microdrive_attach(mpu, 0);
- spitz_binfo.kernel_filename = machine->kernel_filename;
- spitz_binfo.kernel_cmdline = machine->kernel_cmdline;
- spitz_binfo.initrd_filename = machine->initrd_filename;
spitz_binfo.board_id = arm_id;
- arm_load_kernel(mpu->cpu, &spitz_binfo);
+ arm_load_kernel(mpu->cpu, machine, &spitz_binfo);
sl_bootparam_write(SL_PXA_PARAM_BASE);
}
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
index e9627e356e..4d95a1f3e2 100644
--- a/hw/arm/tosa.c
+++ b/hw/arm/tosa.c
@@ -218,9 +218,6 @@ static struct arm_boot_info tosa_binfo = {
static void tosa_init(MachineState *machine)
{
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *rom = g_new(MemoryRegion, 1);
PXA2xxState *mpu;
@@ -245,11 +242,8 @@ static void tosa_init(MachineState *machine)
tosa_tg_init(mpu);
- tosa_binfo.kernel_filename = kernel_filename;
- tosa_binfo.kernel_cmdline = kernel_cmdline;
- tosa_binfo.initrd_filename = initrd_filename;
tosa_binfo.board_id = 0x208;
- arm_load_kernel(mpu->cpu, &tosa_binfo);
+ arm_load_kernel(mpu->cpu, machine, &tosa_binfo);
sl_bootparam_write(SL_PXA_PARAM_BASE);
}
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index e25561705f..e86af01537 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -375,11 +375,8 @@ static void versatile_init(MachineState *machine, int board_id)
}
versatile_binfo.ram_size = machine->ram_size;
- versatile_binfo.kernel_filename = machine->kernel_filename;
- versatile_binfo.kernel_cmdline = machine->kernel_cmdline;
- versatile_binfo.initrd_filename = machine->initrd_filename;
versatile_binfo.board_id = board_id;
- arm_load_kernel(cpu, &versatile_binfo);
+ arm_load_kernel(cpu, machine, &versatile_binfo);
}
static void vpb_init(MachineState *machine)
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 5d932c27c0..4673a88a8d 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -707,9 +707,6 @@ static void vexpress_common_init(MachineState *machine)
}
daughterboard->bootinfo.ram_size = machine->ram_size;
- daughterboard->bootinfo.kernel_filename = machine->kernel_filename;
- daughterboard->bootinfo.kernel_cmdline = machine->kernel_cmdline;
- daughterboard->bootinfo.initrd_filename = machine->initrd_filename;
daughterboard->bootinfo.nb_cpus = machine->smp.cpus;
daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID;
daughterboard->bootinfo.loader_start = daughterboard->loader_start;
@@ -719,7 +716,7 @@ static void vexpress_common_init(MachineState *machine)
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
/* When booting Linux we should be in secure state if the CPU has one. */
daughterboard->bootinfo.secure_boot = vms->secure;
- arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &daughterboard->bootinfo);
}
static bool vexpress_get_secure(Object *obj, Error **errp)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index a8b2d97fe9..6cdf156cf5 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -517,7 +517,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
int i, srat_start;
uint64_t mem_base;
MachineClass *mc = MACHINE_GET_CLASS(vms);
- const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(MACHINE(vms));
+ MachineState *ms = MACHINE(vms);
+ const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms);
srat_start = table_data->len;
srat = acpi_data_push(table_data, sizeof(*srat));
@@ -533,12 +534,13 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
mem_base = vms->memmap[VIRT_MEM].base;
- for (i = 0; i < nb_numa_nodes; ++i) {
- if (numa_info[i].node_mem > 0) {
+ for (i = 0; i < ms->numa_state->num_nodes; ++i) {
+ if (ms->numa_state->nodes[i].node_mem > 0) {
numamem = acpi_data_push(table_data, sizeof(*numamem));
- build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i,
+ build_srat_memory(numamem, mem_base,
+ ms->numa_state->nodes[i].node_mem, i,
MEM_AFFINITY_ENABLED);
- mem_base += numa_info[i].node_mem;
+ mem_base += ms->numa_state->nodes[i].node_mem;
}
}
@@ -759,6 +761,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
GArray *table_offsets;
unsigned dsdt, xsdt;
GArray *tables_blob = tables->table_data;
+ MachineState *ms = MACHINE(vms);
table_offsets = g_array_new(false, true /* clear */,
sizeof(uint32_t));
@@ -793,12 +796,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
build_spcr(tables_blob, tables->linker, vms);
- if (nb_numa_nodes > 0) {
+ if (ms->numa_state->num_nodes > 0) {
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, vms);
- if (have_numa_distance) {
+ if (ms->numa_state->have_numa_distance) {
acpi_add_table(table_offsets, tables_blob);
- build_slit(tables_blob, tables->linker);
+ build_slit(tables_blob, tables->linker, ms);
}
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0d1629ccb3..d74538b021 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -203,6 +203,8 @@ static bool cpu_type_valid(const char *cpu)
static void create_fdt(VirtMachineState *vms)
{
+ MachineState *ms = MACHINE(vms);
+ int nb_numa_nodes = ms->numa_state->num_nodes;
void *fdt = create_device_tree(&vms->fdt_size);
if (!fdt) {
@@ -234,7 +236,7 @@ static void create_fdt(VirtMachineState *vms)
"clk24mhz");
qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vms->clock_phandle);
- if (have_numa_distance) {
+ if (nb_numa_nodes > 0 && ms->numa_state->have_numa_distance) {
int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t);
uint32_t *matrix = g_malloc0(size);
int idx, i, j;
@@ -244,7 +246,8 @@ static void create_fdt(VirtMachineState *vms)
idx = (i * nb_numa_nodes + j) * 3;
matrix[idx + 0] = cpu_to_be32(i);
matrix[idx + 1] = cpu_to_be32(j);
- matrix[idx + 2] = cpu_to_be32(numa_info[i].distance[j]);
+ matrix[idx + 2] =
+ cpu_to_be32(ms->numa_state->nodes[i].distance[j]);
}
}
@@ -1368,6 +1371,7 @@ void virt_machine_done(Notifier *notifier, void *data)
{
VirtMachineState *vms = container_of(notifier, VirtMachineState,
machine_done);
+ MachineState *ms = MACHINE(vms);
ARMCPU *cpu = ARM_CPU(first_cpu);
struct arm_boot_info *info = &vms->bootinfo;
AddressSpace *as = arm_boot_address_space(cpu, info);
@@ -1385,7 +1389,7 @@ void virt_machine_done(Notifier *notifier, void *data)
vms->memmap[VIRT_PLATFORM_BUS].size,
vms->irqmap[VIRT_PLATFORM_BUS]);
}
- if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as) < 0) {
+ if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) {
exit(1);
}
@@ -1711,16 +1715,13 @@ static void machvirt_init(MachineState *machine)
create_platform_bus(vms, pic);
vms->bootinfo.ram_size = machine->ram_size;
- vms->bootinfo.kernel_filename = machine->kernel_filename;
- vms->bootinfo.kernel_cmdline = machine->kernel_cmdline;
- vms->bootinfo.initrd_filename = machine->initrd_filename;
vms->bootinfo.nb_cpus = smp_cpus;
vms->bootinfo.board_id = -1;
vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base;
vms->bootinfo.get_dtb = machvirt_dtb;
vms->bootinfo.skip_dtb_autoload = true;
vms->bootinfo.firmware_loaded = firmware_loaded;
- arm_load_kernel(ARM_CPU(first_cpu), &vms->bootinfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
vms->machine_done.notify = virt_machine_done;
qemu_add_machine_init_done_notifier(&vms->machine_done);
@@ -1848,7 +1849,7 @@ virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx)
{
- return idx % nb_numa_nodes;
+ return idx % ms->numa_state->num_nodes;
}
static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 89da34808b..c14774e542 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -158,9 +158,6 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
static void zynq_init(MachineState *machine)
{
ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
ARMCPU *cpu;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
@@ -303,16 +300,13 @@ static void zynq_init(MachineState *machine)
sysbus_mmio_map(busdev, 0, 0xF8007000);
zynq_binfo.ram_size = ram_size;
- zynq_binfo.kernel_filename = kernel_filename;
- zynq_binfo.kernel_cmdline = kernel_cmdline;
- zynq_binfo.initrd_filename = initrd_filename;
zynq_binfo.nb_cpus = 1;
zynq_binfo.board_id = 0xd32;
zynq_binfo.loader_start = 0;
zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR;
zynq_binfo.write_board_setup = zynq_write_board_setup;
- arm_load_kernel(ARM_CPU(first_cpu), &zynq_binfo);
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &zynq_binfo);
}
static void zynq_machine_init(MachineClass *mc)
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index f95fde2309..462493c467 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -441,14 +441,11 @@ static void versal_virt_init(MachineState *machine)
0, &s->soc.fpd.apu.mr, 0);
s->binfo.ram_size = machine->ram_size;
- s->binfo.kernel_filename = machine->kernel_filename;
- s->binfo.kernel_cmdline = machine->kernel_cmdline;
- s->binfo.initrd_filename = machine->initrd_filename;
s->binfo.loader_start = 0x0;
s->binfo.get_dtb = versal_virt_get_dtb;
s->binfo.modify_dtb = versal_virt_modify_dtb;
if (machine->kernel_filename) {
- arm_load_kernel(s->soc.fpd.apu.cpu[0], &s->binfo);
+ arm_load_kernel(s->soc.fpd.apu.cpu[0], machine, &s->binfo);
} else {
AddressSpace *as = arm_boot_address_space(s->soc.fpd.apu.cpu[0],
&s->binfo);
@@ -457,7 +454,7 @@ static void versal_virt_init(MachineState *machine)
s->binfo.loader_start = 0x1000;
s->binfo.dtb_limit = 0x1000000;
if (arm_load_dtb(s->binfo.loader_start,
- &s->binfo, s->binfo.dtb_limit, as) < 0) {
+ &s->binfo, s->binfo.dtb_limit, as, machine) < 0) {
exit(EXIT_FAILURE);
}
}
diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
index 044d3394c0..53cfe7c1f1 100644
--- a/hw/arm/xlnx-zcu102.c
+++ b/hw/arm/xlnx-zcu102.c
@@ -171,11 +171,8 @@ static void xlnx_zcu102_init(MachineState *machine)
/* TODO create and connect IDE devices for ide_drive_get() */
xlnx_zcu102_binfo.ram_size = ram_size;
- xlnx_zcu102_binfo.kernel_filename = machine->kernel_filename;
- xlnx_zcu102_binfo.kernel_cmdline = machine->kernel_cmdline;
- xlnx_zcu102_binfo.initrd_filename = machine->initrd_filename;
xlnx_zcu102_binfo.loader_start = 0;
- arm_load_kernel(s->soc.boot_cpu_ptr, &xlnx_zcu102_binfo);
+ arm_load_kernel(s->soc.boot_cpu_ptr, machine, &xlnx_zcu102_binfo);
}
static void xlnx_zcu102_machine_instance_init(Object *obj)
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 0f587e63d3..fb03c60ebb 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -196,8 +196,8 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
object_initialize_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]",
&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]),
- "cortex-r5f-" TYPE_ARM_CPU, &error_abort,
- NULL);
+ ARM_CPU_TYPE_NAME("cortex-r5f"),
+ &error_abort, NULL);
name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
if (strcmp(name, boot_cpu)) {
@@ -237,8 +237,8 @@ static void xlnx_zynqmp_init(Object *obj)
for (i = 0; i < num_apus; i++) {
object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]",
&s->apu_cpu[i], sizeof(s->apu_cpu[i]),
- "cortex-a53-" TYPE_ARM_CPU, &error_abort,
- NULL);
+ ARM_CPU_TYPE_NAME("cortex-a53"),
+ &error_abort, NULL);
}
sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index 3923b87e4c..34794fe3ae 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -296,9 +296,6 @@ static const TypeInfo aer915_info = {
static void z2_init(MachineState *machine)
{
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
MemoryRegion *address_space_mem = get_system_memory();
uint32_t sector_len = 0x10000;
PXA2xxState *mpu;
@@ -352,11 +349,8 @@ static void z2_init(MachineState *machine)
qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS,
qemu_allocate_irq(z2_lcd_cs, z2_lcd, 0));
- z2_binfo.kernel_filename = kernel_filename;
- z2_binfo.kernel_cmdline = kernel_cmdline;
- z2_binfo.initrd_filename = initrd_filename;
z2_binfo.board_id = 0x6dd;
- arm_load_kernel(mpu->cpu, &z2_binfo);
+ arm_load_kernel(mpu->cpu, machine, &z2_binfo);
}
static void z2_machine_init(MachineClass *mc)
diff --git a/hw/char/escc.c b/hw/char/escc.c
index e185522e27..8f7bf322cb 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -45,14 +45,21 @@
* mouse and keyboard ports don't implement all functions and they are
* only asynchronous. There is no DMA.
*
- * Z85C30 is also used on PowerMacs. There are some small differences
- * between Sparc version (sunzilog) and PowerMac (pmac):
+ * Z85C30 is also used on PowerMacs and m68k Macs.
+ *
+ * There are some small differences between Sparc version (sunzilog)
+ * and PowerMac (pmac):
* Offset between control and data registers
* There is some kind of lockup bug, but we can ignore it
* CTS is inverted
* DMA on pmac using DBDMA chip
* pmac can do IRDA and faster rates, sunzilog can only do 38400
* pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
+ *
+ * Linux driver for m68k Macs is the same as for PowerMac (pmac_zilog),
+ * but registers are grouped by type and not by channel:
+ * channel is selected by bit 0 of the address (instead of bit 1)
+ * and register is selected by bit 1 of the address (instead of bit 0).
*/
/*
@@ -172,6 +179,16 @@ static void handle_kbd_command(ESCCChannelState *s, int val);
static int serial_can_receive(void *opaque);
static void serial_receive_byte(ESCCChannelState *s, int ch);
+static int reg_shift(ESCCState *s)
+{
+ return s->bit_swap ? s->it_shift + 1 : s->it_shift;
+}
+
+static int chn_shift(ESCCState *s)
+{
+ return s->bit_swap ? s->it_shift : s->it_shift + 1;
+}
+
static void clear_queue(void *opaque)
{
ESCCChannelState *s = opaque;
@@ -436,8 +453,8 @@ static void escc_mem_write(void *opaque, hwaddr addr,
int newreg, channel;
val &= 0xff;
- saddr = (addr >> serial->it_shift) & 1;
- channel = (addr >> (serial->it_shift + 1)) & 1;
+ saddr = (addr >> reg_shift(serial)) & 1;
+ channel = (addr >> chn_shift(serial)) & 1;
s = &serial->chn[channel];
switch (saddr) {
case SERIAL_CTRL:
@@ -547,8 +564,8 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr,
uint32_t ret;
int channel;
- saddr = (addr >> serial->it_shift) & 1;
- channel = (addr >> (serial->it_shift + 1)) & 1;
+ saddr = (addr >> reg_shift(serial)) & 1;
+ channel = (addr >> chn_shift(serial)) & 1;
s = &serial->chn[channel];
switch (saddr) {
case SERIAL_CTRL:
@@ -832,6 +849,7 @@ static void escc_realize(DeviceState *dev, Error **errp)
static Property escc_properties[] = {
DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0),
DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0),
+ DEFINE_PROP_BOOL("bit_swap", ESCCState, bit_swap, false),
DEFINE_PROP_UINT32("disabled", ESCCState, disabled, 0),
DEFINE_PROP_UINT32("chnBtype", ESCCState, chn[0].type, 0),
DEFINE_PROP_UINT32("chnAtype", ESCCState, chn[1].type, 0),
diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c
index 1f66bda346..cd970cc4c5 100644
--- a/hw/core/machine-hmp-cmds.c
+++ b/hw/core/machine-hmp-cmds.c
@@ -23,6 +23,7 @@
#include "qapi/string-output-visitor.h"
#include "qemu/error-report.h"
#include "sysemu/numa.h"
+#include "hw/boards.h"
void hmp_info_cpus(Monitor *mon, const QDict *qdict)
{
@@ -139,15 +140,21 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
void hmp_info_numa(Monitor *mon, const QDict *qdict)
{
- int i;
+ int i, nb_numa_nodes;
NumaNodeMem *node_mem;
CpuInfoList *cpu_list, *cpu;
+ MachineState *ms = MACHINE(qdev_get_machine());
+
+ nb_numa_nodes = ms->numa_state ? ms->numa_state->num_nodes : 0;
+ monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
+ if (!nb_numa_nodes) {
+ return;
+ }
cpu_list = qmp_query_cpus(&error_abort);
node_mem = g_new0(NumaNodeMem, nb_numa_nodes);
- query_numa_node_mem(node_mem);
- monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
+ query_numa_node_mem(node_mem, ms);
for (i = 0; i < nb_numa_nodes; i++) {
monitor_printf(mon, "node %d cpus:", i);
for (cpu = cpu_list; cpu; cpu = cpu->next) {
diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
index 15cf7c62e3..eed5aeb2f7 100644
--- a/hw/core/machine-qmp-cmds.c
+++ b/hw/core/machine-qmp-cmds.c
@@ -230,6 +230,10 @@ MachineInfoList *qmp_query_machines(Error **errp)
info->hotpluggable_cpus = mc->has_hotpluggable_cpus;
info->numa_mem_supported = mc->numa_mem_supported;
info->deprecated = !!mc->deprecation_reason;
+ if (mc->default_cpu_type) {
+ info->default_cpu_type = g_strdup(mc->default_cpu_type);
+ info->has_default_cpu_type = true;
+ }
entry = g_malloc0(sizeof(*entry));
entry->value = info;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 83cd1bfeec..1689ad3bf8 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -27,7 +27,9 @@
#include "hw/pci/pci.h"
#include "hw/mem/nvdimm.h"
-GlobalProperty hw_compat_4_1[] = {};
+GlobalProperty hw_compat_4_1[] = {
+ { "virtio-pci", "x-pcie-flr-init", "off" },
+};
const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1);
GlobalProperty hw_compat_4_0[] = {
@@ -956,6 +958,9 @@ static void machine_initfn(Object *obj)
NULL);
}
+ if (mc->numa_mem_supported) {
+ ms->numa_state = g_new0(NumaState, 1);
+ }
/* Register notifier when init is done for sysbus sanity checks */
ms->sysbus_notifier.notify = machine_init_notify;
@@ -976,6 +981,7 @@ static void machine_finalize(Object *obj)
g_free(ms->firmware);
g_free(ms->device_memory);
g_free(ms->nvdimms_state);
+ g_free(ms->numa_state);
}
bool machine_usb(MachineState *machine)
@@ -1050,7 +1056,7 @@ static void machine_numa_finish_cpu_init(MachineState *machine)
MachineClass *mc = MACHINE_GET_CLASS(machine);
const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(machine);
- assert(nb_numa_nodes);
+ assert(machine->numa_state->num_nodes);
for (i = 0; i < possible_cpus->len; i++) {
if (possible_cpus->cpus[i].props.has_node_id) {
break;
@@ -1096,9 +1102,11 @@ void machine_run_board_init(MachineState *machine)
{
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
- numa_complete_configuration(machine);
- if (nb_numa_nodes) {
- machine_numa_finish_cpu_init(machine);
+ if (machine_class->numa_mem_supported) {
+ numa_complete_configuration(machine);
+ if (machine->numa_state->num_nodes) {
+ machine_numa_finish_cpu_init(machine);
+ }
}
/* If the machine supports the valid_cpu_types check and the user
diff --git a/hw/core/numa.c b/hw/core/numa.c
index 4f7e4628a0..4dfec5c95b 100644
--- a/hw/core/numa.c
+++ b/hw/core/numa.c
@@ -55,10 +55,6 @@ static int have_mem;
static int max_numa_nodeid; /* Highest specified NUMA node ID, plus one.
* For all nodes, nodeid < max_numa_nodeid
*/
-int nb_numa_nodes;
-bool have_numa_distance;
-NodeInfo numa_info[MAX_NODES];
-
static void parse_numa_node(MachineState *ms, NumaNodeOptions *node,
Error **errp)
@@ -68,11 +64,12 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node,
uint16List *cpus = NULL;
MachineClass *mc = MACHINE_GET_CLASS(ms);
unsigned int max_cpus = ms->smp.max_cpus;
+ NodeInfo *numa_info = ms->numa_state->nodes;
if (node->has_nodeid) {
nodenr = node->nodeid;
} else {
- nodenr = nb_numa_nodes;
+ nodenr = ms->numa_state->num_nodes;
}
if (nodenr >= MAX_NODES) {
@@ -138,14 +135,16 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node,
}
numa_info[nodenr].present = true;
max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1);
- nb_numa_nodes++;
+ ms->numa_state->num_nodes++;
}
-static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
+static
+void parse_numa_distance(MachineState *ms, NumaDistOptions *dist, Error **errp)
{
uint16_t src = dist->src;
uint16_t dst = dist->dst;
uint8_t val = dist->val;
+ NodeInfo *numa_info = ms->numa_state->nodes;
if (src >= MAX_NODES || dst >= MAX_NODES) {
error_setg(errp, "Parameter '%s' expects an integer between 0 and %d",
@@ -173,12 +172,18 @@ static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
}
numa_info[src].distance[dst] = val;
- have_numa_distance = true;
+ ms->numa_state->have_numa_distance = true;
}
void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
{
Error *err = NULL;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if (!mc->numa_mem_supported) {
+ error_setg(errp, "NUMA is not supported by this machine-type");
+ goto end;
+ }
switch (object->type) {
case NUMA_OPTIONS_TYPE_NODE:
@@ -188,7 +193,7 @@ void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
}
break;
case NUMA_OPTIONS_TYPE_DIST:
- parse_numa_distance(&object->u.dist, &err);
+ parse_numa_distance(ms, &object->u.dist, &err);
if (err) {
goto end;
}
@@ -198,7 +203,7 @@ void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
error_setg(&err, "Missing mandatory node-id property");
goto end;
}
- if (!numa_info[object->u.cpu.node_id].present) {
+ if (!ms->numa_state->nodes[object->u.cpu.node_id].present) {
error_setg(&err, "Invalid node-id=%" PRId64 ", NUMA node must be "
"defined with -numa node,nodeid=ID before it's used with "
"-numa cpu,node-id=ID", object->u.cpu.node_id);
@@ -253,10 +258,12 @@ end:
* distance from a node to itself is always NUMA_DISTANCE_MIN,
* so providing it is never necessary.
*/
-static void validate_numa_distance(void)
+static void validate_numa_distance(MachineState *ms)
{
int src, dst;
bool is_asymmetrical = false;
+ int nb_numa_nodes = ms->numa_state->num_nodes;
+ NodeInfo *numa_info = ms->numa_state->nodes;
for (src = 0; src < nb_numa_nodes; src++) {
for (dst = src; dst < nb_numa_nodes; dst++) {
@@ -294,17 +301,18 @@ static void validate_numa_distance(void)
}
}
-static void complete_init_numa_distance(void)
+static void complete_init_numa_distance(MachineState *ms)
{
int src, dst;
+ NodeInfo *numa_info = ms->numa_state->nodes;
/* Fixup NUMA distance by symmetric policy because if it is an
* asymmetric distance table, it should be a complete table and
* there would not be any missing distance except local node, which
* is verified by validate_numa_distance above.
*/
- for (src = 0; src < nb_numa_nodes; src++) {
- for (dst = 0; dst < nb_numa_nodes; dst++) {
+ for (src = 0; src < ms->numa_state->num_nodes; src++) {
+ for (dst = 0; dst < ms->numa_state->num_nodes; dst++) {
if (numa_info[src].distance[dst] == 0) {
if (src == dst) {
numa_info[src].distance[dst] = NUMA_DISTANCE_MIN;
@@ -356,6 +364,7 @@ void numa_complete_configuration(MachineState *ms)
{
int i;
MachineClass *mc = MACHINE_GET_CLASS(ms);
+ NodeInfo *numa_info = ms->numa_state->nodes;
/*
* If memory hotplug is enabled (slots > 0) but without '-numa'
@@ -370,7 +379,7 @@ void numa_complete_configuration(MachineState *ms)
*
* Enable NUMA implicitly by adding a new NUMA node automatically.
*/
- if (ms->ram_slots > 0 && nb_numa_nodes == 0 &&
+ if (ms->ram_slots > 0 && ms->numa_state->num_nodes == 0 &&
mc->auto_enable_numa_with_memhp) {
NumaNodeOptions node = { };
parse_numa_node(ms, &node, &error_abort);
@@ -388,26 +397,27 @@ void numa_complete_configuration(MachineState *ms)
}
/* This must be always true if all nodes are present: */
- assert(nb_numa_nodes == max_numa_nodeid);
+ assert(ms->numa_state->num_nodes == max_numa_nodeid);
- if (nb_numa_nodes > 0) {
+ if (ms->numa_state->num_nodes > 0) {
uint64_t numa_total;
- if (nb_numa_nodes > MAX_NODES) {
- nb_numa_nodes = MAX_NODES;
+ if (ms->numa_state->num_nodes > MAX_NODES) {
+ ms->numa_state->num_nodes = MAX_NODES;
}
/* If no memory size is given for any node, assume the default case
* and distribute the available memory equally across all nodes
*/
- for (i = 0; i < nb_numa_nodes; i++) {
+ for (i = 0; i < ms->numa_state->num_nodes; i++) {
if (numa_info[i].node_mem != 0) {
break;
}
}
- if (i == nb_numa_nodes) {
+ if (i == ms->numa_state->num_nodes) {
assert(mc->numa_auto_assign_ram);
- mc->numa_auto_assign_ram(mc, numa_info, nb_numa_nodes, ram_size);
+ mc->numa_auto_assign_ram(mc, numa_info,
+ ms->numa_state->num_nodes, ram_size);
if (!qtest_enabled()) {
warn_report("Default splitting of RAM between nodes is deprecated,"
" Use '-numa node,memdev' to explictly define RAM"
@@ -416,7 +426,7 @@ void numa_complete_configuration(MachineState *ms)
}
numa_total = 0;
- for (i = 0; i < nb_numa_nodes; i++) {
+ for (i = 0; i < ms->numa_state->num_nodes; i++) {
numa_total += numa_info[i].node_mem;
}
if (numa_total != ram_size) {
@@ -438,12 +448,12 @@ void numa_complete_configuration(MachineState *ms)
* asymmetric. In this case, the distances for both directions
* of all node pairs are required.
*/
- if (have_numa_distance) {
+ if (ms->numa_state->have_numa_distance) {
/* Validate enough NUMA distance information was provided. */
- validate_numa_distance();
+ validate_numa_distance(ms);
/* Validation succeeded, now fill in any missing distances. */
- complete_init_numa_distance();
+ complete_init_numa_distance(ms);
}
}
}
@@ -510,16 +520,18 @@ void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,
{
uint64_t addr = 0;
int i;
+ MachineState *ms = MACHINE(qdev_get_machine());
- if (nb_numa_nodes == 0 || !have_memdevs) {
+ if (ms->numa_state == NULL ||
+ ms->numa_state->num_nodes == 0 || !have_memdevs) {
allocate_system_memory_nonnuma(mr, owner, name, ram_size);
return;
}
memory_region_init(mr, owner, name, ram_size);
- for (i = 0; i < nb_numa_nodes; i++) {
- uint64_t size = numa_info[i].node_mem;
- HostMemoryBackend *backend = numa_info[i].node_memdev;
+ for (i = 0; i < ms->numa_state->num_nodes; i++) {
+ uint64_t size = ms->numa_state->nodes[i].node_mem;
+ HostMemoryBackend *backend = ms->numa_state->nodes[i].node_memdev;
if (!backend) {
continue;
}
@@ -575,17 +587,17 @@ static void numa_stat_memory_devices(NumaNodeMem node_mem[])
qapi_free_MemoryDeviceInfoList(info_list);
}
-void query_numa_node_mem(NumaNodeMem node_mem[])
+void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms)
{
int i;
- if (nb_numa_nodes <= 0) {
+ if (ms->numa_state == NULL || ms->numa_state->num_nodes <= 0) {
return;
}
numa_stat_memory_devices(node_mem);
- for (i = 0; i < nb_numa_nodes; i++) {
- node_mem[i].node_mem += numa_info[i].node_mem;
+ for (i = 0; i < ms->numa_state->num_nodes; i++) {
+ node_mem[i].node_mem += ms->numa_state->nodes[i].node_mem;
}
}
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 0f11d55b14..5a4066383b 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -38,6 +38,7 @@ common-obj-$(CONFIG_RASPI) += bcm2835_fb.o
common-obj-$(CONFIG_SM501) += sm501.o
common-obj-$(CONFIG_TCX) += tcx.o
common-obj-$(CONFIG_CG3) += cg3.o
+common-obj-$(CONFIG_NEXTCUBE) += next-fb.o
obj-$(CONFIG_VGA) += vga.o
diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c
new file mode 100644
index 0000000000..2b726a10f8
--- /dev/null
+++ b/hw/display/next-fb.c
@@ -0,0 +1,146 @@
+/*
+ * NeXT Cube/Station Framebuffer Emulation
+ *
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "ui/console.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/display/framebuffer.h"
+#include "ui/pixel_ops.h"
+#include "hw/m68k/next-cube.h"
+
+#define NEXTFB(obj) OBJECT_CHECK(NeXTFbState, (obj), TYPE_NEXTFB)
+
+struct NeXTFbState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion fb_mr;
+ MemoryRegionSection fbsection;
+ QemuConsole *con;
+
+ uint32_t cols;
+ uint32_t rows;
+ int invalidate;
+};
+typedef struct NeXTFbState NeXTFbState;
+
+static void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s,
+ int width, int pitch)
+{
+ NeXTFbState *nfbstate = NEXTFB(opaque);
+ static const uint32_t pal[4] = {
+ 0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555, 0xFF000000
+ };
+ uint32_t *buf = (uint32_t *)d;
+ int i = 0;
+
+ for (i = 0; i < nfbstate->cols / 4; i++) {
+ int j = i * 4;
+ uint8_t src = s[i];
+ buf[j + 3] = pal[src & 0x3];
+ src >>= 2;
+ buf[j + 2] = pal[src & 0x3];
+ src >>= 2;
+ buf[j + 1] = pal[src & 0x3];
+ src >>= 2;
+ buf[j + 0] = pal[src & 0x3];
+ }
+}
+
+static void nextfb_update(void *opaque)
+{
+ NeXTFbState *s = NEXTFB(opaque);
+ int dest_width = 4;
+ int src_width;
+ int first = 0;
+ int last = 0;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+
+ src_width = s->cols / 4 + 8;
+ dest_width = s->cols * 4;
+
+ if (s->invalidate) {
+ framebuffer_update_memory_section(&s->fbsection, &s->fb_mr, 0,
+ s->cols, src_width);
+ s->invalidate = 0;
+ }
+
+ framebuffer_update_display(surface, &s->fbsection, s->cols, s->rows,
+ src_width, dest_width, 0, 1, nextfb_draw_line,
+ s, &first, &last);
+
+ dpy_gfx_update(s->con, 0, 0, s->cols, s->rows);
+}
+
+static void nextfb_invalidate(void *opaque)
+{
+ NeXTFbState *s = NEXTFB(opaque);
+ s->invalidate = 1;
+}
+
+static const GraphicHwOps nextfb_ops = {
+ .invalidate = nextfb_invalidate,
+ .gfx_update = nextfb_update,
+};
+
+static void nextfb_realize(DeviceState *dev, Error **errp)
+{
+ NeXTFbState *s = NEXTFB(dev);
+
+ memory_region_init_ram(&s->fb_mr, OBJECT(dev), "next-video", 0x1CB100,
+ &error_fatal);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->fb_mr);
+
+ s->invalidate = 1;
+ s->cols = 1120;
+ s->rows = 832;
+
+ s->con = graphic_console_init(dev, 0, &nextfb_ops, s);
+ qemu_console_resize(s->con, s->cols, s->rows);
+}
+
+static void nextfb_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+ dc->realize = nextfb_realize;
+
+ /* Note: This device does not any state that we have to reset or migrate */
+}
+
+static const TypeInfo nextfb_info = {
+ .name = TYPE_NEXTFB,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NeXTFbState),
+ .class_init = nextfb_class_init,
+};
+
+static void nextfb_register_types(void)
+{
+ type_register_static(&nextfb_info);
+}
+
+type_init(nextfb_register_types)
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index d176df6d44..a254275b64 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -566,14 +566,14 @@ static void xilinx_axidma_init(Object *obj)
XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
- TYPE_XILINX_AXI_DMA_DATA_STREAM);
- object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
- TYPE_XILINX_AXI_DMA_CONTROL_STREAM);
- object_property_add_child(OBJECT(s), "axistream-connected-target",
- (Object *)&s->rx_data_dev, &error_abort);
- object_property_add_child(OBJECT(s), "axistream-control-connected-target",
- (Object *)&s->rx_control_dev, &error_abort);
+ object_initialize_child(OBJECT(s), "axistream-connected-target",
+ &s->rx_data_dev, sizeof(s->rx_data_dev),
+ TYPE_XILINX_AXI_DMA_DATA_STREAM, &error_abort,
+ NULL);
+ object_initialize_child(OBJECT(s), "axistream-control-connected-target",
+ &s->rx_control_dev, sizeof(s->rx_control_dev),
+ TYPE_XILINX_AXI_DMA_CONTROL_STREAM, &error_abort,
+ NULL);
sysbus_init_irq(sbd, &s->streams[0].irq);
sysbus_init_irq(sbd, &s->streams[1].irq);
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 034e413fd0..e54e571a75 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2694,9 +2694,9 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
if (pcms->numa_nodes) {
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
- if (have_numa_distance) {
+ if (machine->numa_state->have_numa_distance) {
acpi_add_table(table_offsets, tables_blob);
- build_slit(tables_blob, tables->linker);
+ build_slit(tables_blob, tables->linker, machine);
}
}
if (acpi_get_mcfg(&mcfg)) {
diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
index 80c133a724..2c59b6894b 100644
--- a/hw/i386/kvm/clock.c
+++ b/hw/i386/kvm/clock.c
@@ -41,6 +41,9 @@ typedef struct KVMClockState {
uint64_t clock;
bool clock_valid;
+ /* whether the 'clock' value was obtained in the 'paused' state */
+ bool runstate_paused;
+
/* whether machine type supports reliable KVM_GET_CLOCK */
bool mach_use_reliable_get_clock;
@@ -202,6 +205,8 @@ static void kvmclock_vm_state_change(void *opaque, int running,
return;
}
+ s->runstate_paused = runstate_check(RUN_STATE_PAUSED);
+
kvm_synchronize_all_tsc();
kvm_update_clock(s);
@@ -260,9 +265,9 @@ static int kvmclock_pre_load(void *opaque)
}
/*
- * When migrating, read the clock just before migration,
- * so that the guest clock counts during the events
- * between:
+ * When migrating a running guest, read the clock just
+ * before migration, so that the guest clock counts
+ * during the events between:
*
* * vm_stop()
* *
@@ -277,7 +282,9 @@ static int kvmclock_pre_save(void *opaque)
{
KVMClockState *s = opaque;
- kvm_update_clock(s);
+ if (!s->runstate_paused) {
+ kvm_update_clock(s);
+ }
return 0;
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index c14ed86439..bad866fe44 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1002,6 +1002,8 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
int i;
const CPUArchIdList *cpus;
MachineClass *mc = MACHINE_GET_CLASS(pcms);
+ MachineState *ms = MACHINE(pcms);
+ int nb_numa_nodes = ms->numa_state->num_nodes;
fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
@@ -1044,7 +1046,7 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms)
}
for (i = 0; i < nb_numa_nodes; i++) {
numa_fw_cfg[pcms->apic_id_limit + 1 + i] =
- cpu_to_le64(numa_info[i].node_mem);
+ cpu_to_le64(ms->numa_state->nodes[i].node_mem);
}
fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg,
(1 + pcms->apic_id_limit + nb_numa_nodes) *
@@ -1774,13 +1776,14 @@ void pc_machine_done(Notifier *notifier, void *data)
void pc_guest_info_init(PCMachineState *pcms)
{
int i;
+ MachineState *ms = MACHINE(pcms);
pcms->apic_xrupt_override = kvm_allows_irq0_override();
- pcms->numa_nodes = nb_numa_nodes;
+ pcms->numa_nodes = ms->numa_state->num_nodes;
pcms->node_mem = g_malloc0(pcms->numa_nodes *
sizeof *pcms->node_mem);
- for (i = 0; i < nb_numa_nodes; i++) {
- pcms->node_mem[i] = numa_info[i].node_mem;
+ for (i = 0; i < ms->numa_state->num_nodes; i++) {
+ pcms->node_mem[i] = ms->numa_state->nodes[i].node_mem;
}
pcms->machine_done.notify = pc_machine_done;
@@ -2418,6 +2421,14 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
int max_socket = (ms->smp.max_cpus - 1) /
smp_threads / smp_cores / pcms->smp_dies;
+ /*
+ * die-id was optional in QEMU 4.0 and older, so keep it optional
+ * if there's only one die per socket.
+ */
+ if (cpu->die_id < 0 && pcms->smp_dies == 1) {
+ cpu->die_id = 0;
+ }
+
if (cpu->socket_id < 0) {
error_setg(errp, "CPU socket-id is not set");
return;
@@ -2425,9 +2436,13 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
cpu->socket_id, max_socket);
return;
+ }
+ if (cpu->die_id < 0) {
+ error_setg(errp, "CPU die-id is not set");
+ return;
} else if (cpu->die_id > pcms->smp_dies - 1) {
error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
- cpu->die_id, max_socket);
+ cpu->die_id, pcms->smp_dies - 1);
return;
}
if (cpu->core_id < 0) {
@@ -2869,7 +2884,7 @@ static int64_t pc_get_default_cpu_node_id(const MachineState *ms, int idx)
x86_topo_ids_from_apicid(ms->possible_cpus->cpus[idx].arch_id,
pcms->smp_dies, ms->smp.cores,
ms->smp.threads, &topo);
- return topo.pkg_id % nb_numa_nodes;
+ return topo.pkg_id % ms->numa_state->num_nodes;
}
static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms)
@@ -2901,8 +2916,10 @@ static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms)
ms->smp.threads, &topo);
ms->possible_cpus->cpus[i].props.has_socket_id = true;
ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id;
- ms->possible_cpus->cpus[i].props.has_die_id = true;
- ms->possible_cpus->cpus[i].props.die_id = topo.die_id;
+ if (pcms->smp_dies > 1) {
+ ms->possible_cpus->cpus[i].props.has_die_id = true;
+ ms->possible_cpus->cpus[i].props.die_id = topo.die_id;
+ }
ms->possible_cpus->cpus[i].props.has_core_id = true;
ms->possible_cpus->cpus[i].props.core_id = topo.core_id;
ms->possible_cpus->cpus[i].props.has_thread_id = true;
diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index 012ab90396..41ad91ad53 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -258,6 +258,7 @@ static void vmmouse_reset(DeviceState *d)
VMMouseState *s = VMMOUSE(d);
s->queue_size = VMMOUSE_QUEUE_SIZE;
+ s->nb_queue = 0;
vmmouse_disable(s);
}
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 62ab8b7273..8e93e51e81 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -21,6 +21,7 @@
#include "hw/qdev-properties.h"
#include "target/arm/cpu.h"
#include "exec/exec-all.h"
+#include "exec/memop.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
@@ -2348,7 +2349,8 @@ static MemTxResult nvic_sysreg_ns_write(void *opaque, hwaddr addr,
if (attrs.secure) {
/* S accesses to the alias act like NS accesses to the real region */
attrs.secure = 0;
- return memory_region_dispatch_write(mr, addr, value, size, attrs);
+ return memory_region_dispatch_write(mr, addr, value,
+ size_memop(size) | MO_TE, attrs);
} else {
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
if (attrs.user) {
@@ -2367,7 +2369,8 @@ static MemTxResult nvic_sysreg_ns_read(void *opaque, hwaddr addr,
if (attrs.secure) {
/* S accesses to the alias act like NS accesses to the real region */
attrs.secure = 0;
- return memory_region_dispatch_read(mr, addr, data, size, attrs);
+ return memory_region_dispatch_read(mr, addr, data,
+ size_memop(size) | MO_TE, attrs);
} else {
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
if (attrs.user) {
@@ -2393,7 +2396,8 @@ static MemTxResult nvic_systick_write(void *opaque, hwaddr addr,
/* Direct the access to the correct systick */
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
- return memory_region_dispatch_write(mr, addr, value, size, attrs);
+ return memory_region_dispatch_write(mr, addr, value,
+ size_memop(size) | MO_TE, attrs);
}
static MemTxResult nvic_systick_read(void *opaque, hwaddr addr,
@@ -2405,7 +2409,8 @@ static MemTxResult nvic_systick_read(void *opaque, hwaddr addr,
/* Direct the access to the correct systick */
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
- return memory_region_dispatch_read(mr, addr, data, size, attrs);
+ return memory_region_dispatch_read(mr, addr, data, size_memop(size) | MO_TE,
+ attrs);
}
static const MemoryRegionOps nvic_systick_ops = {
diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig
index 49ef0b3f6d..a74fac5abd 100644
--- a/hw/m68k/Kconfig
+++ b/hw/m68k/Kconfig
@@ -7,3 +7,8 @@ config MCF5208
bool
select COLDFIRE
select PTIMER
+
+config NEXTCUBE
+ bool
+ select FRAMEBUFFER
+ select ESCC
diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs
index 482f8477b4..f25854730d 100644
--- a/hw/m68k/Makefile.objs
+++ b/hw/m68k/Makefile.objs
@@ -1,2 +1,3 @@
obj-$(CONFIG_AN5206) += an5206.o mcf5206.o
obj-$(CONFIG_MCF5208) += mcf5208.o mcf_intc.o
+obj-$(CONFIG_NEXTCUBE) += next-kbd.o next-cube.o
diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c
new file mode 100644
index 0000000000..9a4a7328f9
--- /dev/null
+++ b/hw/m68k/next-cube.c
@@ -0,0 +1,978 @@
+/*
+ * NeXT Cube System Driver
+ *
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * This code 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.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/hwaddr.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "hw/irq.h"
+#include "hw/m68k/next-cube.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/scsi/esp.h"
+#include "hw/sysbus.h"
+#include "hw/char/escc.h" /* ZILOG 8530 Serial Emulation */
+#include "hw/block/fdc.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "ui/console.h"
+#include "target/m68k/cpu.h"
+
+/* #define DEBUG_NEXT */
+#ifdef DEBUG_NEXT
+#define DPRINTF(fmt, ...) \
+ do { printf("NeXT: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define TYPE_NEXT_MACHINE MACHINE_TYPE_NAME("next-cube")
+#define NEXT_MACHINE(obj) OBJECT_CHECK(NeXTState, (obj), TYPE_NEXT_MACHINE)
+
+#define ENTRY 0x0100001e
+#define RAM_SIZE 0x4000000
+#define ROM_FILE "Rev_2.5_v66.bin"
+
+typedef struct next_dma {
+ uint32_t csr;
+
+ uint32_t saved_next;
+ uint32_t saved_limit;
+ uint32_t saved_start;
+ uint32_t saved_stop;
+
+ uint32_t next;
+ uint32_t limit;
+ uint32_t start;
+ uint32_t stop;
+
+ uint32_t next_initbuf;
+ uint32_t size;
+} next_dma;
+
+typedef struct {
+ MachineState parent;
+
+ uint32_t int_mask;
+ uint32_t int_status;
+
+ uint8_t scsi_csr_1;
+ uint8_t scsi_csr_2;
+ next_dma dma[10];
+ qemu_irq *scsi_irq;
+ qemu_irq scsi_dma;
+ qemu_irq scsi_reset;
+ qemu_irq *fd_irq;
+
+ uint32_t scr1;
+ uint32_t scr2;
+
+ uint8_t rtc_ram[32];
+} NeXTState;
+
+/* Thanks to NeXT forums for this */
+/*
+static const uint8_t rtc_ram3[32] = {
+ 0x94, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x7B, 0x00,
+ 0x00, 0x00, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x13
+};
+*/
+static const uint8_t rtc_ram2[32] = {
+ 0x94, 0x0f, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfb, 0x6d, 0x00, 0x00, 0x4b, 0x00,
+ 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x7e,
+};
+
+#define SCR2_RTCLK 0x2
+#define SCR2_RTDATA 0x4
+#define SCR2_TOBCD(x) (((x / 10) << 4) + (x % 10))
+
+static void nextscr2_write(NeXTState *s, uint32_t val, int size)
+{
+ static int led;
+ static int phase;
+ static uint8_t old_scr2;
+ static uint8_t rtc_command;
+ static uint8_t rtc_value;
+ static uint8_t rtc_status = 0x90;
+ static uint8_t rtc_return;
+ uint8_t scr2_2;
+
+ if (size == 4) {
+ scr2_2 = (val >> 8) & 0xFF;
+ } else {
+ scr2_2 = val & 0xFF;
+ }
+
+ if (val & 0x1) {
+ DPRINTF("fault!\n");
+ led++;
+ if (led == 10) {
+ DPRINTF("LED flashing, possible fault!\n");
+ led = 0;
+ }
+ }
+
+ if (scr2_2 & 0x1) {
+ /* DPRINTF("RTC %x phase %i\n", scr2_2, phase); */
+ if (phase == -1) {
+ phase = 0;
+ }
+ /* If we are in going down clock... do something */
+ if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) &&
+ ((scr2_2 & SCR2_RTCLK) == 0)) {
+ if (phase < 8) {
+ rtc_command = (rtc_command << 1) |
+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
+ }
+ if (phase >= 8 && phase < 16) {
+ rtc_value = (rtc_value << 1) | ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
+
+ /* if we read RAM register, output RT_DATA bit */
+ if (rtc_command <= 0x1F) {
+ scr2_2 = scr2_2 & (~SCR2_RTDATA);
+ if (s->rtc_ram[rtc_command] & (0x80 >> (phase - 8))) {
+ scr2_2 |= SCR2_RTDATA;
+ }
+
+ rtc_return = (rtc_return << 1) |
+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
+ }
+ /* read the status 0x30 */
+ if (rtc_command == 0x30) {
+ scr2_2 = scr2_2 & (~SCR2_RTDATA);
+ /* for now status = 0x98 (new rtc + FTU) */
+ if (rtc_status & (0x80 >> (phase - 8))) {
+ scr2_2 |= SCR2_RTDATA;
+ }
+
+ rtc_return = (rtc_return << 1) |
+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
+ }
+ /* read the status 0x31 */
+ if (rtc_command == 0x31) {
+ scr2_2 = scr2_2 & (~SCR2_RTDATA);
+ /* for now 0x00 */
+ if (0x00 & (0x80 >> (phase - 8))) {
+ scr2_2 |= SCR2_RTDATA;
+ }
+ rtc_return = (rtc_return << 1) |
+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
+ }
+
+ if ((rtc_command >= 0x20) && (rtc_command <= 0x2F)) {
+ scr2_2 = scr2_2 & (~SCR2_RTDATA);
+ /* for now 0x00 */
+ time_t time_h = time(NULL);
+ struct tm *info = localtime(&time_h);
+ int ret = 0;
+
+ switch (rtc_command) {
+ case 0x20:
+ ret = SCR2_TOBCD(info->tm_sec);
+ break;
+ case 0x21:
+ ret = SCR2_TOBCD(info->tm_min);
+ break;
+ case 0x22:
+ ret = SCR2_TOBCD(info->tm_hour);
+ break;
+ case 0x24:
+ ret = SCR2_TOBCD(info->tm_mday);
+ break;
+ case 0x25:
+ ret = SCR2_TOBCD((info->tm_mon + 1));
+ break;
+ case 0x26:
+ ret = SCR2_TOBCD((info->tm_year - 100));
+ break;
+
+ }
+
+ if (ret & (0x80 >> (phase - 8))) {
+ scr2_2 |= SCR2_RTDATA;
+ }
+ rtc_return = (rtc_return << 1) |
+ ((scr2_2 & SCR2_RTDATA) ? 1 : 0);
+ }
+
+ }
+
+ phase++;
+ if (phase == 16) {
+ if (rtc_command >= 0x80 && rtc_command <= 0x9F) {
+ s->rtc_ram[rtc_command - 0x80] = rtc_value;
+ }
+ /* write to x30 register */
+ if (rtc_command == 0xB1) {
+ /* clear FTU */
+ if (rtc_value & 0x04) {
+ rtc_status = rtc_status & (~0x18);
+ s->int_status = s->int_status & (~0x04);
+ }
+ }
+ }
+ }
+ } else {
+ /* else end or abort */
+ phase = -1;
+ rtc_command = 0;
+ rtc_value = 0;
+ }
+ s->scr2 = val & 0xFFFF00FF;
+ s->scr2 |= scr2_2 << 8;
+ old_scr2 = scr2_2;
+}
+
+static uint32_t mmio_readb(NeXTState *s, hwaddr addr)
+{
+ switch (addr) {
+ case 0xc000:
+ return (s->scr1 >> 24) & 0xFF;
+ case 0xc001:
+ return (s->scr1 >> 16) & 0xFF;
+ case 0xc002:
+ return (s->scr1 >> 8) & 0xFF;
+ case 0xc003:
+ return (s->scr1 >> 0) & 0xFF;
+
+ case 0xd000:
+ return (s->scr2 >> 24) & 0xFF;
+ case 0xd001:
+ return (s->scr2 >> 16) & 0xFF;
+ case 0xd002:
+ return (s->scr2 >> 8) & 0xFF;
+ case 0xd003:
+ return (s->scr2 >> 0) & 0xFF;
+ case 0x14020:
+ DPRINTF("MMIO Read 0x4020\n");
+ return 0x7f;
+
+ default:
+ DPRINTF("MMIO Read B @ %"HWADDR_PRIx"\n", addr);
+ return 0x0;
+ }
+}
+
+static uint32_t mmio_readw(NeXTState *s, hwaddr addr)
+{
+ switch (addr) {
+ default:
+ DPRINTF("MMIO Read W @ %"HWADDR_PRIx"\n", addr);
+ return 0x0;
+ }
+}
+
+static uint32_t mmio_readl(NeXTState *s, hwaddr addr)
+{
+ switch (addr) {
+ case 0x7000:
+ /* DPRINTF("Read INT status: %x\n", s->int_status); */
+ return s->int_status;
+
+ case 0x7800:
+ DPRINTF("MMIO Read INT mask: %x\n", s->int_mask);
+ return s->int_mask;
+
+ case 0xc000:
+ return s->scr1;
+
+ case 0xd000:
+ return s->scr2;
+
+ default:
+ DPRINTF("MMIO Read L @ %"HWADDR_PRIx"\n", addr);
+ return 0x0;
+ }
+}
+
+static void mmio_writeb(NeXTState *s, hwaddr addr, uint32_t val)
+{
+ switch (addr) {
+ case 0xd003:
+ nextscr2_write(s, val, 1);
+ break;
+ default:
+ DPRINTF("MMIO Write B @ %x with %x\n", (unsigned int)addr, val);
+ }
+
+}
+
+static void mmio_writew(NeXTState *s, hwaddr addr, uint32_t val)
+{
+ DPRINTF("MMIO Write W\n");
+}
+
+static void mmio_writel(NeXTState *s, hwaddr addr, uint32_t val)
+{
+ switch (addr) {
+ case 0x7000:
+ DPRINTF("INT Status old: %x new: %x\n", s->int_status, val);
+ s->int_status = val;
+ break;
+ case 0x7800:
+ DPRINTF("INT Mask old: %x new: %x\n", s->int_mask, val);
+ s->int_mask = val;
+ break;
+ case 0xc000:
+ DPRINTF("SCR1 Write: %x\n", val);
+ break;
+ case 0xd000:
+ nextscr2_write(s, val, 4);
+ break;
+
+ default:
+ DPRINTF("MMIO Write l @ %x with %x\n", (unsigned int)addr, val);
+ }
+}
+
+static uint64_t mmio_readfn(void *opaque, hwaddr addr, unsigned size)
+{
+ NeXTState *ns = NEXT_MACHINE(opaque);
+
+ switch (size) {
+ case 1:
+ return mmio_readb(ns, addr);
+ case 2:
+ return mmio_readw(ns, addr);
+ case 4:
+ return mmio_readl(ns, addr);
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void mmio_writefn(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ NeXTState *ns = NEXT_MACHINE(opaque);
+
+ switch (size) {
+ case 1:
+ mmio_writeb(ns, addr, value);
+ break;
+ case 2:
+ mmio_writew(ns, addr, value);
+ break;
+ case 4:
+ mmio_writel(ns, addr, value);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static const MemoryRegionOps mmio_ops = {
+ .read = mmio_readfn,
+ .write = mmio_writefn,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint32_t scr_readb(NeXTState *s, hwaddr addr)
+{
+ switch (addr) {
+ case 0x14108:
+ DPRINTF("FD read @ %x\n", (unsigned int)addr);
+ return 0x40 | 0x04 | 0x2 | 0x1;
+ case 0x14020:
+ DPRINTF("SCSI 4020 STATUS READ %X\n", s->scsi_csr_1);
+ return s->scsi_csr_1;
+
+ case 0x14021:
+ DPRINTF("SCSI 4021 STATUS READ %X\n", s->scsi_csr_2);
+ return 0x40;
+
+ /*
+ * These 4 registers are the hardware timer, not sure which register
+ * is the latch instead of data, but no problems so far
+ */
+ case 0x1a000:
+ return 0xff & (clock() >> 24);
+ case 0x1a001:
+ return 0xff & (clock() >> 16);
+ case 0x1a002:
+ return 0xff & (clock() >> 8);
+ case 0x1a003:
+ /* Hack: We need to have this change consistently to make it work */
+ return 0xFF & clock();
+
+ default:
+ DPRINTF("BMAP Read B @ %x\n", (unsigned int)addr);
+ return 0;
+ }
+}
+
+static uint32_t scr_readw(NeXTState *s, hwaddr addr)
+{
+ DPRINTF("BMAP Read W @ %x\n", (unsigned int)addr);
+ return 0;
+}
+
+static uint32_t scr_readl(NeXTState *s, hwaddr addr)
+{
+ DPRINTF("BMAP Read L @ %x\n", (unsigned int)addr);
+ return 0;
+}
+
+#define SCSICSR_ENABLE 0x01
+#define SCSICSR_RESET 0x02 /* reset scsi dma */
+#define SCSICSR_FIFOFL 0x04
+#define SCSICSR_DMADIR 0x08 /* if set, scsi to mem */
+#define SCSICSR_CPUDMA 0x10 /* if set, dma enabled */
+#define SCSICSR_INTMASK 0x20 /* if set, interrupt enabled */
+
+static void scr_writeb(NeXTState *s, hwaddr addr, uint32_t value)
+{
+ switch (addr) {
+ case 0x14108:
+ DPRINTF("FDCSR Write: %x\n", value);
+
+ if (value == 0x0) {
+ /* qemu_irq_raise(s->fd_irq[0]); */
+ }
+ break;
+ case 0x14020: /* SCSI Control Register */
+ if (value & SCSICSR_FIFOFL) {
+ DPRINTF("SCSICSR FIFO Flush\n");
+ /* will have to add another irq to the esp if this is needed */
+ /* esp_puflush_fifo(esp_g); */
+ /* qemu_irq_pulse(s->scsi_dma); */
+ }
+
+ if (value & SCSICSR_ENABLE) {
+ DPRINTF("SCSICSR Enable\n");
+ /*
+ * qemu_irq_raise(s->scsi_dma);
+ * s->scsi_csr_1 = 0xc0;
+ * s->scsi_csr_1 |= 0x1;
+ * qemu_irq_pulse(s->scsi_dma);
+ */
+ }
+ /*
+ * else
+ * s->scsi_csr_1 &= ~SCSICSR_ENABLE;
+ */
+
+ if (value & SCSICSR_RESET) {
+ DPRINTF("SCSICSR Reset\n");
+ /* I think this should set DMADIR. CPUDMA and INTMASK to 0 */
+ /* qemu_irq_raise(s->scsi_reset); */
+ /* s->scsi_csr_1 &= ~(SCSICSR_INTMASK |0x80|0x1); */
+
+ }
+ if (value & SCSICSR_DMADIR) {
+ DPRINTF("SCSICSR DMAdir\n");
+ }
+ if (value & SCSICSR_CPUDMA) {
+ DPRINTF("SCSICSR CPUDMA\n");
+ /* qemu_irq_raise(s->scsi_dma); */
+
+ s->int_status |= 0x4000000;
+ } else {
+ s->int_status &= ~(0x4000000);
+ }
+ if (value & SCSICSR_INTMASK) {
+ DPRINTF("SCSICSR INTMASK\n");
+ /*
+ * int_mask &= ~0x1000;
+ * s->scsi_csr_1 |= value;
+ * s->scsi_csr_1 &= ~SCSICSR_INTMASK;
+ * if (s->scsi_queued) {
+ * s->scsi_queued = 0;
+ * next_irq(s, NEXT_SCSI_I, level);
+ * }
+ */
+ } else {
+ /* int_mask |= 0x1000; */
+ }
+ if (value & 0x80) {
+ /* int_mask |= 0x1000; */
+ /* s->scsi_csr_1 |= 0x80; */
+ }
+ DPRINTF("SCSICSR Write: %x\n", value);
+ /* s->scsi_csr_1 = value; */
+ return;
+ /* Hardware timer latch - not implemented yet */
+ case 0x1a000:
+ default:
+ DPRINTF("BMAP Write B @ %x with %x\n", (unsigned int)addr, value);
+ }
+}
+
+static void scr_writew(NeXTState *s, hwaddr addr, uint32_t value)
+{
+ DPRINTF("BMAP Write W @ %x with %x\n", (unsigned int)addr, value);
+}
+
+static void scr_writel(NeXTState *s, hwaddr addr, uint32_t value)
+{
+ DPRINTF("BMAP Write L @ %x with %x\n", (unsigned int)addr, value);
+}
+
+static uint64_t scr_readfn(void *opaque, hwaddr addr, unsigned size)
+{
+ NeXTState *ns = NEXT_MACHINE(opaque);
+
+ switch (size) {
+ case 1:
+ return scr_readb(ns, addr);
+ case 2:
+ return scr_readw(ns, addr);
+ case 4:
+ return scr_readl(ns, addr);
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void scr_writefn(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ NeXTState *ns = NEXT_MACHINE(opaque);
+
+ switch (size) {
+ case 1:
+ scr_writeb(ns, addr, value);
+ break;
+ case 2:
+ scr_writew(ns, addr, value);
+ break;
+ case 4:
+ scr_writel(ns, addr, value);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static const MemoryRegionOps scr_ops = {
+ .read = scr_readfn,
+ .write = scr_writefn,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+#define NEXTDMA_SCSI(x) (0x10 + x)
+#define NEXTDMA_FD(x) (0x10 + x)
+#define NEXTDMA_ENTX(x) (0x110 + x)
+#define NEXTDMA_ENRX(x) (0x150 + x)
+#define NEXTDMA_CSR 0x0
+#define NEXTDMA_NEXT 0x4000
+#define NEXTDMA_LIMIT 0x4004
+#define NEXTDMA_START 0x4008
+#define NEXTDMA_STOP 0x400c
+#define NEXTDMA_NEXT_INIT 0x4200
+#define NEXTDMA_SIZE 0x4204
+
+static void dma_writel(void *opaque, hwaddr addr, uint64_t value,
+ unsigned int size)
+{
+ NeXTState *next_state = NEXT_MACHINE(opaque);
+
+ switch (addr) {
+ case NEXTDMA_ENRX(NEXTDMA_CSR):
+ if (value & DMA_DEV2M) {
+ next_state->dma[NEXTDMA_ENRX].csr |= DMA_DEV2M;
+ }
+
+ if (value & DMA_SETENABLE) {
+ /* DPRINTF("SCSI DMA ENABLE\n"); */
+ next_state->dma[NEXTDMA_ENRX].csr |= DMA_ENABLE;
+ }
+ if (value & DMA_SETSUPDATE) {
+ next_state->dma[NEXTDMA_ENRX].csr |= DMA_SUPDATE;
+ }
+ if (value & DMA_CLRCOMPLETE) {
+ next_state->dma[NEXTDMA_ENRX].csr &= ~DMA_COMPLETE;
+ }
+
+ if (value & DMA_RESET) {
+ next_state->dma[NEXTDMA_ENRX].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
+ DMA_ENABLE | DMA_DEV2M);
+ }
+ /* DPRINTF("RXCSR \tWrite: %x\n",value); */
+ break;
+ case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
+ next_state->dma[NEXTDMA_ENRX].next_initbuf = value;
+ break;
+ case NEXTDMA_ENRX(NEXTDMA_NEXT):
+ next_state->dma[NEXTDMA_ENRX].next = value;
+ break;
+ case NEXTDMA_ENRX(NEXTDMA_LIMIT):
+ next_state->dma[NEXTDMA_ENRX].limit = value;
+ break;
+ case NEXTDMA_SCSI(NEXTDMA_CSR):
+ if (value & DMA_DEV2M) {
+ next_state->dma[NEXTDMA_SCSI].csr |= DMA_DEV2M;
+ }
+ if (value & DMA_SETENABLE) {
+ /* DPRINTF("SCSI DMA ENABLE\n"); */
+ next_state->dma[NEXTDMA_SCSI].csr |= DMA_ENABLE;
+ }
+ if (value & DMA_SETSUPDATE) {
+ next_state->dma[NEXTDMA_SCSI].csr |= DMA_SUPDATE;
+ }
+ if (value & DMA_CLRCOMPLETE) {
+ next_state->dma[NEXTDMA_SCSI].csr &= ~DMA_COMPLETE;
+ }
+
+ if (value & DMA_RESET) {
+ next_state->dma[NEXTDMA_SCSI].csr &= ~(DMA_COMPLETE | DMA_SUPDATE |
+ DMA_ENABLE | DMA_DEV2M);
+ /* DPRINTF("SCSI DMA RESET\n"); */
+ }
+ /* DPRINTF("RXCSR \tWrite: %x\n",value); */
+ break;
+
+ case NEXTDMA_SCSI(NEXTDMA_NEXT):
+ next_state->dma[NEXTDMA_SCSI].next = value;
+ break;
+
+ case NEXTDMA_SCSI(NEXTDMA_LIMIT):
+ next_state->dma[NEXTDMA_SCSI].limit = value;
+ break;
+
+ case NEXTDMA_SCSI(NEXTDMA_START):
+ next_state->dma[NEXTDMA_SCSI].start = value;
+ break;
+
+ case NEXTDMA_SCSI(NEXTDMA_STOP):
+ next_state->dma[NEXTDMA_SCSI].stop = value;
+ break;
+
+ case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
+ next_state->dma[NEXTDMA_SCSI].next_initbuf = value;
+ break;
+
+ default:
+ DPRINTF("DMA write @ %x w/ %x\n", (unsigned)addr, (unsigned)value);
+ }
+}
+
+static uint64_t dma_readl(void *opaque, hwaddr addr, unsigned int size)
+{
+ NeXTState *next_state = NEXT_MACHINE(opaque);
+
+ switch (addr) {
+ case NEXTDMA_SCSI(NEXTDMA_CSR):
+ DPRINTF("SCSI DMA CSR READ\n");
+ return next_state->dma[NEXTDMA_SCSI].csr;
+ case NEXTDMA_ENRX(NEXTDMA_CSR):
+ return next_state->dma[NEXTDMA_ENRX].csr;
+ case NEXTDMA_ENRX(NEXTDMA_NEXT_INIT):
+ return next_state->dma[NEXTDMA_ENRX].next_initbuf;
+ case NEXTDMA_ENRX(NEXTDMA_NEXT):
+ return next_state->dma[NEXTDMA_ENRX].next;
+ case NEXTDMA_ENRX(NEXTDMA_LIMIT):
+ return next_state->dma[NEXTDMA_ENRX].limit;
+
+ case NEXTDMA_SCSI(NEXTDMA_NEXT):
+ return next_state->dma[NEXTDMA_SCSI].next;
+ case NEXTDMA_SCSI(NEXTDMA_NEXT_INIT):
+ return next_state->dma[NEXTDMA_SCSI].next_initbuf;
+ case NEXTDMA_SCSI(NEXTDMA_LIMIT):
+ return next_state->dma[NEXTDMA_SCSI].limit;
+ case NEXTDMA_SCSI(NEXTDMA_START):
+ return next_state->dma[NEXTDMA_SCSI].start;
+ case NEXTDMA_SCSI(NEXTDMA_STOP):
+ return next_state->dma[NEXTDMA_SCSI].stop;
+
+ default:
+ DPRINTF("DMA read @ %x\n", (unsigned int)addr);
+ return 0;
+ }
+
+ /*
+ * once the csr's are done, subtract 0x3FEC from the addr, and that will
+ * normalize the upper registers
+ */
+}
+
+static const MemoryRegionOps dma_ops = {
+ .read = dma_readl,
+ .write = dma_writel,
+ .impl.min_access_size = 4,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * TODO: set the shift numbers as values in the enum, so the first switch
+ * will not be needed
+ */
+void next_irq(void *opaque, int number, int level)
+{
+ M68kCPU *cpu = opaque;
+ int shift = 0;
+ NeXTState *ns = NEXT_MACHINE(qdev_get_machine());
+
+ /* first switch sets interupt status */
+ /* DPRINTF("IRQ %i\n",number); */
+ switch (number) {
+ /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
+ case NEXT_FD_I:
+ shift = 7;;
+ break;
+ case NEXT_KBD_I:
+ shift = 3;
+ break;
+ case NEXT_PWR_I:
+ shift = 2;
+ break;
+ case NEXT_ENRX_I:
+ shift = 9;
+ break;
+ case NEXT_ENTX_I:
+ shift = 10;
+ break;
+ case NEXT_SCSI_I:
+ shift = 12;
+ break;
+ case NEXT_CLK_I:
+ shift = 5;
+ break;
+
+ /* level 5 - scc (serial) */
+ case NEXT_SCC_I:
+ shift = 17;
+ break;
+
+ /* level 6 - audio etherrx/tx dma */
+ case NEXT_ENTX_DMA_I:
+ shift = 28;
+ break;
+ case NEXT_ENRX_DMA_I:
+ shift = 27;
+ break;
+ case NEXT_SCSI_DMA_I:
+ shift = 26;
+ break;
+ case NEXT_SND_I:
+ shift = 23;
+ break;
+ case NEXT_SCC_DMA_I:
+ shift = 21;
+ break;
+
+ }
+ /*
+ * this HAS to be wrong, the interrupt handlers in mach and together
+ * int_status and int_mask and return if there is a hit
+ */
+ if (ns->int_mask & (1 << shift)) {
+ DPRINTF("%x interrupt masked @ %x\n", 1 << shift, cpu->env.pc);
+ /* return; */
+ }
+
+ /* second switch triggers the correct interrupt */
+ if (level) {
+ ns->int_status |= 1 << shift;
+
+ switch (number) {
+ /* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
+ case NEXT_FD_I:
+ case NEXT_KBD_I:
+ case NEXT_PWR_I:
+ case NEXT_ENRX_I:
+ case NEXT_ENTX_I:
+ case NEXT_SCSI_I:
+ case NEXT_CLK_I:
+ m68k_set_irq_level(cpu, 3, 27);
+ break;
+
+ /* level 5 - scc (serial) */
+ case NEXT_SCC_I:
+ m68k_set_irq_level(cpu, 5, 29);
+ break;
+
+ /* level 6 - audio etherrx/tx dma */
+ case NEXT_ENTX_DMA_I:
+ case NEXT_ENRX_DMA_I:
+ case NEXT_SCSI_DMA_I:
+ case NEXT_SND_I:
+ case NEXT_SCC_DMA_I:
+ m68k_set_irq_level(cpu, 6, 30);
+ break;
+ }
+ } else {
+ ns->int_status &= ~(1 << shift);
+ cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
+ }
+}
+
+static void next_serial_irq(void *opaque, int n, int level)
+{
+ /* DPRINTF("SCC IRQ NUM %i\n",n); */
+ if (n) {
+ next_irq(opaque, NEXT_SCC_DMA_I, level);
+ } else {
+ next_irq(opaque, NEXT_SCC_I, level);
+ }
+}
+
+static void next_escc_init(M68kCPU *cpu)
+{
+ qemu_irq *ser_irq = qemu_allocate_irqs(next_serial_irq, cpu, 2);
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ dev = qdev_create(NULL, TYPE_ESCC);
+ qdev_prop_set_uint32(dev, "disabled", 0);
+ qdev_prop_set_uint32(dev, "frequency", 9600 * 384);
+ qdev_prop_set_uint32(dev, "it_shift", 0);
+ qdev_prop_set_bit(dev, "bit_swap", true);
+ qdev_prop_set_chr(dev, "chrB", serial_hd(1));
+ qdev_prop_set_chr(dev, "chrA", serial_hd(0));
+ qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
+ qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
+ qdev_init_nofail(dev);
+
+ s = SYS_BUS_DEVICE(dev);
+ sysbus_connect_irq(s, 0, ser_irq[0]);
+ sysbus_connect_irq(s, 1, ser_irq[1]);
+ sysbus_mmio_map(s, 0, 0x2118000);
+}
+
+static void next_cube_init(MachineState *machine)
+{
+ M68kCPU *cpu;
+ CPUM68KState *env;
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
+ MemoryRegion *rom = g_new(MemoryRegion, 1);
+ MemoryRegion *mmiomem = g_new(MemoryRegion, 1);
+ MemoryRegion *scrmem = g_new(MemoryRegion, 1);
+ MemoryRegion *dmamem = g_new(MemoryRegion, 1);
+ MemoryRegion *bmapm1 = g_new(MemoryRegion, 1);
+ MemoryRegion *bmapm2 = g_new(MemoryRegion, 1);
+ MemoryRegion *sysmem = get_system_memory();
+ NeXTState *ns = NEXT_MACHINE(machine);
+ DeviceState *dev;
+
+ /* Initialize the cpu core */
+ cpu = M68K_CPU(cpu_create(machine->cpu_type));
+ if (!cpu) {
+ error_report("Unable to find m68k CPU definition");
+ exit(1);
+ }
+ env = &cpu->env;
+
+ /* Initialize CPU registers. */
+ env->vbr = 0;
+ env->sr = 0x2700;
+
+ /* Set internal registers to initial values */
+ /* 0x0000XX00 << vital bits */
+ ns->scr1 = 0x00011102;
+ ns->scr2 = 0x00ff0c80;
+
+ /* Load RTC RAM - TODO: provide possibility to load contents from file */
+ memcpy(ns->rtc_ram, rtc_ram2, 32);
+
+ /* 64MB RAM starting at 0x04000000 */
+ memory_region_allocate_system_memory(ram, NULL, "next.ram", ram_size);
+ memory_region_add_subregion(sysmem, 0x04000000, ram);
+
+ /* Framebuffer */
+ dev = qdev_create(NULL, TYPE_NEXTFB);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0B000000);
+
+ /* MMIO */
+ memory_region_init_io(mmiomem, NULL, &mmio_ops, machine, "next.mmio",
+ 0xD0000);
+ memory_region_add_subregion(sysmem, 0x02000000, mmiomem);
+
+ /* BMAP memory */
+ memory_region_init_ram_shared_nomigrate(bmapm1, NULL, "next.bmapmem", 64,
+ true, &error_fatal);
+ memory_region_add_subregion(sysmem, 0x020c0000, bmapm1);
+ /* The Rev_2.5_v66.bin firmware accesses it at 0x820c0020, too */
+ memory_region_init_alias(bmapm2, NULL, "next.bmapmem2", bmapm1, 0x0, 64);
+ memory_region_add_subregion(sysmem, 0x820c0000, bmapm2);
+
+ /* BMAP IO - acts as a catch-all for now */
+ memory_region_init_io(scrmem, NULL, &scr_ops, machine, "next.scr",
+ 0x20000);
+ memory_region_add_subregion(sysmem, 0x02100000, scrmem);
+
+ /* KBD */
+ dev = qdev_create(NULL, TYPE_NEXTKBD);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x0200e000);
+
+ /* Load ROM here */
+ if (bios_name == NULL) {
+ bios_name = ROM_FILE;
+ }
+ /* still not sure if the rom should also be mapped at 0x0*/
+ memory_region_init_rom(rom, NULL, "next.rom", 0x20000, &error_fatal);
+ memory_region_add_subregion(sysmem, 0x01000000, rom);
+ if (load_image_targphys(bios_name, 0x01000000, 0x20000) < 8) {
+ if (!qtest_enabled()) {
+ error_report("Failed to load firmware '%s'.", bios_name);
+ }
+ } else {
+ uint8_t *ptr;
+ /* Initial PC is always at offset 4 in firmware binaries */
+ ptr = rom_ptr(0x01000004, 4);
+ g_assert(ptr != NULL);
+ env->pc = ldl_p(ptr);
+ if (env->pc >= 0x01020000) {
+ error_report("'%s' does not seem to be a valid firmware image.",
+ bios_name);
+ exit(1);
+ }
+ }
+
+ /* Serial */
+ next_escc_init(cpu);
+
+ /* TODO: */
+ /* Network */
+ /* SCSI */
+
+ /* DMA */
+ memory_region_init_io(dmamem, NULL, &dma_ops, machine, "next.dma", 0x5000);
+ memory_region_add_subregion(sysmem, 0x02000000, dmamem);
+}
+
+static void next_machine_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "NeXT Cube";
+ mc->init = next_cube_init;
+ mc->default_ram_size = RAM_SIZE;
+ mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
+}
+
+static const TypeInfo next_typeinfo = {
+ .name = TYPE_NEXT_MACHINE,
+ .parent = TYPE_MACHINE,
+ .class_init = next_machine_class_init,
+ .instance_size = sizeof(NeXTState),
+};
+
+static void next_register_type(void)
+{
+ type_register_static(&next_typeinfo);
+}
+
+type_init(next_register_type)
diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
new file mode 100644
index 0000000000..2dff87be15
--- /dev/null
+++ b/hw/m68k/next-kbd.c
@@ -0,0 +1,291 @@
+/*
+ * QEMU NeXT Keyboard/Mouse emulation
+ *
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * This is admittedly hackish, but works well enough for basic input. Mouse
+ * support will be added once we can boot something that needs the mouse.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "exec/address-spaces.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/m68k/next-cube.h"
+#include "ui/console.h"
+#include "sysemu/sysemu.h"
+#include "migration/vmstate.h"
+
+#define NEXTKBD(obj) OBJECT_CHECK(NextKBDState, (obj), TYPE_NEXTKBD)
+
+/* following defintions from next68k netbsd */
+#define CSR_INT 0x00800000
+#define CSR_DATA 0x00400000
+
+#define KD_KEYMASK 0x007f
+#define KD_DIRECTION 0x0080 /* pressed or released */
+#define KD_CNTL 0x0100
+#define KD_LSHIFT 0x0200
+#define KD_RSHIFT 0x0400
+#define KD_LCOMM 0x0800
+#define KD_RCOMM 0x1000
+#define KD_LALT 0x2000
+#define KD_RALT 0x4000
+#define KD_VALID 0x8000 /* only set for scancode keys ? */
+#define KD_MODS 0x4f00
+
+#define KBD_QUEUE_SIZE 256
+
+typedef struct {
+ uint8_t data[KBD_QUEUE_SIZE];
+ int rptr, wptr, count;
+} KBDQueue;
+
+
+typedef struct NextKBDState {
+ SysBusDevice sbd;
+ MemoryRegion mr;
+ KBDQueue queue;
+ uint16_t shift;
+} NextKBDState;
+
+static void queue_code(void *opaque, int code);
+
+/* lots of magic numbers here */
+static uint32_t kbd_read_byte(void *opaque, hwaddr addr)
+{
+ switch (addr & 0x3) {
+ case 0x0: /* 0xe000 */
+ return 0x80 | 0x20;
+
+ case 0x1: /* 0xe001 */
+ return 0x80 | 0x40 | 0x20 | 0x10;
+
+ case 0x2: /* 0xe002 */
+ /* returning 0x40 caused mach to hang */
+ return 0x10 | 0x2 | 0x1;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "NeXT kbd read byte %"HWADDR_PRIx"\n", addr);
+ }
+
+ return 0;
+}
+
+static uint32_t kbd_read_word(void *opaque, hwaddr addr)
+{
+ qemu_log_mask(LOG_UNIMP, "NeXT kbd read word %"HWADDR_PRIx"\n", addr);
+ return 0;
+}
+
+/* even more magic numbers */
+static uint32_t kbd_read_long(void *opaque, hwaddr addr)
+{
+ int key = 0;
+ NextKBDState *s = NEXTKBD(opaque);
+ KBDQueue *q = &s->queue;
+
+ switch (addr & 0xf) {
+ case 0x0: /* 0xe000 */
+ return 0xA0F09300;
+
+ case 0x8: /* 0xe008 */
+ /* get keycode from buffer */
+ if (q->count > 0) {
+ key = q->data[q->rptr];
+ if (++q->rptr == KBD_QUEUE_SIZE) {
+ q->rptr = 0;
+ }
+
+ q->count--;
+
+ if (s->shift) {
+ key |= s->shift;
+ }
+
+ if (key & 0x80) {
+ return 0;
+ } else {
+ return 0x10000000 | KD_VALID | key;
+ }
+ } else {
+ return 0;
+ }
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "NeXT kbd read long %"HWADDR_PRIx"\n", addr);
+ return 0;
+ }
+}
+
+static uint64_t kbd_readfn(void *opaque, hwaddr addr, unsigned size)
+{
+ switch (size) {
+ case 1:
+ return kbd_read_byte(opaque, addr);
+ case 2:
+ return kbd_read_word(opaque, addr);
+ case 4:
+ return kbd_read_long(opaque, addr);
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void kbd_writefn(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ qemu_log_mask(LOG_UNIMP, "NeXT kbd write: size=%u addr=0x%"HWADDR_PRIx
+ "val=0x%"PRIx64"\n", size, addr, value);
+}
+
+static const MemoryRegionOps kbd_ops = {
+ .read = kbd_readfn,
+ .write = kbd_writefn,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void nextkbd_event(void *opaque, int ch)
+{
+ /*
+ * Will want to set vars for caps/num lock
+ * if (ch & 0x80) -> key release
+ * there's also e0 escaped scancodes that might need to be handled
+ */
+ queue_code(opaque, ch);
+}
+
+static const unsigned char next_keycodes[128] = {
+ 0x00, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F,
+ 0x4E, 0x1E, 0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0x00,
+ 0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06,
+ 0x07, 0x08, 0x00, 0x00, 0x2A, 0x00, 0x39, 0x3A,
+ 0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C,
+ 0x2B, 0x26, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34,
+ 0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static void queue_code(void *opaque, int code)
+{
+ NextKBDState *s = NEXTKBD(opaque);
+ KBDQueue *q = &s->queue;
+ int key = code & KD_KEYMASK;
+ int release = code & 0x80;
+ static int ext;
+
+ if (code == 0xE0) {
+ ext = 1;
+ }
+
+ if (code == 0x2A || code == 0x1D || code == 0x36) {
+ if (code == 0x2A) {
+ s->shift = KD_LSHIFT;
+ } else if (code == 0x36) {
+ s->shift = KD_RSHIFT;
+ ext = 0;
+ } else if (code == 0x1D && !ext) {
+ s->shift = KD_LCOMM;
+ } else if (code == 0x1D && ext) {
+ ext = 0;
+ s->shift = KD_RCOMM;
+ }
+ return;
+ } else if (code == (0x2A | 0x80) || code == (0x1D | 0x80) ||
+ code == (0x36 | 0x80)) {
+ s->shift = 0;
+ return;
+ }
+
+ if (q->count >= KBD_QUEUE_SIZE) {
+ return;
+ }
+
+ q->data[q->wptr] = next_keycodes[key] | release;
+
+ if (++q->wptr == KBD_QUEUE_SIZE) {
+ q->wptr = 0;
+ }
+
+ q->count++;
+
+ /*
+ * might need to actually trigger the NeXT irq, but as the keyboard works
+ * at the moment, I'll worry about it later
+ */
+ /* s->update_irq(s->update_arg, 1); */
+}
+
+static void nextkbd_reset(DeviceState *dev)
+{
+ NextKBDState *nks = NEXTKBD(dev);
+
+ memset(&nks->queue, 0, sizeof(KBDQueue));
+ nks->shift = 0;
+}
+
+static void nextkbd_realize(DeviceState *dev, Error **errp)
+{
+ NextKBDState *s = NEXTKBD(dev);
+
+ memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
+
+ qemu_add_kbd_event_handler(nextkbd_event, s);
+}
+
+static const VMStateDescription nextkbd_vmstate = {
+ .name = TYPE_NEXTKBD,
+ .unmigratable = 1, /* TODO: Implement this when m68k CPU is migratable */
+};
+
+static void nextkbd_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+ dc->vmsd = &nextkbd_vmstate;
+ dc->realize = nextkbd_realize;
+ dc->reset = nextkbd_reset;
+}
+
+static const TypeInfo nextkbd_info = {
+ .name = TYPE_NEXTKBD,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NextKBDState),
+ .class_init = nextkbd_class_init,
+};
+
+static void nextkbd_register_types(void)
+{
+ type_register_static(&nextkbd_info);
+}
+
+type_init(nextkbd_register_types)
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 7c324a1329..99e2faf01b 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -172,6 +172,8 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
{
PCDIMMDevice *dimm = PC_DIMM(dev);
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
+ MachineState *ms = MACHINE(qdev_get_machine());
+ int nb_numa_nodes = ms->numa_state->num_nodes;
if (!dimm->hostmem) {
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index e4aad707fb..a150680966 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -26,57 +26,57 @@ common-obj-$(CONFIG_PUV3) += puv3_pm.o
common-obj-$(CONFIG_MACIO) += macio/
-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
+common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
-obj-$(CONFIG_NSERIES) += cbus.o
-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
-obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o exynos4210_clk.o exynos4210_rng.o
-obj-$(CONFIG_IMX) += imx_ccm.o
-obj-$(CONFIG_IMX) += imx31_ccm.o
-obj-$(CONFIG_IMX) += imx25_ccm.o
-obj-$(CONFIG_IMX) += imx6_ccm.o
-obj-$(CONFIG_IMX) += imx6ul_ccm.o
+common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
+common-obj-$(CONFIG_NSERIES) += cbus.o
+common-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
+common-obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o exynos4210_clk.o exynos4210_rng.o
+common-obj-$(CONFIG_IMX) += imx_ccm.o
+common-obj-$(CONFIG_IMX) += imx31_ccm.o
+common-obj-$(CONFIG_IMX) += imx25_ccm.o
+common-obj-$(CONFIG_IMX) += imx6_ccm.o
+common-obj-$(CONFIG_IMX) += imx6ul_ccm.o
obj-$(CONFIG_IMX) += imx6_src.o
-obj-$(CONFIG_IMX) += imx7_ccm.o
-obj-$(CONFIG_IMX) += imx2_wdt.o
-obj-$(CONFIG_IMX) += imx7_snvs.o
-obj-$(CONFIG_IMX) += imx7_gpr.o
-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
-obj-$(CONFIG_MAINSTONE) += mst_fpga.o
-obj-$(CONFIG_OMAP) += omap_clk.o
-obj-$(CONFIG_OMAP) += omap_gpmc.o
-obj-$(CONFIG_OMAP) += omap_l4.o
-obj-$(CONFIG_OMAP) += omap_sdrc.o
-obj-$(CONFIG_OMAP) += omap_tap.o
-obj-$(CONFIG_RASPI) += bcm2835_mbox.o
-obj-$(CONFIG_RASPI) += bcm2835_property.o
-obj-$(CONFIG_RASPI) += bcm2835_rng.o
-obj-$(CONFIG_SLAVIO) += slavio_misc.o
-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
-obj-$(CONFIG_ZYNQ) += zynq-xadc.o
-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
+common-obj-$(CONFIG_IMX) += imx7_ccm.o
+common-obj-$(CONFIG_IMX) += imx2_wdt.o
+common-obj-$(CONFIG_IMX) += imx7_snvs.o
+common-obj-$(CONFIG_IMX) += imx7_gpr.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
+common-obj-$(CONFIG_MAINSTONE) += mst_fpga.o
+common-obj-$(CONFIG_OMAP) += omap_clk.o
+common-obj-$(CONFIG_OMAP) += omap_gpmc.o
+common-obj-$(CONFIG_OMAP) += omap_l4.o
+common-obj-$(CONFIG_OMAP) += omap_sdrc.o
+common-obj-$(CONFIG_OMAP) += omap_tap.o
+common-obj-$(CONFIG_RASPI) += bcm2835_mbox.o
+common-obj-$(CONFIG_RASPI) += bcm2835_property.o
+common-obj-$(CONFIG_RASPI) += bcm2835_rng.o
+common-obj-$(CONFIG_SLAVIO) += slavio_misc.o
+common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
+common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o
+common-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o
obj-$(CONFIG_MIPS_CPS) += mips_cpc.o
obj-$(CONFIG_MIPS_ITU) += mips_itu.o
-obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
-obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
+common-obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
+common-obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
-obj-$(CONFIG_TZ_MPC) += tz-mpc.o
-obj-$(CONFIG_TZ_MSC) += tz-msc.o
-obj-$(CONFIG_TZ_PPC) += tz-ppc.o
-obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
+common-obj-$(CONFIG_TZ_MPC) += tz-mpc.o
+common-obj-$(CONFIG_TZ_MSC) += tz-msc.o
+common-obj-$(CONFIG_TZ_PPC) += tz-ppc.o
+common-obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
-obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o
-obj-$(CONFIG_ARMSSE_CPUID) += armsse-cpuid.o
-obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o
+common-obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o
+common-obj-$(CONFIG_ARMSSE_CPUID) += armsse-cpuid.o
+common-obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o
-obj-$(CONFIG_PVPANIC) += pvpanic.o
-obj-$(CONFIG_AUX) += auxbus.o
-obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o
-obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
-obj-$(CONFIG_MSF2) += msf2-sysreg.o
-obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
+common-obj-$(CONFIG_PVPANIC) += pvpanic.o
+common-obj-$(CONFIG_AUX) += auxbus.o
+common-obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o
+common-obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
+common-obj-$(CONFIG_MSF2) += msf2-sysreg.o
+common-obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
-obj-$(CONFIG_GRLIB) += grlib_ahb_apb_pnp.o
+common-obj-$(CONFIG_GRLIB) += grlib_ahb_apb_pnp.o
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index d8716a1f73..2c8c065401 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -994,15 +994,14 @@ static void xilinx_enet_init(Object *obj)
XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
- TYPE_XILINX_AXI_ENET_DATA_STREAM);
- object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
- TYPE_XILINX_AXI_ENET_CONTROL_STREAM);
- object_property_add_child(OBJECT(s), "axistream-connected-target",
- (Object *)&s->rx_data_dev, &error_abort);
- object_property_add_child(OBJECT(s), "axistream-control-connected-target",
- (Object *)&s->rx_control_dev, &error_abort);
-
+ object_initialize_child(OBJECT(s), "axistream-connected-target",
+ &s->rx_data_dev, sizeof(s->rx_data_dev),
+ TYPE_XILINX_AXI_ENET_DATA_STREAM, &error_abort,
+ NULL);
+ object_initialize_child(OBJECT(s), "axistream-control-connected-target",
+ &s->rx_control_dev, sizeof(s->rx_control_dev),
+ TYPE_XILINX_AXI_ENET_CONTROL_STREAM, &error_abort,
+ NULL);
sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000);
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 06a7c018d7..0592818447 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -21,6 +21,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "sysemu/numa.h"
+#include "hw/boards.h"
#define TYPE_PXB_BUS "pxb-bus"
#define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)
@@ -213,9 +214,15 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp)
PCIBus *bus;
const char *dev_name = NULL;
Error *local_err = NULL;
+ MachineState *ms = MACHINE(qdev_get_machine());
+
+ if (ms->numa_state == NULL) {
+ error_setg(errp, "NUMA is not supported by this machine-type");
+ return;
+ }
if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
- pxb->numa_node >= nb_numa_nodes) {
+ pxb->numa_node >= ms->numa_state->num_nodes) {
error_setg(errp, "Illegal numa node %d", pxb->numa_node);
return;
}
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index d95086fbbd..3f08db7b9e 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -434,9 +434,14 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
.fdt = fdt,
.offset = isa_offset,
};
+ uint32_t phandle;
_FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
+ phandle = qemu_fdt_alloc_phandle(fdt);
+ assert(phandle > 0);
+ _FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle)));
+
/* ISA devices are not necessarily parented to the ISA bus so we
* can not use object_child_foreach() */
qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
@@ -600,9 +605,20 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
pnv_psi_pic_print_info(&chip9->psi, mon);
}
+static bool pnv_match_cpu(const char *default_type, const char *cpu_type)
+{
+ PowerPCCPUClass *ppc_default =
+ POWERPC_CPU_CLASS(object_class_by_name(default_type));
+ PowerPCCPUClass *ppc =
+ POWERPC_CPU_CLASS(object_class_by_name(cpu_type));
+
+ return ppc_default->pvr_match(ppc_default, ppc->pvr);
+}
+
static void pnv_init(MachineState *machine)
{
PnvMachineState *pnv = PNV_MACHINE(machine);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
MemoryRegion *ram;
char *fw_filename;
long fw_size;
@@ -662,13 +678,23 @@ static void pnv_init(MachineState *machine)
}
}
+ /*
+ * Check compatibility of the specified CPU with the machine
+ * default.
+ */
+ if (!pnv_match_cpu(mc->default_cpu_type, machine->cpu_type)) {
+ error_report("invalid CPU model '%s' for %s machine",
+ machine->cpu_type, mc->name);
+ exit(1);
+ }
+
/* Create the processor chips */
i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
i, machine->cpu_type);
if (!object_class_by_name(chip_typename)) {
- error_report("invalid CPU model '%.*s' for %s machine",
- i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name);
+ error_report("invalid chip model '%.*s' for %s machine",
+ i, machine->cpu_type, mc->name);
exit(1);
}
@@ -1346,25 +1372,47 @@ static void pnv_machine_class_props_init(ObjectClass *oc)
NULL);
}
-static void pnv_machine_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
+
+ mc->desc = "IBM PowerNV (Non-Virtualized) POWER8";
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
+
+ xic->icp_get = pnv_icp_get;
+ xic->ics_get = pnv_ics_get;
+ xic->ics_resend = pnv_ics_resend;
+}
+
+static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "IBM PowerNV (Non-Virtualized) POWER9";
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
+
+ mc->alias = "powernv";
+}
+
+static void pnv_machine_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
mc->desc = "IBM PowerNV (Non-Virtualized)";
mc->init = pnv_init;
mc->reset = pnv_reset;
mc->max_cpus = MAX_CPUS;
- mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
* storage */
mc->no_parallel = 1;
mc->default_boot_order = NULL;
- mc->default_ram_size = 1 * GiB;
- xic->icp_get = pnv_icp_get;
- xic->ics_get = pnv_ics_get;
- xic->ics_resend = pnv_ics_resend;
+ /*
+ * RAM defaults to less than 2048 for 32-bit hosts, and large
+ * enough to fit the maximum initrd size at it's load address
+ */
+ mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE;
ispc->print_info = pnv_pic_print_info;
pnv_machine_class_props_init(oc);
@@ -1384,10 +1432,27 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
.parent = TYPE_PNV9_CHIP, \
}
+#define DEFINE_PNV_MACHINE_TYPE(cpu, class_initfn) \
+ { \
+ .name = MACHINE_TYPE_NAME(cpu), \
+ .parent = TYPE_PNV_MACHINE, \
+ .instance_size = sizeof(PnvMachineState), \
+ .instance_init = pnv_machine_instance_init, \
+ .class_init = class_initfn, \
+ .interfaces = (InterfaceInfo[]) { \
+ { TYPE_XICS_FABRIC }, \
+ { TYPE_INTERRUPT_STATS_PROVIDER }, \
+ { }, \
+ }, \
+ }
+
static const TypeInfo types[] = {
+ DEFINE_PNV_MACHINE_TYPE("powernv8", pnv_machine_power8_class_init),
+ DEFINE_PNV_MACHINE_TYPE("powernv9", pnv_machine_power9_class_init),
{
.name = TYPE_PNV_MACHINE,
.parent = TYPE_MACHINE,
+ .abstract = true,
.instance_size = sizeof(PnvMachineState),
.instance_init = pnv_machine_instance_init,
.class_init = pnv_machine_class_init,
diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
index 0e31c5786b..67aab98fef 100644
--- a/hw/ppc/pnv_xscom.c
+++ b/hw/ppc/pnv_xscom.c
@@ -106,6 +106,16 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
case 0x201302a: /* CAPP stuff */
case 0x2013801: /* CAPP stuff */
case 0x2013802: /* CAPP stuff */
+
+ /* P9 CAPP regs */
+ case 0x2010841:
+ case 0x2010842:
+ case 0x201082a:
+ case 0x2010828:
+ case 0x4010841:
+ case 0x4010842:
+ case 0x401082a:
+ case 0x4010828:
return 0;
default:
return -1;
@@ -138,6 +148,16 @@ static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val)
case 0x2013801: /* CAPP stuff */
case 0x2013802: /* CAPP stuff */
+ /* P9 CAPP regs */
+ case 0x2010841:
+ case 0x2010842:
+ case 0x201082a:
+ case 0x2010828:
+ case 0x4010841:
+ case 0x4010842:
+ case 0x401082a:
+ case 0x4010828:
+
/* P8 PRD registers */
case PRD_P8_IPOLL_REG_MASK:
case PRD_P8_IPOLL_REG_STATUS:
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index baedadf20b..222a325056 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -336,7 +336,7 @@ static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr)
return ret;
}
- if (nb_numa_nodes > 1) {
+ if (ms->numa_state->num_nodes > 1) {
ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu);
if (ret < 0) {
return ret;
@@ -356,11 +356,11 @@ static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr)
static hwaddr spapr_node0_size(MachineState *machine)
{
- if (nb_numa_nodes) {
+ if (machine->numa_state->num_nodes) {
int i;
- for (i = 0; i < nb_numa_nodes; ++i) {
- if (numa_info[i].node_mem) {
- return MIN(pow2floor(numa_info[i].node_mem),
+ for (i = 0; i < machine->numa_state->num_nodes; ++i) {
+ if (machine->numa_state->nodes[i].node_mem) {
+ return MIN(pow2floor(machine->numa_state->nodes[i].node_mem),
machine->ram_size);
}
}
@@ -403,12 +403,12 @@ static int spapr_populate_memory(SpaprMachineState *spapr, void *fdt)
{
MachineState *machine = MACHINE(spapr);
hwaddr mem_start, node_size;
- int i, nb_nodes = nb_numa_nodes;
- NodeInfo *nodes = numa_info;
+ int i, nb_nodes = machine->numa_state->num_nodes;
+ NodeInfo *nodes = machine->numa_state->nodes;
NodeInfo ramnode;
/* No NUMA nodes, assume there is just one node with whole RAM */
- if (!nb_numa_nodes) {
+ if (!nb_nodes) {
nb_nodes = 1;
ramnode.node_mem = machine->ram_size;
nodes = &ramnode;
@@ -559,7 +559,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
_FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
pft_size_prop, sizeof(pft_size_prop))));
- if (nb_numa_nodes > 1) {
+ if (ms->numa_state->num_nodes > 1) {
_FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
}
@@ -866,6 +866,7 @@ static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt,
static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
{
MachineState *machine = MACHINE(spapr);
+ int nb_numa_nodes = machine->numa_state->num_nodes;
int ret, i, offset;
uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
@@ -1168,6 +1169,7 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
{
MachineState *machine = MACHINE(spapr);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
int chosen;
const char *boot_device = machine->boot_order;
char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
@@ -1225,6 +1227,11 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
_FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
}
+ /* We can deal with BAR reallocation just fine, advertise it to the guest */
+ if (smc->linux_pci_probe) {
+ _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
+ }
+
spapr_dt_ov5_platform_support(spapr, fdt, chosen);
g_free(stdout_path);
@@ -1741,7 +1748,7 @@ static void spapr_machine_reset(MachineState *machine)
* The final value of spapr->gpu_numa_id is going to be written to
* max-associativity-domains in spapr_build_fdt().
*/
- spapr->gpu_numa_id = MAX(1, nb_numa_nodes);
+ spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
qemu_devices_reset();
/*
@@ -1752,7 +1759,7 @@ static void spapr_machine_reset(MachineState *machine)
spapr_ovec_cleanup(spapr->ov5_cas);
spapr->ov5_cas = spapr_ovec_new();
- ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal);
+ ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
}
/*
@@ -2539,12 +2546,12 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp)
return;
}
- for (i = 0; i < nb_numa_nodes; i++) {
- if (numa_info[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
+ for (i = 0; i < machine->numa_state->num_nodes; i++) {
+ if (machine->numa_state->nodes[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
error_setg(errp,
"Node %d memory size 0x%" PRIx64
" is not aligned to %" PRIu64 " MiB",
- i, numa_info[i].node_mem,
+ i, machine->numa_state->nodes[i].node_mem,
SPAPR_MEMORY_BLOCK_SIZE / MiB);
return;
}
@@ -3829,6 +3836,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
CPUArchId *core_slot;
int index;
bool hotplugged = spapr_drc_hotplugged(dev);
+ int i;
core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
if (!core_slot) {
@@ -3862,13 +3870,26 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
core_slot->cpu = OBJECT(dev);
if (smc->pre_2_10_has_unused_icps) {
- int i;
-
for (i = 0; i < cc->nr_threads; i++) {
cs = CPU(core->threads[i]);
pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
}
}
+
+ /*
+ * Set compatibility mode to match the boot CPU, which was either set
+ * by the machine reset code or by CAS.
+ */
+ if (hotplugged) {
+ for (i = 0; i < cc->nr_threads; i++) {
+ ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+ }
}
static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
@@ -4178,7 +4199,7 @@ spapr_cpu_index_to_props(MachineState *machine, unsigned cpu_index)
static int64_t spapr_get_default_cpu_node_id(const MachineState *ms, int idx)
{
- return idx / ms->smp.cores % nb_numa_nodes;
+ return idx / ms->smp.cores % ms->numa_state->num_nodes;
}
static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
@@ -4470,6 +4491,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
spapr_caps_add_properties(smc, &error_abort);
smc->irq = &spapr_irq_dual;
smc->dr_phb_enabled = true;
+ smc->linux_pci_probe = true;
}
static const TypeInfo spapr_machine_info = {
@@ -4529,12 +4551,14 @@ DEFINE_SPAPR_MACHINE(4_2, "4.2", true);
*/
static void spapr_machine_4_1_class_options(MachineClass *mc)
{
+ SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
static GlobalProperty compat[] = {
/* Only allow 4kiB and 64kiB IOMMU pagesizes */
{ TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
};
spapr_machine_4_2_class_options(mc);
+ smc->linux_pci_probe = false;
compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index bf47fbdf6f..1d93de8161 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -41,11 +41,6 @@ static void spapr_cpu_reset(void *opaque)
* using an RTAS call */
cs->halted = 1;
- /* Set compatibility mode to match the boot CPU, which was either set
- * by the machine reset code or by CAS. This should never fail.
- */
- ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &error_abort);
-
env->spr[SPR_HIOR] = 0;
lpcr = env->spr[SPR_LPCR];
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index e20a946b99..23e4bdb829 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1811,7 +1811,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
spapr_ovec_cleanup(ov5_updates);
if (spapr->cas_reboot) {
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET);
}
return H_SUCCESS;
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index deb0b0c80c..7b71ad7c74 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -280,7 +280,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
unsigned int irq, max_irqs = 0;
SpaprPhbState *phb = NULL;
PCIDevice *pdev = NULL;
- spapr_pci_msi *msi;
+ SpaprPciMsi *msi;
int *config_addr_key;
Error *err = NULL;
int i;
@@ -328,7 +328,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
return;
}
- msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);
+ msi = (SpaprPciMsi *) g_hash_table_lookup(phb->msi, &config_addr);
/* Releasing MSIs */
if (!req_num) {
@@ -415,7 +415,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
irq, req_num);
/* Add MSI device to cache */
- msi = g_new(spapr_pci_msi, 1);
+ msi = g_new(SpaprPciMsi, 1);
msi->first_irq = irq;
msi->num = req_num;
config_addr_key = g_new(int, 1);
@@ -446,7 +446,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
SpaprPhbState *phb = NULL;
PCIDevice *pdev = NULL;
- spapr_pci_msi *msi;
+ SpaprPciMsi *msi;
/* Find SpaprPhbState */
phb = spapr_pci_find_phb(spapr, buid);
@@ -459,7 +459,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
}
/* Find device descriptor and start IRQ */
- msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr);
+ msi = (SpaprPciMsi *) g_hash_table_lookup(phb->msi, &config_addr);
if (!msi || !msi->first_irq || !msi->num || (ioa_intr_num >= msi->num)) {
trace_spapr_pci_msi("Failed to return vector", config_addr);
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
@@ -1700,11 +1700,13 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
state = func_drck->dr_entity_sense(func_drc);
if (state == SPAPR_DR_ENTITY_SENSE_PRESENT
&& !spapr_drc_unplug_requested(func_drc)) {
- error_setg(errp,
- "PCI: slot %d, function %d still present. "
- "Must unplug all non-0 functions first.",
- slotnr, i);
- return;
+ /*
+ * Attempting to remove function 0 of a multifunction
+ * device will will cascade into removing all child
+ * functions, even if their unplug weren't requested
+ * beforehand.
+ */
+ spapr_drc_detach(func_drc);
}
}
}
@@ -1804,7 +1806,7 @@ static void spapr_phb_destroy_msi(gpointer opaque)
{
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
- spapr_pci_msi *msi = opaque;
+ SpaprPciMsi *msi = opaque;
if (!smc->legacy_irq_allocation) {
spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
@@ -1825,6 +1827,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
SysBusDevice *s = SYS_BUS_DEVICE(dev);
SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
PCIHostState *phb = PCI_HOST_BRIDGE(s);
+ MachineState *ms = MACHINE(spapr);
char *namebuf;
int i;
PCIBus *bus;
@@ -1877,7 +1880,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
}
if (sphb->numa_node != -1 &&
- (sphb->numa_node >= MAX_NODES || !numa_info[sphb->numa_node].present)) {
+ (sphb->numa_node >= MAX_NODES ||
+ !ms->numa_state->nodes[sphb->numa_node].present)) {
error_setg(errp, "Invalid NUMA node ID for PCI host bridge");
return;
}
@@ -2118,7 +2122,7 @@ static const VMStateDescription vmstate_spapr_pci_lsi = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_UINT32_EQUAL(irq, struct spapr_pci_lsi, NULL),
+ VMSTATE_UINT32_EQUAL(irq, SpaprPciLsi, NULL),
VMSTATE_END_OF_LIST()
},
@@ -2129,9 +2133,9 @@ static const VMStateDescription vmstate_spapr_pci_msi = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField []) {
- VMSTATE_UINT32(key, spapr_pci_msi_mig),
- VMSTATE_UINT32(value.first_irq, spapr_pci_msi_mig),
- VMSTATE_UINT32(value.num, spapr_pci_msi_mig),
+ VMSTATE_UINT32(key, SpaprPciMsiMig),
+ VMSTATE_UINT32(value.first_irq, SpaprPciMsiMig),
+ VMSTATE_UINT32(value.num, SpaprPciMsiMig),
VMSTATE_END_OF_LIST()
},
};
@@ -2163,12 +2167,12 @@ static int spapr_pci_pre_save(void *opaque)
if (!sphb->msi_devs_num) {
return 0;
}
- sphb->msi_devs = g_new(spapr_pci_msi_mig, sphb->msi_devs_num);
+ sphb->msi_devs = g_new(SpaprPciMsiMig, sphb->msi_devs_num);
g_hash_table_iter_init(&iter, sphb->msi);
for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
sphb->msi_devs[i].key = *(uint32_t *) key;
- sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
+ sphb->msi_devs[i].value = *(SpaprPciMsi *) value;
}
return 0;
@@ -2215,10 +2219,10 @@ static const VMStateDescription vmstate_spapr_pci = {
VMSTATE_UINT64_TEST(mig_io_win_addr, SpaprPhbState, pre_2_8_migration),
VMSTATE_UINT64_TEST(mig_io_win_size, SpaprPhbState, pre_2_8_migration),
VMSTATE_STRUCT_ARRAY(lsi_table, SpaprPhbState, PCI_NUM_PINS, 0,
- vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
+ vmstate_spapr_pci_lsi, SpaprPciLsi),
VMSTATE_INT32(msi_devs_num, SpaprPhbState),
VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, SpaprPhbState, msi_devs_num, 0,
- vmstate_spapr_pci_msi, spapr_pci_msi_mig),
+ vmstate_spapr_pci_msi, SpaprPciMsiMig),
VMSTATE_END_OF_LIST()
},
};
diff --git a/hw/ppc/spapr_pci_nvlink2.c b/hw/ppc/spapr_pci_nvlink2.c
index eda8c752aa..4aa89ede23 100644
--- a/hw/ppc/spapr_pci_nvlink2.c
+++ b/hw/ppc/spapr_pci_nvlink2.c
@@ -39,11 +39,7 @@
#define SPAPR_GPU_NUMA_ID (cpu_to_be32(1))
-struct spapr_phb_pci_nvgpu_config {
- uint64_t nv2_ram_current;
- uint64_t nv2_atsd_current;
- int num; /* number of non empty (i.e. tgt!=0) entries in slots[] */
- struct spapr_phb_pci_nvgpu_slot {
+typedef struct SpaprPhbPciNvGpuSlot {
uint64_t tgt;
uint64_t gpa;
unsigned numa_id;
@@ -54,12 +50,18 @@ struct spapr_phb_pci_nvgpu_config {
PCIDevice *npdev;
uint32_t link_speed;
} links[NVGPU_MAX_LINKS];
- } slots[NVGPU_MAX_NUM];
+} SpaprPhbPciNvGpuSlot;
+
+struct SpaprPhbPciNvGpuConfig {
+ uint64_t nv2_ram_current;
+ uint64_t nv2_atsd_current;
+ int num; /* number of non empty (i.e. tgt!=0) entries in slots[] */
+ SpaprPhbPciNvGpuSlot slots[NVGPU_MAX_NUM];
Error *errp;
};
-static struct spapr_phb_pci_nvgpu_slot *
-spapr_nvgpu_get_slot(struct spapr_phb_pci_nvgpu_config *nvgpus, uint64_t tgt)
+static SpaprPhbPciNvGpuSlot *
+spapr_nvgpu_get_slot(SpaprPhbPciNvGpuConfig *nvgpus, uint64_t tgt)
{
int i;
@@ -81,13 +83,13 @@ spapr_nvgpu_get_slot(struct spapr_phb_pci_nvgpu_config *nvgpus, uint64_t tgt)
return &nvgpus->slots[i];
}
-static void spapr_pci_collect_nvgpu(struct spapr_phb_pci_nvgpu_config *nvgpus,
+static void spapr_pci_collect_nvgpu(SpaprPhbPciNvGpuConfig *nvgpus,
PCIDevice *pdev, uint64_t tgt,
MemoryRegion *mr, Error **errp)
{
MachineState *machine = MACHINE(qdev_get_machine());
SpaprMachineState *spapr = SPAPR_MACHINE(machine);
- struct spapr_phb_pci_nvgpu_slot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt);
+ SpaprPhbPciNvGpuSlot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt);
if (!nvslot) {
error_setg(errp, "Found too many GPUs per vPHB");
@@ -102,11 +104,11 @@ static void spapr_pci_collect_nvgpu(struct spapr_phb_pci_nvgpu_config *nvgpus,
++spapr->gpu_numa_id;
}
-static void spapr_pci_collect_nvnpu(struct spapr_phb_pci_nvgpu_config *nvgpus,
+static void spapr_pci_collect_nvnpu(SpaprPhbPciNvGpuConfig *nvgpus,
PCIDevice *pdev, uint64_t tgt,
MemoryRegion *mr, Error **errp)
{
- struct spapr_phb_pci_nvgpu_slot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt);
+ SpaprPhbPciNvGpuSlot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt);
int j;
if (!nvslot) {
@@ -138,7 +140,7 @@ static void spapr_phb_pci_collect_nvgpu(PCIBus *bus, PCIDevice *pdev,
if (tgt) {
Error *local_err = NULL;
- struct spapr_phb_pci_nvgpu_config *nvgpus = opaque;
+ SpaprPhbPciNvGpuConfig *nvgpus = opaque;
Object *mr_gpu = object_property_get_link(po, "nvlink2-mr[0]", NULL);
Object *mr_npu = object_property_get_link(po, "nvlink2-atsd-mr[0]",
NULL);
@@ -177,7 +179,7 @@ void spapr_phb_nvgpu_setup(SpaprPhbState *sphb, Error **errp)
return;
}
- sphb->nvgpus = g_new0(struct spapr_phb_pci_nvgpu_config, 1);
+ sphb->nvgpus = g_new0(SpaprPhbPciNvGpuConfig, 1);
sphb->nvgpus->nv2_ram_current = sphb->nv2_gpa_win_addr;
sphb->nvgpus->nv2_atsd_current = sphb->nv2_atsd_win_addr;
@@ -194,7 +196,7 @@ void spapr_phb_nvgpu_setup(SpaprPhbState *sphb, Error **errp)
/* Add found GPU RAM and ATSD MRs if found */
for (i = 0, valid_gpu_num = 0; i < sphb->nvgpus->num; ++i) {
Object *nvmrobj;
- struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i];
+ SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
if (!nvslot->gpdev) {
continue;
@@ -242,7 +244,7 @@ void spapr_phb_nvgpu_free(SpaprPhbState *sphb)
}
for (i = 0; i < sphb->nvgpus->num; ++i) {
- struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i];
+ SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev),
"nvlink2-mr[0]", NULL);
@@ -276,7 +278,7 @@ void spapr_phb_nvgpu_populate_dt(SpaprPhbState *sphb, void *fdt, int bus_off,
}
for (i = 0; (i < sphb->nvgpus->num) && (atsdnum < ARRAY_SIZE(atsd)); ++i) {
- struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i];
+ SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
if (!nvslot->gpdev) {
continue;
@@ -354,7 +356,7 @@ void spapr_phb_nvgpu_ram_populate_dt(SpaprPhbState *sphb, void *fdt)
/* Add memory nodes for GPU RAM and mark them unusable */
for (i = 0; i < sphb->nvgpus->num; ++i) {
- struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i];
+ SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev),
"nvlink2-mr[0]", NULL);
uint32_t associativity[] = {
@@ -398,7 +400,7 @@ void spapr_phb_nvgpu_populate_pcidev_dt(PCIDevice *dev, void *fdt, int offset,
}
for (i = 0; i < sphb->nvgpus->num; ++i) {
- struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i];
+ SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
/* Skip "slot" without attached GPU */
if (!nvslot->gpdev) {
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 526b489297..bee3835214 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -266,6 +266,7 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
target_ulong args,
uint32_t nret, target_ulong rets)
{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
MachineState *ms = MACHINE(qdev_get_machine());
unsigned int max_cpus = ms->smp.max_cpus;
target_ulong parameter = rtas_ld(args, 0);
@@ -283,6 +284,20 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
current_machine->ram_size / MiB,
ms->smp.cpus,
max_cpus);
+ if (pcc->n_host_threads > 0) {
+ char *hostthr_val, *old = param_val;
+
+ /*
+ * Add HostThrs property. This property is not present in PAPR but
+ * is expected by some guests to communicate the number of physical
+ * host threads per core on the system so that they can scale
+ * information which varies based on the thread configuration.
+ */
+ hostthr_val = g_strdup_printf(",HostThrs=%d", pcc->n_host_threads);
+ param_val = g_strconcat(param_val, hostthr_val, NULL);
+ g_free(hostthr_val);
+ g_free(old);
+ }
ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1);
g_free(param_val);
break;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 00235148be..4b3bd4a804 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -15,6 +15,7 @@
#include "cpu.h"
#include "s390-pci-inst.h"
#include "s390-pci-bus.h"
+#include "exec/memop.h"
#include "exec/memory-internal.h"
#include "qemu/error-report.h"
#include "sysemu/hw_accel.h"
@@ -372,7 +373,8 @@ static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
mr = pbdev->pdev->io_regions[pcias].memory;
mr = s390_get_subregion(mr, offset, len);
offset -= mr->addr;
- return memory_region_dispatch_read(mr, offset, data, len,
+ return memory_region_dispatch_read(mr, offset, data,
+ size_memop(len) | MO_BE,
MEMTXATTRS_UNSPECIFIED);
}
@@ -471,7 +473,8 @@ static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
mr = pbdev->pdev->io_regions[pcias].memory;
mr = s390_get_subregion(mr, offset, len);
offset -= mr->addr;
- return memory_region_dispatch_write(mr, offset, data, len,
+ return memory_region_dispatch_write(mr, offset, data,
+ size_memop(len) | MO_BE,
MEMTXATTRS_UNSPECIFIED);
}
@@ -780,8 +783,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
for (i = 0; i < len / 8; i++) {
result = memory_region_dispatch_write(mr, offset + i * 8,
- ldq_p(buffer + i * 8), 8,
- MEMTXATTRS_UNSPECIFIED);
+ ldq_p(buffer + i * 8),
+ MO_64, MEMTXATTRS_UNSPECIFIED);
if (result != MEMTX_OK) {
s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return 0;
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index ed81d5c44c..59c2bbeee6 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -44,6 +44,13 @@ enum timer_ctrl_op {
op_pulse_enable
};
+/*
+ * Minimum value of the reload register to filter out short period
+ * timers which have a noticeable impact in emulation. 5us should be
+ * enough, use 20us for "safety".
+ */
+#define TIMER_MIN_NS (20 * SCALE_US)
+
/**
* Avoid mutual references between AspeedTimerCtrlState and AspeedTimer
* structs, as it's a waste of memory. The ptimer BH callback needs to know
@@ -98,6 +105,14 @@ static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns)
return t->reload - MIN(t->reload, ticks);
}
+static uint32_t calculate_min_ticks(AspeedTimer *t, uint32_t value)
+{
+ uint32_t rate = calculate_rate(t);
+ uint32_t min_ticks = muldiv64(TIMER_MIN_NS, rate, NANOSECONDS_PER_SECOND);
+
+ return value < min_ticks ? min_ticks : value;
+}
+
static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
{
uint64_t delta_ns;
@@ -261,7 +276,7 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
switch (reg) {
case TIMER_REG_RELOAD:
old_reload = t->reload;
- t->reload = value;
+ t->reload = calculate_min_ticks(t, value);
/* If the reload value was not previously set, or zero, and
* the current value is valid, try to start the timer if it is
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 9846e4b513..7c07295519 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -2038,26 +2038,36 @@ static void usb_mtp_realize(USBDevice *dev, Error **errp)
{
MTPState *s = USB_MTP(dev);
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- QTAILQ_INIT(&s->objects);
- if (s->desc == NULL) {
- if (s->root == NULL) {
- error_setg(errp, "usb-mtp: rootdir property must be configured");
- return;
- }
- s->desc = strrchr(s->root, '/');
- if (s->desc && s->desc[0]) {
- s->desc = g_strdup(s->desc + 1);
- } else {
- s->desc = g_strdup("none");
- }
+ if ((s->root == NULL) || !g_path_is_absolute(s->root)) {
+ error_setg(errp, "usb-mtp: rootdir must be configured and be an absolute path");
+ return;
}
+
+ if (access(s->root, R_OK) != 0) {
+ error_setg(errp, "usb-mtp: rootdir does not exist/not readable");
+ return;
+ } else if (!s->readonly && access(s->root, W_OK) != 0) {
+ error_setg(errp, "usb-mtp: rootdir does not have write permissions");
+ return;
+ }
+
/* Mark store as RW */
if (!s->readonly) {
s->flags |= (1 << MTP_FLAG_WRITABLE);
}
+ if (s->desc == NULL) {
+ /*
+ * This does not check if path exists
+ * but we have the checks above
+ */
+ s->desc = g_path_get_basename(s->root);
+ }
+
+ usb_desc_create_serial(dev);
+ usb_desc_init(dev);
+ QTAILQ_INIT(&s->objects);
+
}
static const VMStateDescription vmstate_usb_mtp = {
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index f578264948..80988bb305 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1914,6 +1914,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
}
usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
if (xfer->packet.status == USB_RET_NAK) {
+ xhci_xfer_unmap(xfer);
return;
}
xhci_try_complete_packet(xfer);
@@ -2161,6 +2162,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
DeviceOutRequest | USB_REQ_SET_ADDRESS,
slotid, 0, 0, NULL);
assert(p.status != USB_RET_ASYNC);
+ usb_packet_cleanup(&p);
}
res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx);
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index f71aace156..136f3a9ad6 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
+#include "exec/memop.h"
#include "qemu/units.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
@@ -1073,7 +1074,8 @@ static void vfio_rtl8168_quirk_address_write(void *opaque, hwaddr addr,
/* Write to the proper guest MSI-X table instead */
memory_region_dispatch_write(&vdev->pdev.msix_table_mmio,
- offset, val, size,
+ offset, val,
+ size_memop(size) | MO_LE,
MEMTXATTRS_UNSPECIFIED);
}
return; /* Do not write guest MSI-X data to hardware */
@@ -1104,7 +1106,8 @@ static uint64_t vfio_rtl8168_quirk_data_read(void *opaque,
if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
hwaddr offset = rtl->addr & 0xfff;
memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, offset,
- &data, size, MEMTXATTRS_UNSPECIFIED);
+ &data, size_memop(size) | MO_LE,
+ MEMTXATTRS_UNSPECIFIED);
trace_vfio_quirk_rtl8168_msix_read(vdev->vbasedev.name, offset, data);
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 8babd92e59..c6b47a9c73 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -17,6 +17,7 @@
#include "qemu/osdep.h"
+#include "exec/memop.h"
#include "standard-headers/linux/virtio_pci.h"
#include "hw/virtio/virtio.h"
#include "migration/qemu-file-types.h"
@@ -543,16 +544,17 @@ void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr,
val = pci_get_byte(buf);
break;
case 2:
- val = cpu_to_le16(pci_get_word(buf));
+ val = pci_get_word(buf);
break;
case 4:
- val = cpu_to_le32(pci_get_long(buf));
+ val = pci_get_long(buf);
break;
default:
/* As length is under guest control, handle illegal values. */
return;
}
- memory_region_dispatch_write(mr, addr, val, len, MEMTXATTRS_UNSPECIFIED);
+ memory_region_dispatch_write(mr, addr, val, size_memop(len) | MO_LE,
+ MEMTXATTRS_UNSPECIFIED);
}
static void
@@ -575,16 +577,17 @@ virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr,
/* Make sure caller aligned buf properly */
assert(!(((uintptr_t)buf) & (len - 1)));
- memory_region_dispatch_read(mr, addr, &val, len, MEMTXATTRS_UNSPECIFIED);
+ memory_region_dispatch_read(mr, addr, &val, size_memop(len) | MO_LE,
+ MEMTXATTRS_UNSPECIFIED);
switch (len) {
case 1:
pci_set_byte(buf, val);
break;
case 2:
- pci_set_word(buf, le16_to_cpu(val));
+ pci_set_word(buf, val);
break;
case 4:
- pci_set_long(buf, le32_to_cpu(val));
+ pci_set_long(buf, val);
break;
default:
/* As length is under guest control, handle illegal values. */
@@ -601,6 +604,10 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
pci_default_write_config(pci_dev, address, val, len);
+ if (proxy->flags & VIRTIO_PCI_FLAG_INIT_FLR) {
+ pcie_cap_flr_write_config(pci_dev, address, val, len);
+ }
+
if (range_covers_byte(address, len, PCI_COMMAND) &&
!(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
virtio_pci_stop_ioeventfd(proxy);
@@ -1777,6 +1784,10 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
pcie_ats_init(pci_dev, 256);
}
+ if (proxy->flags & VIRTIO_PCI_FLAG_INIT_FLR) {
+ /* Set Function Level Reset capability bit */
+ pcie_cap_flr_init(pci_dev);
+ }
} else {
/*
* make future invocations of pci_is_express() return false
@@ -1844,6 +1855,8 @@ static Property virtio_pci_properties[] = {
VIRTIO_PCI_FLAG_INIT_LNKCTL_BIT, true),
DEFINE_PROP_BIT("x-pcie-pm-init", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_INIT_PM_BIT, true),
+ DEFINE_PROP_BIT("x-pcie-flr-init", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_INIT_FLR_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 292275acb1..e2eaaa9182 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -44,6 +44,7 @@ enum {
VIRTIO_PCI_FLAG_INIT_DEVERR_BIT,
VIRTIO_PCI_FLAG_INIT_LNKCTL_BIT,
VIRTIO_PCI_FLAG_INIT_PM_BIT,
+ VIRTIO_PCI_FLAG_INIT_FLR_BIT,
};
/* Need to activate work-arounds for buggy guests at vmstate load. */
@@ -80,6 +81,9 @@ enum {
/* Init Power Management */
#define VIRTIO_PCI_FLAG_INIT_PM (1 << VIRTIO_PCI_FLAG_INIT_PM_BIT)
+/* Init Function Level Reset capability */
+#define VIRTIO_PCI_FLAG_INIT_FLR (1 << VIRTIO_PCI_FLAG_INIT_FLR_BIT)
+
typedef struct {
MSIMessage msg;
int virq;
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index d1650e1dee..e93bed020f 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -192,27 +192,24 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
}
if (vrng->conf.rng == NULL) {
- vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
+ Object *default_backend = object_new(TYPE_RNG_BUILTIN);
- user_creatable_complete(USER_CREATABLE(vrng->conf.default_backend),
+ user_creatable_complete(USER_CREATABLE(default_backend),
&local_err);
if (local_err) {
error_propagate(errp, local_err);
- object_unref(OBJECT(vrng->conf.default_backend));
+ object_unref(default_backend);
return;
}
- object_property_add_child(OBJECT(dev),
- "default-backend",
- OBJECT(vrng->conf.default_backend),
- NULL);
+ object_property_add_child(OBJECT(dev), "default-backend",
+ default_backend, &error_abort);
/* The child property took a reference, we can safely drop ours now */
- object_unref(OBJECT(vrng->conf.default_backend));
+ object_unref(default_backend);
- object_property_set_link(OBJECT(dev),
- OBJECT(vrng->conf.default_backend),
- "rng", NULL);
+ object_property_set_link(OBJECT(dev), default_backend,
+ "rng", &error_abort);
}
vrng->rng = vrng->conf.rng;
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 7b36d672f0..21550747cf 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -140,6 +140,7 @@ enum {
NBD_FLAG_CAN_MULTI_CONN_BIT = 8, /* Multi-client cache consistent */
NBD_FLAG_SEND_RESIZE_BIT = 9, /* Send resize */
NBD_FLAG_SEND_CACHE_BIT = 10, /* Send CACHE (prefetch) */
+ NBD_FLAG_SEND_FAST_ZERO_BIT = 11, /* FAST_ZERO flag for WRITE_ZEROES */
};
#define NBD_FLAG_HAS_FLAGS (1 << NBD_FLAG_HAS_FLAGS_BIT)
@@ -153,6 +154,7 @@ enum {
#define NBD_FLAG_CAN_MULTI_CONN (1 << NBD_FLAG_CAN_MULTI_CONN_BIT)
#define NBD_FLAG_SEND_RESIZE (1 << NBD_FLAG_SEND_RESIZE_BIT)
#define NBD_FLAG_SEND_CACHE (1 << NBD_FLAG_SEND_CACHE_BIT)
+#define NBD_FLAG_SEND_FAST_ZERO (1 << NBD_FLAG_SEND_FAST_ZERO_BIT)
/* New-style handshake (global) flags, sent from server to client, and
control what will happen during handshake phase. */
@@ -205,6 +207,7 @@ enum {
#define NBD_CMD_FLAG_DF (1 << 2) /* don't fragment structured read */
#define NBD_CMD_FLAG_REQ_ONE (1 << 3) /* only one extent in BLOCK_STATUS
* reply chunk */
+#define NBD_CMD_FLAG_FAST_ZERO (1 << 4) /* fail if WRITE_ZEROES is not fast */
/* Supported request types */
enum {
@@ -270,6 +273,7 @@ static inline bool nbd_reply_type_is_error(int type)
#define NBD_EINVAL 22
#define NBD_ENOSPC 28
#define NBD_EOVERFLOW 75
+#define NBD_ENOTSUP 95
#define NBD_ESHUTDOWN 108
/* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */
@@ -326,7 +330,7 @@ typedef struct NBDClient NBDClient;
NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
uint64_t size, const char *name, const char *desc,
- const char *bitmap, uint16_t nbdflags,
+ const char *bitmap, bool readonly, bool shared,
void (*close)(NBDExport *), bool writethrough,
BlockBackend *on_eject_blk, Error **errp);
void nbd_export_close(NBDExport *exp);
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 8323094648..d2d443c4f9 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -329,14 +329,14 @@ CPUArchState *cpu_copy(CPUArchState *env);
#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS - 2))
/* Set if TLB entry is an IO callback. */
#define TLB_MMIO (1 << (TARGET_PAGE_BITS - 3))
-/* Set if TLB entry must have MMU lookup repeated for every access */
-#define TLB_RECHECK (1 << (TARGET_PAGE_BITS - 4))
+/* Set if TLB entry contains a watchpoint. */
+#define TLB_WATCHPOINT (1 << (TARGET_PAGE_BITS - 4))
/* Use this mask to check interception with an alignment mask
* in a TCG backend.
*/
-#define TLB_FLAGS_MASK (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \
- | TLB_RECHECK)
+#define TLB_FLAGS_MASK \
+ (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO | TLB_WATCHPOINT)
/**
* tlb_hit_page: return true if page aligned @addr is a hit against the
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index 189709b6de..be946ba1ce 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -231,7 +231,7 @@ typedef struct CPUTLB { } CPUTLB;
#endif /* !CONFIG_USER_ONLY && CONFIG_TCG */
/*
- * This structure must be placed in ArchCPU immedately
+ * This structure must be placed in ArchCPU immediately
* before CPUArchState, as a field named "neg".
*/
typedef struct CPUNegativeOffsetState {
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 135aeaab0d..81b02eb2fe 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -260,8 +260,6 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
void tlb_set_page(CPUState *cpu, target_ulong vaddr,
hwaddr paddr, int prot,
int mmu_idx, target_ulong size);
-void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
- uintptr_t retaddr);
#else
static inline void tlb_init(CPUState *cpu)
{
@@ -312,6 +310,14 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
{
}
#endif
+void *probe_access(CPUArchState *env, target_ulong addr, int size,
+ MMUAccessType access_type, int mmu_idx, uintptr_t retaddr);
+
+static inline void *probe_write(CPUArchState *env, target_ulong addr, int size,
+ int mmu_idx, uintptr_t retaddr)
+{
+ return probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, retaddr);
+}
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h
index d4a3477d71..95f2d20d55 100644
--- a/include/exec/memattrs.h
+++ b/include/exec/memattrs.h
@@ -37,6 +37,8 @@ typedef struct MemTxAttrs {
unsigned int user:1;
/* Requester ID (for MSI for example) */
unsigned int requester_id:16;
+ /* Invert endianness for this page */
+ unsigned int byte_swap:1;
/*
* The following are target-specific page-table bits. These are not
* related to actual memory transactions at all. However, this structure
diff --git a/include/exec/memop.h b/include/exec/memop.h
new file mode 100644
index 0000000000..529d07b02d
--- /dev/null
+++ b/include/exec/memop.h
@@ -0,0 +1,134 @@
+/*
+ * Constants for memory operations
+ *
+ * Authors:
+ * Richard Henderson <rth@twiddle.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef MEMOP_H
+#define MEMOP_H
+
+#include "qemu/host-utils.h"
+
+typedef enum MemOp {
+ MO_8 = 0,
+ MO_16 = 1,
+ MO_32 = 2,
+ MO_64 = 3,
+ MO_SIZE = 3, /* Mask for the above. */
+
+ MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */
+
+ MO_BSWAP = 8, /* Host reverse endian. */
+#ifdef HOST_WORDS_BIGENDIAN
+ MO_LE = MO_BSWAP,
+ MO_BE = 0,
+#else
+ MO_LE = 0,
+ MO_BE = MO_BSWAP,
+#endif
+#ifdef NEED_CPU_H
+#ifdef TARGET_WORDS_BIGENDIAN
+ MO_TE = MO_BE,
+#else
+ MO_TE = MO_LE,
+#endif
+#endif
+
+ /*
+ * MO_UNALN accesses are never checked for alignment.
+ * MO_ALIGN accesses will result in a call to the CPU's
+ * do_unaligned_access hook if the guest address is not aligned.
+ * The default depends on whether the target CPU defines
+ * TARGET_ALIGNED_ONLY.
+ *
+ * Some architectures (e.g. ARMv8) need the address which is aligned
+ * to a size more than the size of the memory access.
+ * Some architectures (e.g. SPARCv9) need an address which is aligned,
+ * but less strictly than the natural alignment.
+ *
+ * MO_ALIGN supposes the alignment size is the size of a memory access.
+ *
+ * There are three options:
+ * - unaligned access permitted (MO_UNALN).
+ * - an alignment to the size of an access (MO_ALIGN);
+ * - an alignment to a specified size, which may be more or less than
+ * the access size (MO_ALIGN_x where 'x' is a size in bytes);
+ */
+ MO_ASHIFT = 4,
+ MO_AMASK = 7 << MO_ASHIFT,
+#ifdef NEED_CPU_H
+#ifdef TARGET_ALIGNED_ONLY
+ MO_ALIGN = 0,
+ MO_UNALN = MO_AMASK,
+#else
+ MO_ALIGN = MO_AMASK,
+ MO_UNALN = 0,
+#endif
+#endif
+ MO_ALIGN_2 = 1 << MO_ASHIFT,
+ MO_ALIGN_4 = 2 << MO_ASHIFT,
+ MO_ALIGN_8 = 3 << MO_ASHIFT,
+ MO_ALIGN_16 = 4 << MO_ASHIFT,
+ MO_ALIGN_32 = 5 << MO_ASHIFT,
+ MO_ALIGN_64 = 6 << MO_ASHIFT,
+
+ /* Combinations of the above, for ease of use. */
+ MO_UB = MO_8,
+ MO_UW = MO_16,
+ MO_UL = MO_32,
+ MO_SB = MO_SIGN | MO_8,
+ MO_SW = MO_SIGN | MO_16,
+ MO_SL = MO_SIGN | MO_32,
+ MO_Q = MO_64,
+
+ MO_LEUW = MO_LE | MO_UW,
+ MO_LEUL = MO_LE | MO_UL,
+ MO_LESW = MO_LE | MO_SW,
+ MO_LESL = MO_LE | MO_SL,
+ MO_LEQ = MO_LE | MO_Q,
+
+ MO_BEUW = MO_BE | MO_UW,
+ MO_BEUL = MO_BE | MO_UL,
+ MO_BESW = MO_BE | MO_SW,
+ MO_BESL = MO_BE | MO_SL,
+ MO_BEQ = MO_BE | MO_Q,
+
+#ifdef NEED_CPU_H
+ MO_TEUW = MO_TE | MO_UW,
+ MO_TEUL = MO_TE | MO_UL,
+ MO_TESW = MO_TE | MO_SW,
+ MO_TESL = MO_TE | MO_SL,
+ MO_TEQ = MO_TE | MO_Q,
+#endif
+
+ MO_SSIZE = MO_SIZE | MO_SIGN,
+} MemOp;
+
+/* MemOp to size in bytes. */
+static inline unsigned memop_size(MemOp op)
+{
+ return 1 << (op & MO_SIZE);
+}
+
+/* Size in bytes to MemOp. */
+static inline MemOp size_memop(unsigned size)
+{
+#ifdef CONFIG_DEBUG_TCG
+ /* Power of 2 up to 8. */
+ assert((size & (size - 1)) == 0 && size >= 1 && size <= 8);
+#endif
+ return ctz32(size);
+}
+
+/* Big endianness from MemOp. */
+static inline bool memop_big_endian(MemOp op)
+{
+ return (op & MO_BSWAP) == MO_BE;
+}
+
+#endif
diff --git a/include/exec/memory.h b/include/exec/memory.h
index fddc2ff48a..2dd810259d 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -19,6 +19,7 @@
#include "exec/cpu-common.h"
#include "exec/hwaddr.h"
#include "exec/memattrs.h"
+#include "exec/memop.h"
#include "exec/ramlist.h"
#include "qemu/bswap.h"
#include "qemu/queue.h"
@@ -1087,16 +1088,6 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
/**
- * memory_region_iommu_replay_all: replay existing IOMMU translations
- * to all the notifiers registered.
- *
- * Note: this is not related to record-and-replay functionality.
- *
- * @iommu_mr: the memory region to observe
- */
-void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
-
-/**
* memory_region_unregister_iommu_notifier: unregister a notifier for
* changes to IOMMU translation entries.
*
@@ -1749,13 +1740,13 @@ void mtree_info(bool flatview, bool dispatch_tree, bool owner);
* @mr: #MemoryRegion to access
* @addr: address within that region
* @pval: pointer to uint64_t which the data is written to
- * @size: size of the access in bytes
+ * @op: size, sign, and endianness of the memory operation
* @attrs: memory transaction attributes to use for the access
*/
MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
hwaddr addr,
uint64_t *pval,
- unsigned size,
+ MemOp op,
MemTxAttrs attrs);
/**
* memory_region_dispatch_write: perform a write directly to the specified
@@ -1764,13 +1755,13 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
* @mr: #MemoryRegion to access
* @addr: address within that region
* @data: data to write
- * @size: size of the access in bytes
+ * @op: size, sign, and endianness of the memory operation
* @attrs: memory transaction attributes to use for the access
*/
MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
hwaddr addr,
uint64_t data,
- unsigned size,
+ MemOp op,
MemTxAttrs attrs);
/**
@@ -2210,6 +2201,9 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr,
}
}
+/* enum device_endian to MemOp. */
+MemOp devend_memop(enum device_endian end);
+
#endif
#endif
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 1a563ad756..991cf05134 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -414,7 +414,7 @@ build_append_gas_from_struct(GArray *table, const struct AcpiGenericAddress *s)
void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
uint64_t len, int node, MemoryAffinityFlags flags);
-void build_slit(GArray *table_data, BIOSLinker *linker);
+void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms);
void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
const char *oem_id, const char *oem_table_id);
diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
index 5714dea1a2..7f4d0ca7cd 100644
--- a/include/hw/arm/boot.h
+++ b/include/hw/arm/boot.h
@@ -131,7 +131,7 @@ struct arm_boot_info {
* before sysbus-fdt arm_register_platform_bus_fdt_creator. Indeed the
* machine init done notifiers are called in registration reverse order.
*/
-void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
+void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info);
AddressSpace *arm_boot_address_space(ARMCPU *cpu,
const struct arm_boot_info *info);
@@ -158,7 +158,7 @@ AddressSpace *arm_boot_address_space(ARMCPU *cpu,
* Note: Must not be called unless have_dtb(binfo) is true.
*/
int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
- hwaddr addr_limit, AddressSpace *as);
+ hwaddr addr_limit, AddressSpace *as, MachineState *ms);
/* Write a secure board setup routine with a dummy handler for SMCs */
void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
diff --git a/include/hw/boards.h b/include/hw/boards.h
index ced86109ec..2289536e48 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -299,6 +299,7 @@ struct MachineState {
CPUArchIdList *possible_cpus;
CpuTopology smp;
struct NVDIMMState *nvdimms_state;
+ struct NumaState *numa_state;
};
#define DEFINE_MACHINE(namestr, machine_initfn) \
diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h
index d5196c53e6..794b653484 100644
--- a/include/hw/char/escc.h
+++ b/include/hw/char/escc.h
@@ -51,6 +51,7 @@ typedef struct ESCCState {
struct ESCCChannelState chn[2];
uint32_t it_shift;
+ bool bit_swap;
MemoryRegion mmio;
uint32_t disabled;
uint32_t frequency;
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 77fca95a40..c7cda65c66 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -1070,12 +1070,49 @@ static inline bool cpu_breakpoint_test(CPUState *cpu, vaddr pc, int mask)
return false;
}
+#ifdef CONFIG_USER_ONLY
+static inline int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
+ int flags, CPUWatchpoint **watchpoint)
+{
+ return -ENOSYS;
+}
+
+static inline int cpu_watchpoint_remove(CPUState *cpu, vaddr addr,
+ vaddr len, int flags)
+{
+ return -ENOSYS;
+}
+
+static inline void cpu_watchpoint_remove_by_ref(CPUState *cpu,
+ CPUWatchpoint *wp)
+{
+}
+
+static inline void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
+{
+}
+
+static inline void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
+ MemTxAttrs atr, int fl, uintptr_t ra)
+{
+}
+
+static inline int cpu_watchpoint_address_matches(CPUState *cpu,
+ vaddr addr, vaddr len)
+{
+ return 0;
+}
+#else
int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
int flags, CPUWatchpoint **watchpoint);
int cpu_watchpoint_remove(CPUState *cpu, vaddr addr,
vaddr len, int flags);
void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint);
void cpu_watchpoint_remove_all(CPUState *cpu, int mask);
+void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
+ MemTxAttrs attrs, int flags, uintptr_t ra);
+int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len);
+#endif
/**
* cpu_get_address_space:
diff --git a/include/hw/m68k/next-cube.h b/include/hw/m68k/next-cube.h
new file mode 100644
index 0000000000..a3be2b32ab
--- /dev/null
+++ b/include/hw/m68k/next-cube.h
@@ -0,0 +1,47 @@
+
+#ifndef NEXT_CUBE_H
+#define NEXT_CUBE_H
+
+#define TYPE_NEXTFB "next-fb"
+
+#define TYPE_NEXTKBD "next-kbd"
+
+enum next_dma_chan {
+ NEXTDMA_FD,
+ NEXTDMA_ENRX,
+ NEXTDMA_ENTX,
+ NEXTDMA_SCSI,
+ NEXTDMA_SCC,
+ NEXTDMA_SND
+};
+
+#define DMA_ENABLE 0x01000000
+#define DMA_SUPDATE 0x02000000
+#define DMA_COMPLETE 0x08000000
+
+#define DMA_M2DEV 0x0
+#define DMA_SETENABLE 0x00010000
+#define DMA_SETSUPDATE 0x00020000
+#define DMA_DEV2M 0x00040000
+#define DMA_CLRCOMPLETE 0x00080000
+#define DMA_RESET 0x00100000
+
+enum next_irqs {
+ NEXT_FD_I,
+ NEXT_KBD_I,
+ NEXT_PWR_I,
+ NEXT_ENRX_I,
+ NEXT_ENTX_I,
+ NEXT_SCSI_I,
+ NEXT_CLK_I,
+ NEXT_SCC_I,
+ NEXT_ENTX_DMA_I,
+ NEXT_ENRX_DMA_I,
+ NEXT_SCSI_DMA_I,
+ NEXT_SCC_DMA_I,
+ NEXT_SND_I
+};
+
+void next_irq(void *opaque, int number, int level);
+
+#endif /* NEXT_CUBE_H */
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index 1b61162f91..abd87605b2 100644
--- a/include/hw/pci-host/spapr.h
+++ b/include/hw/pci-host/spapr.h
@@ -34,15 +34,21 @@
typedef struct SpaprPhbState SpaprPhbState;
-typedef struct spapr_pci_msi {
+typedef struct SpaprPciMsi {
uint32_t first_irq;
uint32_t num;
-} spapr_pci_msi;
+} SpaprPciMsi;
-typedef struct spapr_pci_msi_mig {
+typedef struct SpaprPciMsiMig {
uint32_t key;
- spapr_pci_msi value;
-} spapr_pci_msi_mig;
+ SpaprPciMsi value;
+} SpaprPciMsiMig;
+
+typedef struct SpaprPciLsi {
+ uint32_t irq;
+} SpaprPciLsi;
+
+typedef struct SpaprPhbPciNvGpuConfig SpaprPhbPciNvGpuConfig;
struct SpaprPhbState {
PCIHostState parent_obj;
@@ -63,14 +69,12 @@ struct SpaprPhbState {
AddressSpace iommu_as;
MemoryRegion iommu_root;
- struct spapr_pci_lsi {
- uint32_t irq;
- } lsi_table[PCI_NUM_PINS];
+ SpaprPciLsi lsi_table[PCI_NUM_PINS];
GHashTable *msi;
/* Temporary cache for migration purposes */
int32_t msi_devs_num;
- spapr_pci_msi_mig *msi_devs;
+ SpaprPciMsiMig *msi_devs;
QLIST_ENTRY(SpaprPhbState) list;
@@ -89,7 +93,7 @@ struct SpaprPhbState {
hwaddr mig_io_win_addr, mig_io_win_size;
hwaddr nv2_gpa_win_addr;
hwaddr nv2_atsd_win_addr;
- struct spapr_phb_pci_nvgpu_config *nvgpus;
+ SpaprPhbPciNvGpuConfig *nvgpus;
};
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index fa7c380edb..03111fd55b 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -121,6 +121,7 @@ struct SpaprMachineClass {
bool legacy_irq_allocation;
bool broken_host_serial_model; /* present real host info to the guest */
bool pre_4_1_migration; /* don't migrate hpt-max-page-size */
+ bool linux_pci_probe;
void (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h
index ff699335e3..bd05d734b8 100644
--- a/include/hw/virtio/virtio-rng.h
+++ b/include/hw/virtio/virtio-rng.h
@@ -14,7 +14,6 @@
#include "hw/virtio/virtio.h"
#include "sysemu/rng.h"
-#include "sysemu/rng-random.h"
#include "standard-headers/linux/virtio_rng.h"
#define TYPE_VIRTIO_RNG "virtio-rng-device"
@@ -27,7 +26,6 @@ struct VirtIORNGConf {
RngBackend *rng;
uint64_t max_bytes;
uint32_t period_ms;
- RngRandom *default_backend;
};
typedef struct VirtIORNG {
diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h
index d7134d2cd6..777ff5954e 100644
--- a/include/io/channel-socket.h
+++ b/include/io/channel-socket.h
@@ -123,6 +123,7 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,
* qio_channel_socket_listen_sync:
* @ioc: the socket channel object
* @addr: the address to listen to
+ * @num: the expected ammount of connections
* @errp: pointer to a NULL-initialized error object
*
* Attempt to listen to the address @addr. This method
@@ -132,12 +133,14 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,
*/
int qio_channel_socket_listen_sync(QIOChannelSocket *ioc,
SocketAddress *addr,
+ int num,
Error **errp);
/**
* qio_channel_socket_listen_async:
* @ioc: the socket channel object
* @addr: the address to listen to
+ * @num: the expected ammount of connections
* @callback: the function to invoke on completion
* @opaque: user data to pass to @callback
* @destroy: the function to free @opaque
@@ -153,6 +156,7 @@ int qio_channel_socket_listen_sync(QIOChannelSocket *ioc,
*/
void qio_channel_socket_listen_async(QIOChannelSocket *ioc,
SocketAddress *addr,
+ int num,
QIOTaskFunc callback,
gpointer opaque,
GDestroyNotify destroy,
diff --git a/include/io/net-listener.h b/include/io/net-listener.h
index 8081ac58a2..fb101703e3 100644
--- a/include/io/net-listener.h
+++ b/include/io/net-listener.h
@@ -95,6 +95,7 @@ void qio_net_listener_set_name(QIONetListener *listener,
* qio_net_listener_open_sync:
* @listener: the network listener object
* @addr: the address to listen on
+ * @num: the amount of expected connections
* @errp: pointer to a NULL initialized error object
*
* Synchronously open a listening connection on all
@@ -104,6 +105,7 @@ void qio_net_listener_set_name(QIONetListener *listener,
*/
int qio_net_listener_open_sync(QIONetListener *listener,
SocketAddress *addr,
+ int num,
Error **errp);
/**
diff --git a/include/qemu/memfd.h b/include/qemu/memfd.h
index d551c28b68..975b6bdb77 100644
--- a/include/qemu/memfd.h
+++ b/include/qemu/memfd.h
@@ -32,6 +32,10 @@
#define MFD_HUGE_SHIFT 26
#endif
+#if defined CONFIG_LINUX && !defined CONFIG_MEMFD
+int memfd_create(const char *name, unsigned int flags);
+#endif
+
int qemu_memfd_create(const char *name, size_t size, bool hugetlb,
uint64_t hugetlbsize, unsigned int seals, Error **errp);
bool qemu_memfd_alloc_check(void);
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 8140fea685..57cd049d6e 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -41,7 +41,7 @@ int unix_connect(const char *path, Error **errp);
SocketAddress *socket_parse(const char *str, Error **errp);
int socket_connect(SocketAddress *addr, Error **errp);
-int socket_listen(SocketAddress *addr, Error **errp);
+int socket_listen(SocketAddress *addr, int num, Error **errp);
void socket_listen_cleanup(int fd, Error **errp);
int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp);
diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h
index 7a4ce89765..ae9c41d02b 100644
--- a/include/sysemu/numa.h
+++ b/include/sysemu/numa.h
@@ -14,9 +14,6 @@ struct CPUArchId;
#define NUMA_DISTANCE_MAX 254
#define NUMA_DISTANCE_UNREACHABLE 255
-extern int nb_numa_nodes; /* Number of NUMA nodes */
-extern bool have_numa_distance;
-
struct NodeInfo {
uint64_t node_mem;
struct HostMemoryBackend *node_memdev;
@@ -29,12 +26,22 @@ struct NumaNodeMem {
uint64_t node_plugged_mem;
};
-extern NodeInfo numa_info[MAX_NODES];
+struct NumaState {
+ /* Number of NUMA nodes */
+ int num_nodes;
+
+ /* Allow setting NUMA distance for different NUMA nodes */
+ bool have_numa_distance;
+
+ /* NUMA nodes information */
+ NodeInfo nodes[MAX_NODES];
+};
+typedef struct NumaState NumaState;
void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp);
void parse_numa_opts(MachineState *ms);
void numa_complete_configuration(MachineState *ms);
-void query_numa_node_mem(NumaNodeMem node_mem[]);
+void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms);
extern QemuOptsList qemu_numa_opts;
void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
int nb_nodes, ram_addr_t size);
diff --git a/include/sysemu/rng.h b/include/sysemu/rng.h
index 9b22c156f8..fa6eada78c 100644
--- a/include/sysemu/rng.h
+++ b/include/sysemu/rng.h
@@ -24,6 +24,8 @@
#define RNG_BACKEND_CLASS(klass) \
OBJECT_CLASS_CHECK(RngBackendClass, (klass), TYPE_RNG_BACKEND)
+#define TYPE_RNG_BUILTIN "rng-builtin"
+
typedef struct RngRequest RngRequest;
typedef struct RngBackendClass RngBackendClass;
typedef struct RngBackend RngBackend;
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index d2c38f611a..44f18eb739 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -42,8 +42,6 @@ extern const char *keyboard_layout;
extern int win2k_install_hack;
extern int alt_grab;
extern int ctrl_grab;
-extern int smp_cpus;
-extern unsigned int max_cpus;
extern int cursor_hide;
extern int graphic_rotate;
extern int no_quit;
diff --git a/io/channel-socket.c b/io/channel-socket.c
index bec3d931d1..b74f5b92a0 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -197,12 +197,13 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,
int qio_channel_socket_listen_sync(QIOChannelSocket *ioc,
SocketAddress *addr,
+ int num,
Error **errp)
{
int fd;
- trace_qio_channel_socket_listen_sync(ioc, addr);
- fd = socket_listen(addr, errp);
+ trace_qio_channel_socket_listen_sync(ioc, addr, num);
+ fd = socket_listen(addr, num, errp);
if (fd < 0) {
trace_qio_channel_socket_listen_fail(ioc);
return -1;
@@ -219,14 +220,27 @@ int qio_channel_socket_listen_sync(QIOChannelSocket *ioc,
}
+struct QIOChannelListenWorkerData {
+ SocketAddress *addr;
+ int num; /* amount of expected connections */
+};
+
+static void qio_channel_listen_worker_free(gpointer opaque)
+{
+ struct QIOChannelListenWorkerData *data = opaque;
+
+ qapi_free_SocketAddress(data->addr);
+ g_free(data);
+}
+
static void qio_channel_socket_listen_worker(QIOTask *task,
gpointer opaque)
{
QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
- SocketAddress *addr = opaque;
+ struct QIOChannelListenWorkerData *data = opaque;
Error *err = NULL;
- qio_channel_socket_listen_sync(ioc, addr, &err);
+ qio_channel_socket_listen_sync(ioc, data->addr, data->num, &err);
qio_task_set_error(task, err);
}
@@ -234,6 +248,7 @@ static void qio_channel_socket_listen_worker(QIOTask *task,
void qio_channel_socket_listen_async(QIOChannelSocket *ioc,
SocketAddress *addr,
+ int num,
QIOTaskFunc callback,
gpointer opaque,
GDestroyNotify destroy,
@@ -241,16 +256,18 @@ void qio_channel_socket_listen_async(QIOChannelSocket *ioc,
{
QIOTask *task = qio_task_new(
OBJECT(ioc), callback, opaque, destroy);
- SocketAddress *addrCopy;
+ struct QIOChannelListenWorkerData *data;
- addrCopy = QAPI_CLONE(SocketAddress, addr);
+ data = g_new0(struct QIOChannelListenWorkerData, 1);
+ data->addr = QAPI_CLONE(SocketAddress, addr);
+ data->num = num;
/* socket_listen() blocks in DNS lookups, so we must use a thread */
- trace_qio_channel_socket_listen_async(ioc, addr);
+ trace_qio_channel_socket_listen_async(ioc, addr, num);
qio_task_run_in_thread(task,
qio_channel_socket_listen_worker,
- addrCopy,
- (GDestroyNotify)qapi_free_SocketAddress,
+ data,
+ qio_channel_listen_worker_free,
context);
}
diff --git a/io/net-listener.c b/io/net-listener.c
index d8cfe52673..5d8a226872 100644
--- a/io/net-listener.c
+++ b/io/net-listener.c
@@ -62,6 +62,7 @@ static gboolean qio_net_listener_channel_func(QIOChannel *ioc,
int qio_net_listener_open_sync(QIONetListener *listener,
SocketAddress *addr,
+ int num,
Error **errp)
{
QIODNSResolver *resolver = qio_dns_resolver_get_instance();
@@ -82,7 +83,7 @@ int qio_net_listener_open_sync(QIONetListener *listener,
for (i = 0; i < nresaddrs; i++) {
QIOChannelSocket *sioc = qio_channel_socket_new();
- if (qio_channel_socket_listen_sync(sioc, resaddrs[i],
+ if (qio_channel_socket_listen_sync(sioc, resaddrs[i], num,
err ? NULL : &err) == 0) {
success = true;
diff --git a/io/trace-events b/io/trace-events
index 378390521e..d7bc70b966 100644
--- a/io/trace-events
+++ b/io/trace-events
@@ -17,8 +17,8 @@ qio_channel_socket_connect_sync(void *ioc, void *addr) "Socket connect sync ioc=
qio_channel_socket_connect_async(void *ioc, void *addr) "Socket connect async ioc=%p addr=%p"
qio_channel_socket_connect_fail(void *ioc) "Socket connect fail ioc=%p"
qio_channel_socket_connect_complete(void *ioc, int fd) "Socket connect complete ioc=%p fd=%d"
-qio_channel_socket_listen_sync(void *ioc, void *addr) "Socket listen sync ioc=%p addr=%p"
-qio_channel_socket_listen_async(void *ioc, void *addr) "Socket listen async ioc=%p addr=%p"
+qio_channel_socket_listen_sync(void *ioc, void *addr, int num) "Socket listen sync ioc=%p addr=%p num=%d"
+qio_channel_socket_listen_async(void *ioc, void *addr, int num) "Socket listen async ioc=%p addr=%p num=%d"
qio_channel_socket_listen_fail(void *ioc) "Socket listen fail ioc=%p"
qio_channel_socket_listen_complete(void *ioc, int fd) "Socket listen complete ioc=%p fd=%d"
qio_channel_socket_dgram_sync(void *ioc, void *localAddr, void *remoteAddr) "Socket dgram sync ioc=%p localAddr=%p remoteAddr=%p"
diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h
index 8a3764919a..3f79356a07 100644
--- a/linux-user/arm/target_cpu.h
+++ b/linux-user/arm/target_cpu.h
@@ -19,9 +19,27 @@
#ifndef ARM_TARGET_CPU_H
#define ARM_TARGET_CPU_H
-/* We need to be able to map the commpage.
- See validate_guest_space in linux-user/elfload.c. */
-#define MAX_RESERVED_VA 0xffff0000ul
+static inline unsigned long arm_max_reserved_va(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
+ /*
+ * There are magic return addresses above 0xfe000000,
+ * and in general a lot of M-profile system stuff in
+ * the high addresses. Restrict linux-user to the
+ * cached write-back RAM in the system map.
+ */
+ return 0x80000000ul;
+ } else {
+ /*
+ * We need to be able to map the commpage.
+ * See validate_guest_space in linux-user/elfload.c.
+ */
+ return 0xffff0000ul;
+ }
+}
+#define MAX_RESERVED_VA arm_max_reserved_va
static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
{
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 3365e192eb..f6693e5760 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -607,9 +607,23 @@ enum {
ARM_HWCAP_A64_SB = 1 << 29,
ARM_HWCAP_A64_PACA = 1 << 30,
ARM_HWCAP_A64_PACG = 1UL << 31,
+
+ ARM_HWCAP2_A64_DCPODP = 1 << 0,
+ ARM_HWCAP2_A64_SVE2 = 1 << 1,
+ ARM_HWCAP2_A64_SVEAES = 1 << 2,
+ ARM_HWCAP2_A64_SVEPMULL = 1 << 3,
+ ARM_HWCAP2_A64_SVEBITPERM = 1 << 4,
+ ARM_HWCAP2_A64_SVESHA3 = 1 << 5,
+ ARM_HWCAP2_A64_SVESM4 = 1 << 6,
+ ARM_HWCAP2_A64_FLAGM2 = 1 << 7,
+ ARM_HWCAP2_A64_FRINT = 1 << 8,
};
-#define ELF_HWCAP get_elf_hwcap()
+#define ELF_HWCAP get_elf_hwcap()
+#define ELF_HWCAP2 get_elf_hwcap2()
+
+#define GET_FEATURE_ID(feat, hwcap) \
+ do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
static uint32_t get_elf_hwcap(void)
{
@@ -621,8 +635,6 @@ static uint32_t get_elf_hwcap(void)
hwcaps |= ARM_HWCAP_A64_CPUID;
/* probe for the extra features */
-#define GET_FEATURE_ID(feat, hwcap) \
- do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
@@ -645,11 +657,22 @@ static uint32_t get_elf_hwcap(void)
GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
-#undef GET_FEATURE_ID
+ return hwcaps;
+}
+
+static uint32_t get_elf_hwcap2(void)
+{
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
+ uint32_t hwcaps = 0;
+
+ GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
+ GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
return hwcaps;
}
+#undef GET_FEATURE_ID
+
#endif /* not TARGET_AARCH64 */
#endif /* TARGET_ARM */
@@ -2380,6 +2403,8 @@ static void load_elf_image(const char *image_name, int image_fd,
}
info->load_bias = load_bias;
+ info->code_offset = load_bias;
+ info->data_offset = load_bias;
info->load_addr = load_addr;
info->entry = ehdr->e_entry + load_bias;
info->start_code = -1;
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 3281c97ca2..c6b9d6ad66 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -112,6 +112,14 @@
IOCTL(BLKZEROOUT, IOC_W, MK_PTR(MK_ARRAY(TYPE_ULONGLONG, 2)))
#endif
+ IOCTL(FDMSGON, 0, TYPE_NULL)
+ IOCTL(FDMSGOFF, 0, TYPE_NULL)
+ IOCTL(FDFLUSH, 0, TYPE_NULL)
+ IOCTL(FDRESET, 0, TYPE_NULL)
+ IOCTL(FDRAWCMD, 0, TYPE_NULL)
+ IOCTL(FDTWADDLE, 0, TYPE_NULL)
+ IOCTL(FDEJECT, 0, TYPE_NULL)
+
#ifdef FIBMAP
IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG))
#endif
@@ -177,6 +185,8 @@
#endif
#endif /* CONFIG_USBFS */
+ IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT))
+ IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
@@ -246,6 +256,9 @@
IOCTL(RNDADDTOENTCNT, IOC_W, MK_PTR(TYPE_INT))
IOCTL(RNDZAPENTCNT, 0, TYPE_NULL)
IOCTL(RNDCLEARPOOL, 0, TYPE_NULL)
+#ifdef RNDRESEEDCRNG
+ IOCTL(RNDRESEEDCRNG, 0, TYPE_NULL)
+#endif
IOCTL(CDROMPAUSE, 0, TYPE_NULL)
IOCTL(CDROMSTART, 0, TYPE_NULL)
diff --git a/linux-user/main.c b/linux-user/main.c
index 47917bbb20..560d053f72 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -49,7 +49,6 @@
char *exec_path;
int singlestep;
-static const char *filename;
static const char *argv0;
static int gdbstub_port;
static envlist_t *envlist;
@@ -78,12 +77,12 @@ int have_guest_base;
(TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
/* There are a number of places where we assign reserved_va to a variable
of type abi_ulong and expect it to fit. Avoid the last page. */
-# define MAX_RESERVED_VA (0xfffffffful & TARGET_PAGE_MASK)
+# define MAX_RESERVED_VA(CPU) (0xfffffffful & TARGET_PAGE_MASK)
# else
-# define MAX_RESERVED_VA (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
+# define MAX_RESERVED_VA(CPU) (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
# endif
# else
-# define MAX_RESERVED_VA 0
+# define MAX_RESERVED_VA(CPU) 0
# endif
#endif
@@ -236,7 +235,7 @@ static void handle_arg_log(const char *arg)
static void handle_arg_dfilter(const char *arg)
{
- qemu_set_dfilter_ranges(arg, NULL);
+ qemu_set_dfilter_ranges(arg, &error_fatal);
}
static void handle_arg_log_filename(const char *arg)
@@ -357,8 +356,7 @@ static void handle_arg_reserved_va(const char *arg)
unsigned long unshifted = reserved_va;
p++;
reserved_va <<= shift;
- if (reserved_va >> shift != unshifted
- || (MAX_RESERVED_VA && reserved_va > MAX_RESERVED_VA)) {
+ if (reserved_va >> shift != unshifted) {
fprintf(stderr, "Reserved virtual address too big\n");
exit(EXIT_FAILURE);
}
@@ -393,6 +391,13 @@ static void handle_arg_trace(const char *arg)
trace_file = trace_opt_parse(arg);
}
+#if defined(TARGET_XTENSA)
+static void handle_arg_abi_call0(const char *arg)
+{
+ xtensa_set_abi_call0();
+}
+#endif
+
struct qemu_argument {
const char *argv;
const char *env;
@@ -446,6 +451,10 @@ static const struct qemu_argument arg_table[] = {
"", "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
{"version", "QEMU_VERSION", false, handle_arg_version,
"", "display version information and exit"},
+#if defined(TARGET_XTENSA)
+ {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0,
+ "", "assume CALL0 Xtensa ABI"},
+#endif
{NULL, NULL, false, NULL, NULL, NULL}
};
@@ -586,7 +595,6 @@ static int parse_args(int argc, char **argv)
exit(EXIT_FAILURE);
}
- filename = argv[optind];
exec_path = argv[optind];
return optind;
@@ -607,6 +615,7 @@ int main(int argc, char **argv, char **envp)
int i;
int ret;
int execfd;
+ unsigned long max_reserved_va;
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
@@ -657,9 +666,9 @@ int main(int argc, char **argv, char **envp)
execfd = qemu_getauxval(AT_EXECFD);
if (execfd == 0) {
- execfd = open(filename, O_RDONLY);
+ execfd = open(exec_path, O_RDONLY);
if (execfd < 0) {
- printf("Error while loading %s: %s\n", filename, strerror(errno));
+ printf("Error while loading %s: %s\n", exec_path, strerror(errno));
_exit(EXIT_FAILURE);
}
}
@@ -672,31 +681,31 @@ int main(int argc, char **argv, char **envp)
/* init tcg before creating CPUs and to get qemu_host_page_size */
tcg_exec_init(0);
- /* Reserving *too* much vm space via mmap can run into problems
- with rlimits, oom due to page table creation, etc. We will still try it,
- if directed by the command-line option, but not by default. */
- if (HOST_LONG_BITS == 64 &&
- TARGET_VIRT_ADDR_SPACE_BITS <= 32 &&
- reserved_va == 0) {
- /* reserved_va must be aligned with the host page size
- * as it is used with mmap()
- */
- reserved_va = MAX_RESERVED_VA & qemu_host_page_mask;
- }
-
cpu = cpu_create(cpu_type);
env = cpu->env_ptr;
cpu_reset(cpu);
-
thread_cpu = cpu;
- if (getenv("QEMU_STRACE")) {
- do_strace = 1;
+ /*
+ * Reserving too much vm space via mmap can run into problems
+ * with rlimits, oom due to page table creation, etc. We will
+ * still try it, if directed by the command-line option, but
+ * not by default.
+ */
+ max_reserved_va = MAX_RESERVED_VA(cpu);
+ if (reserved_va != 0) {
+ if (max_reserved_va && reserved_va > max_reserved_va) {
+ fprintf(stderr, "Reserved virtual address too big\n");
+ exit(EXIT_FAILURE);
+ }
+ } else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) {
+ /*
+ * reserved_va must be aligned with the host page size
+ * as it is used with mmap()
+ */
+ reserved_va = max_reserved_va & qemu_host_page_mask;
}
- if (seed_optarg == NULL) {
- seed_optarg = getenv("QEMU_RAND_SEED");
- }
{
Error *err = NULL;
if (seed_optarg != NULL) {
@@ -784,10 +793,10 @@ int main(int argc, char **argv, char **envp)
cpu->opaque = ts;
task_settid(ts);
- ret = loader_exec(execfd, filename, target_argv, target_environ, regs,
+ ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs,
info, &bprm);
if (ret != 0) {
- printf("Error while loading %s: %s\n", filename, strerror(-ret));
+ printf("Error while loading %s: %s\n", exec_path, strerror(-ret));
_exit(EXIT_FAILURE);
}
diff --git a/linux-user/openrisc/target_elf.h b/linux-user/openrisc/target_elf.h
index 40ceb025c9..265ecd3079 100644
--- a/linux-user/openrisc/target_elf.h
+++ b/linux-user/openrisc/target_elf.h
@@ -9,6 +9,6 @@
#define OPENRISC_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
- return "or1200";
+ return "any";
}
#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8b41a03901..e2af3c1494 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qemu/path.h"
+#include "qemu/memfd.h"
#include "qemu/queue.h"
#include <elf.h>
#include <endian.h>
@@ -88,6 +89,7 @@
#include <linux/kd.h>
#include <linux/mtio.h>
#include <linux/fs.h>
+#include <linux/fd.h>
#if defined(CONFIG_FIEMAP)
#include <linux/fiemap.h>
#endif
@@ -11847,7 +11849,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
timer_t htimer = g_posix_timers[timerid];
ret = get_errno(timer_getoverrun(htimer));
}
- fd_trans_unregister(ret);
return ret;
}
#endif
@@ -11939,6 +11940,17 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
/* PowerPC specific. */
return do_swapcontext(cpu_env, arg1, arg2, arg3);
#endif
+#ifdef TARGET_NR_memfd_create
+ case TARGET_NR_memfd_create:
+ p = lock_user_string(arg1);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(memfd_create(p, arg2));
+ fd_trans_unregister(ret);
+ unlock_user(p, arg1, 0);
+ return ret;
+#endif
default:
qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 0662270300..fa69c6ab8d 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -758,10 +758,14 @@ struct target_pollfd {
#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SH4) || \
defined(TARGET_XTENSA)
+#define TARGET_FIOGETOWN TARGET_IOR('f', 123, int)
+#define TARGET_FIOSETOWN TARGET_IOW('f', 124, int)
#define TARGET_SIOCATMARK TARGET_IOR('s', 7, int)
#define TARGET_SIOCSPGRP TARGET_IOW('s', 8, pid_t)
#define TARGET_SIOCGPGRP TARGET_IOR('s', 9, pid_t)
#else
+#define TARGET_FIOGETOWN 0x8903
+#define TARGET_FIOSETOWN 0x8901
#define TARGET_SIOCATMARK 0x8905
#define TARGET_SIOCSPGRP 0x8902
#define TARGET_SIOCGPGRP 0x8904
@@ -850,6 +854,7 @@ struct target_pollfd {
#define TARGET_RNDADDTOENTCNT TARGET_IOW('R', 0x01, int)
#define TARGET_RNDZAPENTCNT TARGET_IO('R', 0x04)
#define TARGET_RNDCLEARPOOL TARGET_IO('R', 0x06)
+#define TARGET_RNDRESEEDCRNG TARGET_IO('R', 0x07)
/* From <linux/fs.h> */
@@ -883,6 +888,16 @@ struct target_pollfd {
#define TARGET_BLKROTATIONAL TARGET_IO(0x12, 126)
#define TARGET_BLKZEROOUT TARGET_IO(0x12, 127)
+/* From <linux/fd.h> */
+
+#define TARGET_FDMSGON TARGET_IO(2, 0x45)
+#define TARGET_FDMSGOFF TARGET_IO(2, 0x46)
+#define TARGET_FDFLUSH TARGET_IO(2, 0x4b)
+#define TARGET_FDRESET TARGET_IO(2, 0x54)
+#define TARGET_FDRAWCMD TARGET_IO(2, 0x58)
+#define TARGET_FDTWADDLE TARGET_IO(2, 0x59)
+#define TARGET_FDEJECT TARGET_IO(2, 0x5a)
+
#define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */
#define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index 8d54ef3ae3..590f0313ff 100644
--- a/linux-user/xtensa/signal.c
+++ b/linux-user/xtensa/signal.c
@@ -134,6 +134,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
abi_ulong frame_addr;
struct target_rt_sigframe *frame;
uint32_t ra;
+ bool abi_call0;
+ unsigned base;
int i;
frame_addr = get_sigframe(ka, env, sizeof(*frame));
@@ -182,20 +184,27 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
__put_user(0x00, &frame->retcode[5]);
#endif
}
- env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT);
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER)) {
- env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT);
- }
memset(env->regs, 0, sizeof(env->regs));
env->pc = ka->_sa_handler;
env->regs[1] = frame_addr;
env->sregs[WINDOW_BASE] = 0;
env->sregs[WINDOW_START] = 1;
- env->regs[4] = (ra & 0x3fffffff) | 0x40000000;
- env->regs[6] = sig;
- env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, info);
- env->regs[8] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ abi_call0 = (env->sregs[PS] & PS_WOE) == 0;
+ env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT);
+
+ if (abi_call0) {
+ base = 0;
+ env->regs[base] = ra;
+ } else {
+ env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT);
+ base = 4;
+ env->regs[base] = (ra & 0x3fffffff) | 0x40000000;
+ }
+ env->regs[base + 2] = sig;
+ env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe,
+ info);
+ env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, uc);
unlock_user_struct(frame, frame_addr, 1);
return;
diff --git a/memory.c b/memory.c
index 7fd93b1d42..61a254c3f9 100644
--- a/memory.c
+++ b/memory.c
@@ -351,32 +351,23 @@ static bool memory_region_big_endian(MemoryRegion *mr)
#endif
}
-static bool memory_region_wrong_endianness(MemoryRegion *mr)
+static void adjust_endianness(MemoryRegion *mr, uint64_t *data, MemOp op)
{
-#ifdef TARGET_WORDS_BIGENDIAN
- return mr->ops->endianness == DEVICE_LITTLE_ENDIAN;
-#else
- return mr->ops->endianness == DEVICE_BIG_ENDIAN;
-#endif
-}
-
-static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size)
-{
- if (memory_region_wrong_endianness(mr)) {
- switch (size) {
- case 1:
+ if ((op & MO_BSWAP) != devend_memop(mr->ops->endianness)) {
+ switch (op & MO_SIZE) {
+ case MO_8:
break;
- case 2:
+ case MO_16:
*data = bswap16(*data);
break;
- case 4:
+ case MO_32:
*data = bswap32(*data);
break;
- case 8:
+ case MO_64:
*data = bswap64(*data);
break;
default:
- abort();
+ g_assert_not_reached();
}
}
}
@@ -1446,9 +1437,10 @@ static MemTxResult memory_region_dispatch_read1(MemoryRegion *mr,
MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
hwaddr addr,
uint64_t *pval,
- unsigned size,
+ MemOp op,
MemTxAttrs attrs)
{
+ unsigned size = memop_size(op);
MemTxResult r;
if (!memory_region_access_valid(mr, addr, size, false, attrs)) {
@@ -1457,7 +1449,7 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
}
r = memory_region_dispatch_read1(mr, addr, pval, size, attrs);
- adjust_endianness(mr, pval, size);
+ adjust_endianness(mr, pval, op);
return r;
}
@@ -1490,15 +1482,17 @@ static bool memory_region_dispatch_write_eventfds(MemoryRegion *mr,
MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
hwaddr addr,
uint64_t data,
- unsigned size,
+ MemOp op,
MemTxAttrs attrs)
{
+ unsigned size = memop_size(op);
+
if (!memory_region_access_valid(mr, addr, size, true, attrs)) {
unassigned_mem_write(mr, addr, data, size);
return MEMTX_DECODE_ERROR;
}
- adjust_endianness(mr, &data, size);
+ adjust_endianness(mr, &data, op);
if ((!kvm_eventfds_enabled()) &&
memory_region_dispatch_write_eventfds(mr, addr, data, size, attrs)) {
@@ -1922,15 +1916,6 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
}
}
-void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr)
-{
- IOMMUNotifier *notifier;
-
- IOMMU_NOTIFIER_FOREACH(notifier, iommu_mr) {
- memory_region_iommu_replay(iommu_mr, notifier);
- }
-}
-
void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n)
{
@@ -2347,7 +2332,7 @@ void memory_region_add_eventfd(MemoryRegion *mr,
}
if (size) {
- adjust_endianness(mr, &mrfd.data, size);
+ adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE);
}
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
@@ -2382,7 +2367,7 @@ void memory_region_del_eventfd(MemoryRegion *mr,
unsigned i;
if (size) {
- adjust_endianness(mr, &mrfd.data, size);
+ adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE);
}
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
@@ -3282,3 +3267,21 @@ static void memory_register_types(void)
}
type_init(memory_register_types)
+
+MemOp devend_memop(enum device_endian end)
+{
+ static MemOp conv[] = {
+ [DEVICE_LITTLE_ENDIAN] = MO_LE,
+ [DEVICE_BIG_ENDIAN] = MO_BE,
+ [DEVICE_NATIVE_ENDIAN] = MO_TE,
+ [DEVICE_HOST_ENDIAN] = 0,
+ };
+ switch (end) {
+ case DEVICE_LITTLE_ENDIAN:
+ case DEVICE_BIG_ENDIAN:
+ case DEVICE_NATIVE_ENDIAN:
+ return conv[end];
+ default:
+ g_assert_not_reached();
+ }
+}
diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c
index acf865b900..c54aee4a95 100644
--- a/memory_ldst.inc.c
+++ b/memory_ldst.inc.c
@@ -38,16 +38,8 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
release_lock |= prepare_mmio_access(mr);
/* I/O case */
- r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs);
-#if defined(TARGET_WORDS_BIGENDIAN)
- if (endian == DEVICE_LITTLE_ENDIAN) {
- val = bswap32(val);
- }
-#else
- if (endian == DEVICE_BIG_ENDIAN) {
- val = bswap32(val);
- }
-#endif
+ r = memory_region_dispatch_read(mr, addr1, &val,
+ MO_32 | devend_memop(endian), attrs);
} else {
/* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -114,16 +106,8 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
release_lock |= prepare_mmio_access(mr);
/* I/O case */
- r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs);
-#if defined(TARGET_WORDS_BIGENDIAN)
- if (endian == DEVICE_LITTLE_ENDIAN) {
- val = bswap64(val);
- }
-#else
- if (endian == DEVICE_BIG_ENDIAN) {
- val = bswap64(val);
- }
-#endif
+ r = memory_region_dispatch_read(mr, addr1, &val,
+ MO_64 | devend_memop(endian), attrs);
} else {
/* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -188,7 +172,7 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL,
release_lock |= prepare_mmio_access(mr);
/* I/O case */
- r = memory_region_dispatch_read(mr, addr1, &val, 1, attrs);
+ r = memory_region_dispatch_read(mr, addr1, &val, MO_8, attrs);
} else {
/* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -224,16 +208,8 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
release_lock |= prepare_mmio_access(mr);
/* I/O case */
- r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs);
-#if defined(TARGET_WORDS_BIGENDIAN)
- if (endian == DEVICE_LITTLE_ENDIAN) {
- val = bswap16(val);
- }
-#else
- if (endian == DEVICE_BIG_ENDIAN) {
- val = bswap16(val);
- }
-#endif
+ r = memory_region_dispatch_read(mr, addr1, &val,
+ MO_16 | devend_memop(endian), attrs);
} else {
/* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -300,7 +276,7 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL,
if (l < 4 || !memory_access_is_direct(mr, true)) {
release_lock |= prepare_mmio_access(mr);
- r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
+ r = memory_region_dispatch_write(mr, addr1, val, MO_32, attrs);
} else {
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
stl_p(ptr, val);
@@ -336,17 +312,8 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 4 || !memory_access_is_direct(mr, true)) {
release_lock |= prepare_mmio_access(mr);
-
-#if defined(TARGET_WORDS_BIGENDIAN)
- if (endian == DEVICE_LITTLE_ENDIAN) {
- val = bswap32(val);
- }
-#else
- if (endian == DEVICE_BIG_ENDIAN) {
- val = bswap32(val);
- }
-#endif
- r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
+ r = memory_region_dispatch_write(mr, addr1, val,
+ MO_32 | devend_memop(endian), attrs);
} else {
/* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -408,7 +375,7 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL,
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (!memory_access_is_direct(mr, true)) {
release_lock |= prepare_mmio_access(mr);
- r = memory_region_dispatch_write(mr, addr1, val, 1, attrs);
+ r = memory_region_dispatch_write(mr, addr1, val, MO_8, attrs);
} else {
/* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -441,17 +408,8 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 2 || !memory_access_is_direct(mr, true)) {
release_lock |= prepare_mmio_access(mr);
-
-#if defined(TARGET_WORDS_BIGENDIAN)
- if (endian == DEVICE_LITTLE_ENDIAN) {
- val = bswap16(val);
- }
-#else
- if (endian == DEVICE_BIG_ENDIAN) {
- val = bswap16(val);
- }
-#endif
- r = memory_region_dispatch_write(mr, addr1, val, 2, attrs);
+ r = memory_region_dispatch_write(mr, addr1, val,
+ MO_16 | devend_memop(endian), attrs);
} else {
/* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
@@ -514,17 +472,8 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 8 || !memory_access_is_direct(mr, true)) {
release_lock |= prepare_mmio_access(mr);
-
-#if defined(TARGET_WORDS_BIGENDIAN)
- if (endian == DEVICE_LITTLE_ENDIAN) {
- val = bswap64(val);
- }
-#else
- if (endian == DEVICE_BIG_ENDIAN) {
- val = bswap64(val);
- }
-#endif
- r = memory_region_dispatch_write(mr, addr1, val, 8, attrs);
+ r = memory_region_dispatch_write(mr, addr1, val,
+ MO_64 | devend_memop(endian), attrs);
} else {
/* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
diff --git a/migration/socket.c b/migration/socket.c
index 98efdc0286..97c9efde59 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -178,10 +178,15 @@ static void socket_start_incoming_migration(SocketAddress *saddr,
{
QIONetListener *listener = qio_net_listener_new();
size_t i;
+ int num = 1;
qio_net_listener_set_name(listener, "migration-socket-listener");
- if (qio_net_listener_open_sync(listener, saddr, errp) < 0) {
+ if (migrate_use_multifd()) {
+ num = migrate_multifd_channels();
+ }
+
+ if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) {
object_unref(OBJECT(listener));
return;
}
diff --git a/nbd/client.c b/nbd/client.c
index 49bf9906f9..b9dc829175 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2018 Red Hat, Inc.
+ * Copyright (C) 2016-2019 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device Client Side
@@ -142,17 +142,18 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt,
return 0;
}
-/* If reply represents success, return 1 without further action.
- * If reply represents an error, consume the optional payload of
- * the packet on ioc. Then return 0 for unsupported (so the client
- * can fall back to other approaches), or -1 with errp set for other
- * errors.
+/*
+ * If reply represents success, return 1 without further action. If
+ * reply represents an error, consume the optional payload of the
+ * packet on ioc. Then return 0 for unsupported (so the client can
+ * fall back to other approaches), where @strict determines if only
+ * ERR_UNSUP or all errors fit that category, or -1 with errp set for
+ * other errors.
*/
static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
- Error **errp)
+ bool strict, Error **errp)
{
- char *msg = NULL;
- int result = -1;
+ g_autofree char *msg = NULL;
if (!(reply->type & (1 << 31))) {
return 1;
@@ -163,26 +164,28 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
error_setg(errp, "server error %" PRIu32
" (%s) message is too long",
reply->type, nbd_rep_lookup(reply->type));
- goto cleanup;
+ goto err;
}
msg = g_malloc(reply->length + 1);
if (nbd_read(ioc, msg, reply->length, NULL, errp) < 0) {
error_prepend(errp, "Failed to read option error %" PRIu32
" (%s) message: ",
reply->type, nbd_rep_lookup(reply->type));
- goto cleanup;
+ goto err;
}
msg[reply->length] = '\0';
trace_nbd_server_error_msg(reply->type,
nbd_reply_type_lookup(reply->type), msg);
}
- switch (reply->type) {
- case NBD_REP_ERR_UNSUP:
- trace_nbd_reply_err_unsup(reply->option, nbd_opt_lookup(reply->option));
- result = 0;
- goto cleanup;
+ if (reply->type == NBD_REP_ERR_UNSUP || !strict) {
+ trace_nbd_reply_err_ignored(reply->option,
+ nbd_opt_lookup(reply->option),
+ reply->type, nbd_rep_lookup(reply->type));
+ return 0;
+ }
+ switch (reply->type) {
case NBD_REP_ERR_POLICY:
error_setg(errp, "Denied by server for option %" PRIu32 " (%s)",
reply->option, nbd_opt_lookup(reply->option));
@@ -227,12 +230,9 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
error_append_hint(errp, "server reported: %s\n", msg);
}
- cleanup:
- g_free(msg);
- if (result < 0) {
- nbd_send_opt_abort(ioc);
- }
- return result;
+ err:
+ nbd_send_opt_abort(ioc);
+ return -1;
}
/* nbd_receive_list:
@@ -247,18 +247,17 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
Error **errp)
{
- int ret = -1;
NBDOptionReply reply;
uint32_t len;
uint32_t namelen;
- char *local_name = NULL;
- char *local_desc = NULL;
+ g_autofree char *local_name = NULL;
+ g_autofree char *local_desc = NULL;
int error;
if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) {
return -1;
}
- error = nbd_handle_reply_err(ioc, &reply, errp);
+ error = nbd_handle_reply_err(ioc, &reply, true, errp);
if (error <= 0) {
return error;
}
@@ -298,7 +297,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
local_name = g_malloc(namelen + 1);
if (nbd_read(ioc, local_name, namelen, "export name", errp) < 0) {
nbd_send_opt_abort(ioc);
- goto out;
+ return -1;
}
local_name[namelen] = '\0';
len -= namelen;
@@ -306,24 +305,17 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
local_desc = g_malloc(len + 1);
if (nbd_read(ioc, local_desc, len, "export description", errp) < 0) {
nbd_send_opt_abort(ioc);
- goto out;
+ return -1;
}
local_desc[len] = '\0';
}
trace_nbd_receive_list(local_name, local_desc ?: "");
- *name = local_name;
- local_name = NULL;
+ *name = g_steal_pointer(&local_name);
if (description) {
- *description = local_desc;
- local_desc = NULL;
+ *description = g_steal_pointer(&local_desc);
}
- ret = 1;
-
- out:
- g_free(local_name);
- g_free(local_desc);
- return ret;
+ return 1;
}
@@ -371,7 +363,7 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt,
if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) {
return -1;
}
- error = nbd_handle_reply_err(ioc, &reply, errp);
+ error = nbd_handle_reply_err(ioc, &reply, true, errp);
if (error <= 0) {
return error;
}
@@ -546,12 +538,15 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
}
}
-/* nbd_request_simple_option: Send an option request, and parse the reply
+/*
+ * nbd_request_simple_option: Send an option request, and parse the reply.
+ * @strict controls whether ERR_UNSUP or all errors produce 0 status.
* return 1 for successful negotiation,
* 0 if operation is unsupported,
* -1 with errp set for any other error
*/
-static int nbd_request_simple_option(QIOChannel *ioc, int opt, Error **errp)
+static int nbd_request_simple_option(QIOChannel *ioc, int opt, bool strict,
+ Error **errp)
{
NBDOptionReply reply;
int error;
@@ -563,7 +558,7 @@ static int nbd_request_simple_option(QIOChannel *ioc, int opt, Error **errp)
if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) {
return -1;
}
- error = nbd_handle_reply_err(ioc, &reply, errp);
+ error = nbd_handle_reply_err(ioc, &reply, strict, errp);
if (error <= 0) {
return error;
}
@@ -595,7 +590,7 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
QIOChannelTLS *tioc;
struct NBDTLSHandshakeData data = { 0 };
- ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, errp);
+ ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, true, errp);
if (ret <= 0) {
if (ret == 0) {
error_setg(errp, "Server don't support STARTTLS option");
@@ -695,7 +690,7 @@ static int nbd_receive_one_meta_context(QIOChannel *ioc,
return -1;
}
- ret = nbd_handle_reply_err(ioc, &reply, errp);
+ ret = nbd_handle_reply_err(ioc, &reply, false, errp);
if (ret <= 0) {
return ret;
}
@@ -951,7 +946,7 @@ static int nbd_start_negotiate(AioContext *aio_context, QIOChannel *ioc,
if (structured_reply) {
result = nbd_request_simple_option(ioc,
NBD_OPT_STRUCTURED_REPLY,
- errp);
+ false, errp);
if (result < 0) {
return -EINVAL;
}
diff --git a/nbd/common.c b/nbd/common.c
index cc8b278e54..ddfe7d1183 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -201,6 +201,8 @@ const char *nbd_err_lookup(int err)
return "ENOSPC";
case NBD_EOVERFLOW:
return "EOVERFLOW";
+ case NBD_ENOTSUP:
+ return "ENOTSUP";
case NBD_ESHUTDOWN:
return "ESHUTDOWN";
default:
@@ -231,6 +233,9 @@ int nbd_errno_to_system_errno(int err)
case NBD_EOVERFLOW:
ret = EOVERFLOW;
break;
+ case NBD_ENOTSUP:
+ ret = ENOTSUP;
+ break;
case NBD_ESHUTDOWN:
ret = ESHUTDOWN;
break;
diff --git a/nbd/server.c b/nbd/server.c
index f55ccf8edf..28c3c8be85 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -55,6 +55,11 @@ static int system_errno_to_nbd_errno(int err)
return NBD_ENOSPC;
case EOVERFLOW:
return NBD_EOVERFLOW;
+ case ENOTSUP:
+#if ENOTSUP != EOPNOTSUPP
+ case EOPNOTSUPP:
+#endif
+ return NBD_ENOTSUP;
case ESHUTDOWN:
return NBD_ESHUTDOWN;
case EINVAL:
@@ -206,7 +211,7 @@ static int GCC_FMT_ATTR(4, 0)
nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
Error **errp, const char *fmt, va_list va)
{
- char *msg;
+ g_autofree char *msg = NULL;
int ret;
size_t len;
@@ -216,18 +221,14 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
trace_nbd_negotiate_send_rep_err(msg);
ret = nbd_negotiate_send_rep_len(client, type, len, errp);
if (ret < 0) {
- goto out;
+ return ret;
}
if (nbd_write(client->ioc, msg, len, errp) < 0) {
error_prepend(errp, "write failed (error message): ");
- ret = -EIO;
- } else {
- ret = 0;
+ return -EIO;
}
-out:
- g_free(msg);
- return ret;
+ return 0;
}
/* Send an error reply.
@@ -423,14 +424,14 @@ static void nbd_check_meta_export(NBDClient *client)
/* Send a reply to NBD_OPT_EXPORT_NAME.
* Return -errno on error, 0 on success. */
-static int nbd_negotiate_handle_export_name(NBDClient *client,
- uint16_t myflags, bool no_zeroes,
+static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
Error **errp)
{
char name[NBD_MAX_NAME_SIZE + 1];
char buf[NBD_REPLY_EXPORT_NAME_SIZE] = "";
size_t len;
int ret;
+ uint16_t myflags;
/* Client sends:
[20 .. xx] export name (length bytes)
@@ -458,10 +459,13 @@ static int nbd_negotiate_handle_export_name(NBDClient *client,
return -EINVAL;
}
- trace_nbd_negotiate_new_style_size_flags(client->exp->size,
- client->exp->nbdflags | myflags);
+ myflags = client->exp->nbdflags;
+ if (client->structured_reply) {
+ myflags |= NBD_FLAG_SEND_DF;
+ }
+ trace_nbd_negotiate_new_style_size_flags(client->exp->size, myflags);
stq_be_p(buf, client->exp->size);
- stw_be_p(buf + 8, client->exp->nbdflags | myflags);
+ stw_be_p(buf + 8, myflags);
len = no_zeroes ? 10 : sizeof(buf);
ret = nbd_write(client->ioc, buf, len, errp);
if (ret < 0) {
@@ -526,8 +530,7 @@ static int nbd_reject_length(NBDClient *client, bool fatal, Error **errp)
/* Handle NBD_OPT_INFO and NBD_OPT_GO.
* Return -errno on error, 0 if ready for next option, and 1 to move
* into transmission phase. */
-static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
- Error **errp)
+static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
{
int rc;
char name[NBD_MAX_NAME_SIZE + 1];
@@ -540,6 +543,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
uint32_t sizes[3];
char buf[sizeof(uint64_t) + sizeof(uint16_t)];
uint32_t check_align = 0;
+ uint16_t myflags;
/* Client sends:
4 bytes: L, name length (can be 0)
@@ -637,10 +641,13 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
}
/* Send NBD_INFO_EXPORT always */
- trace_nbd_negotiate_new_style_size_flags(exp->size,
- exp->nbdflags | myflags);
+ myflags = exp->nbdflags;
+ if (client->structured_reply) {
+ myflags |= NBD_FLAG_SEND_DF;
+ }
+ trace_nbd_negotiate_new_style_size_flags(exp->size, myflags);
stq_be_p(buf, exp->size);
- stw_be_p(buf + 8, exp->nbdflags | myflags);
+ stw_be_p(buf + 8, myflags);
rc = nbd_negotiate_send_info(client, NBD_INFO_EXPORT,
sizeof(buf), buf, errp);
if (rc < 0) {
@@ -1037,8 +1044,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
* 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect,
* errp is not set
*/
-static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
- Error **errp)
+static int nbd_negotiate_options(NBDClient *client, Error **errp)
{
uint32_t flags;
bool fixedNewstyle = false;
@@ -1172,13 +1178,12 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
return 1;
case NBD_OPT_EXPORT_NAME:
- return nbd_negotiate_handle_export_name(client,
- myflags, no_zeroes,
+ return nbd_negotiate_handle_export_name(client, no_zeroes,
errp);
case NBD_OPT_INFO:
case NBD_OPT_GO:
- ret = nbd_negotiate_handle_info(client, myflags, errp);
+ ret = nbd_negotiate_handle_info(client, errp);
if (ret == 1) {
assert(option == NBD_OPT_GO);
return 0;
@@ -1209,7 +1214,6 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
} else {
ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp);
client->structured_reply = true;
- myflags |= NBD_FLAG_SEND_DF;
}
break;
@@ -1232,8 +1236,7 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
*/
switch (option) {
case NBD_OPT_EXPORT_NAME:
- return nbd_negotiate_handle_export_name(client,
- myflags, no_zeroes,
+ return nbd_negotiate_handle_export_name(client, no_zeroes,
errp);
default:
@@ -1259,9 +1262,6 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp)
{
char buf[NBD_OLDSTYLE_NEGOTIATE_SIZE] = "";
int ret;
- const uint16_t myflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_TRIM |
- NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA |
- NBD_FLAG_SEND_WRITE_ZEROES | NBD_FLAG_SEND_CACHE);
/* Old style negotiation header, no room for options
[ 0 .. 7] passwd ("NBDMAGIC")
@@ -1289,7 +1289,7 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp)
error_prepend(errp, "write failed: ");
return -EINVAL;
}
- ret = nbd_negotiate_options(client, myflags, errp);
+ ret = nbd_negotiate_options(client, errp);
if (ret != 0) {
if (ret < 0) {
error_prepend(errp, "option negotiation failed: ");
@@ -1461,7 +1461,7 @@ static void nbd_eject_notifier(Notifier *n, void *data)
NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
uint64_t size, const char *name, const char *desc,
- const char *bitmap, uint16_t nbdflags,
+ const char *bitmap, bool readonly, bool shared,
void (*close)(NBDExport *), bool writethrough,
BlockBackend *on_eject_blk, Error **errp)
{
@@ -1485,7 +1485,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
/* Don't allow resize while the NBD server is running, otherwise we don't
* care what happens with the node. */
perm = BLK_PERM_CONSISTENT_READ;
- if ((nbdflags & NBD_FLAG_READ_ONLY) == 0) {
+ if (!readonly) {
perm |= BLK_PERM_WRITE;
}
blk = blk_new(bdrv_get_aio_context(bs), perm,
@@ -1505,7 +1505,17 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
exp->dev_offset = dev_offset;
exp->name = g_strdup(name);
exp->description = g_strdup(desc);
- exp->nbdflags = nbdflags;
+ exp->nbdflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_FLUSH |
+ NBD_FLAG_SEND_FUA | NBD_FLAG_SEND_CACHE);
+ if (readonly) {
+ exp->nbdflags |= NBD_FLAG_READ_ONLY;
+ if (shared) {
+ exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN;
+ }
+ } else {
+ exp->nbdflags |= (NBD_FLAG_SEND_TRIM | NBD_FLAG_SEND_WRITE_ZEROES |
+ NBD_FLAG_SEND_FAST_ZERO);
+ }
assert(size <= INT64_MAX - dev_offset);
exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
@@ -1530,7 +1540,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
goto fail;
}
- if ((nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) &&
+ if (readonly && bdrv_is_writable(bs) &&
bdrv_dirty_bitmap_enabled(bm)) {
error_setg(errp,
"Enabled bitmap '%s' incompatible with readonly export",
@@ -2157,7 +2167,7 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
if (request->type == NBD_CMD_READ && client->structured_reply) {
valid_flags |= NBD_CMD_FLAG_DF;
} else if (request->type == NBD_CMD_WRITE_ZEROES) {
- valid_flags |= NBD_CMD_FLAG_NO_HOLE;
+ valid_flags |= NBD_CMD_FLAG_NO_HOLE | NBD_CMD_FLAG_FAST_ZERO;
} else if (request->type == NBD_CMD_BLOCK_STATUS) {
valid_flags |= NBD_CMD_FLAG_REQ_ONE;
}
@@ -2296,6 +2306,9 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
if (!(request->flags & NBD_CMD_FLAG_NO_HOLE)) {
flags |= BDRV_REQ_MAY_UNMAP;
}
+ if (request->flags & NBD_CMD_FLAG_FAST_ZERO) {
+ flags |= BDRV_REQ_NO_FALLBACK;
+ }
ret = blk_pwrite_zeroes(exp->blk, request->from + exp->dev_offset,
request->len, flags);
return nbd_send_generic_reply(client, request->handle, ret,
diff --git a/nbd/trace-events b/nbd/trace-events
index 7ab6b3788c..f6cde96790 100644
--- a/nbd/trace-events
+++ b/nbd/trace-events
@@ -4,7 +4,7 @@
nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending option request %" PRIu32" (%s), len %" PRIu32
nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32
nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s"
-nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback"
+nbd_reply_err_ignored(uint32_t option, const char *name, uint32_t reply, const char *reply_name) "server failed request %" PRIu32 " (%s) with error 0x%" PRIx32 " (%s), attempting fallback"
nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'"
nbd_opt_info_go_start(const char *opt, const char *name) "Attempting %s for export '%s'"
nbd_opt_info_go_success(const char *opt) "Export is ready after %s request"
diff --git a/pc-bios/README b/pc-bios/README
index d59cd25461..ad78f6dc49 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20190719.
+ built from git tag qemu-slof-20190827.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/skiboot.lid b/pc-bios/skiboot.lid
index 6d5966c3ae..504b95e8b6 100644
--- a/pc-bios/skiboot.lid
+++ b/pc-bios/skiboot.lid
Binary files differ
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index fb0837508b..a3a3e49332 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/qapi/machine.json b/qapi/machine.json
index de5c742d72..ca26779f1a 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -348,13 +348,16 @@
# in future versions of QEMU according to the QEMU deprecation
# policy (since 4.1.0)
#
+# @default-cpu-type: default CPU model typename if none is requested via
+# the -cpu argument. (since 4.2)
+#
# Since: 1.2.0
##
{ 'struct': 'MachineInfo',
'data': { 'name': 'str', '*alias': 'str',
'*is-default': 'bool', 'cpu-max': 'int',
'hotpluggable-cpus': 'bool', 'numa-mem-supported': 'bool',
- 'deprecated': 'bool' } }
+ 'deprecated': 'bool', '*default-cpu-type': 'str' } }
##
# @query-machines:
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index 00a4b6f350..9d74a1cfc0 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -72,6 +72,13 @@ backend settings instead of environment variables. To ease migration to
the new format, the ``-audiodev-help'' option can be used to convert
the current values of the environment variables to ``-audiodev'' options.
+@subsection Creating sound card devices and vnc without audiodev= property (since 4.2)
+
+When not using the deprecated legacy audio config, each sound card
+should specify an @code{audiodev=} property. Additionally, when using
+vnc, you should specify an @code{audiodev=} propery if you plan to
+transmit audio through the VNC protocol.
+
@subsection -mon ...,control=readline,pretty=on|off (since 4.1)
The @code{pretty=on|off} switch has no effect for HMP monitors, but is
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 577d1e8376..b47e89cfca 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -11,6 +11,9 @@
@paragraphindent 0
@c %**end of header
+@set qemu_system qemu-system-x86_64
+@set qemu_system_x86 qemu-system-x86_64
+
@ifinfo
@direntry
* QEMU: (qemu-doc). The QEMU Emulator User Documentation.
@@ -207,12 +210,12 @@ Note that, by default, GUS shares IRQ(7) with parallel ports and so
QEMU must be told to not have parallel ports to have working GUS.
@example
-qemu-system-i386 dos.img -soundhw gus -parallel none
+@value{qemu_system_x86} dos.img -soundhw gus -parallel none
@end example
Alternatively:
@example
-qemu-system-i386 dos.img -device gus,irq=5
+@value{qemu_system_x86} dos.img -device gus,irq=5
@end example
Or some other unclaimed IRQ.
@@ -225,10 +228,11 @@ CS4231A is the chip used in Windows Sound System and GUSMAX products
@section Quick Start
@cindex quick start
-Download and uncompress the linux image (@file{linux.img}) and type:
+Download and uncompress a hard disk image with Linux installed (e.g.
+@file{linux.img}) and type:
@example
-qemu-system-i386 linux.img
+@value{qemu_system} linux.img
@end example
Linux should boot and give you a prompt.
@@ -238,7 +242,7 @@ Linux should boot and give you a prompt.
@example
@c man begin SYNOPSIS
-@command{qemu-system-i386} [@var{options}] [@var{disk_image}]
+@command{@value{qemu_system}} [@var{options}] [@var{disk_image}]
@c man end
@end example
@@ -278,28 +282,35 @@ is specified in seconds. The default is 0 which means no timeout. Libiscsi
Example (without authentication):
@example
-qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
+@value{qemu_system} -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
-cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
-drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
@end example
Example (CHAP username/password via URL):
@example
-qemu-system-i386 -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
+@value{qemu_system} -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
@end example
Example (CHAP username/password via environment variables):
@example
LIBISCSI_CHAP_USERNAME="user" \
LIBISCSI_CHAP_PASSWORD="password" \
-qemu-system-i386 -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+@value{qemu_system} -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
@end example
@item NBD
QEMU supports NBD (Network Block Devices) both using TCP protocol as well
-as Unix Domain Sockets.
+as Unix Domain Sockets. With TCP, the default port is 10809.
+
+Syntax for specifying a NBD device using TCP, in preferred URI form:
+``nbd://<server-ip>[:<port>]/[<export>]''
+
+Syntax for specifying a NBD device using Unix Domain Sockets; remember
+that '?' is a shell glob character and may need quoting:
+``nbd+unix:///[<export>]?socket=<domain-socket>''
-Syntax for specifying a NBD device using TCP
+Older syntax that is also recognized:
``nbd:<server-ip>:<port>[:exportname=<export>]''
Syntax for specifying a NBD device using Unix Domain Sockets
@@ -307,12 +318,12 @@ Syntax for specifying a NBD device using Unix Domain Sockets
Example for TCP
@example
-qemu-system-i386 --drive file=nbd:192.0.2.1:30000
+@value{qemu_system} --drive file=nbd:192.0.2.1:30000
@end example
Example for Unix Domain Sockets
@example
-qemu-system-i386 --drive file=nbd:unix:/tmp/nbd-socket
+@value{qemu_system} --drive file=nbd:unix:/tmp/nbd-socket
@end example
@item SSH
@@ -320,8 +331,8 @@ QEMU supports SSH (Secure Shell) access to remote disks.
Examples:
@example
-qemu-system-i386 -drive file=ssh://user@@host/path/to/disk.img
-qemu-system-i386 -drive file.driver=ssh,file.user=user,file.host=host,file.port=22,file.path=/path/to/disk.img
+@value{qemu_system} -drive file=ssh://user@@host/path/to/disk.img
+@value{qemu_system} -drive file.driver=ssh,file.user=user,file.host=host,file.port=22,file.path=/path/to/disk.img
@end example
Currently authentication must be done using ssh-agent. Other
@@ -339,7 +350,7 @@ sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag]
Example
@example
-qemu-system-i386 --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine
+@value{qemu_system} --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine
@end example
See also @url{https://sheepdog.github.io/sheepdog/}.
@@ -365,17 +376,17 @@ JSON:
Example
@example
URI:
-qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img,
+@value{qemu_system} --drive file=gluster://192.0.2.1/testvol/a.img,
@ file.debug=9,file.logfile=/var/log/qemu-gluster.log
JSON:
-qemu-system-x86_64 'json:@{"driver":"qcow2",
+@value{qemu_system} 'json:@{"driver":"qcow2",
@ "file":@{"driver":"gluster",
@ "volume":"testvol","path":"a.img",
@ "debug":9,"logfile":"/var/log/qemu-gluster.log",
@ "server":[@{"type":"tcp","host":"1.2.3.4","port":24007@},
@ @{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}'
-qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img,
+@value{qemu_system} -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img,
@ file.debug=9,file.logfile=/var/log/qemu-gluster.log,
@ file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007,
@ file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket
@@ -440,17 +451,17 @@ of <protocol>.
Example: boot from a remote Fedora 20 live ISO image
@example
-qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
+@value{qemu_system_x86} --drive media=cdrom,file=https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
-qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
+@value{qemu_system_x86} --drive media=cdrom,file.driver=http,file.url=http://archives.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
@end example
Example: boot from a remote Fedora 20 cloud image using a local overlay for
writes, copy-on-read, and a readahead of 64k
@example
-qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2
+qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2
-qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on
+@value{qemu_system_x86} -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on
@end example
Example: boot from an image stored on a VMware vSphere server with a self-signed
@@ -459,7 +470,7 @@ of 10 seconds.
@example
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k",, "file.timeout":10@}' /tmp/test.qcow2
-qemu-system-x86_64 -drive file=/tmp/test.qcow2
+@value{qemu_system_x86} -drive file=/tmp/test.qcow2
@end example
@end table
@@ -826,7 +837,7 @@ On Linux hosts, a shared memory device is available. The basic syntax
is:
@example
-qemu-system-x86_64 -device ivshmem-plain,memdev=@var{hostmem}
+@value{qemu_system_x86} -device ivshmem-plain,memdev=@var{hostmem}
@end example
where @var{hostmem} names a host memory backend. For a POSIX shared
@@ -847,7 +858,7 @@ memory server is:
ivshmem-server -p @var{pidfile} -S @var{path} -m @var{shm-name} -l @var{shm-size} -n @var{vectors}
# Then start your qemu instances with matching arguments
-qemu-system-x86_64 -device ivshmem-doorbell,vectors=@var{vectors},chardev=@var{id}
+@value{qemu_system_x86} -device ivshmem-doorbell,vectors=@var{vectors},chardev=@var{id}
-chardev socket,path=@var{path},id=@var{id}
@end example
@@ -872,7 +883,7 @@ Instead of specifying the <shm size> using POSIX shm, you may specify
a memory backend that has hugepage support:
@example
-qemu-system-x86_64 -object memory-backend-file,size=1G,mem-path=/dev/hugepages/my-shmem-file,share,id=mb1
+@value{qemu_system_x86} -object memory-backend-file,size=1G,mem-path=/dev/hugepages/my-shmem-file,share,id=mb1
-device ivshmem-plain,memdev=mb1
@end example
@@ -888,7 +899,7 @@ kernel testing.
The syntax is:
@example
-qemu-system-i386 -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda"
+@value{qemu_system} -kernel bzImage -hda rootdisk.img -append "root=/dev/hda"
@end example
Use @option{-kernel} to provide the Linux kernel image and
@@ -903,7 +914,7 @@ If you do not need graphical output, you can disable it and redirect
the virtual serial port and the QEMU monitor to the console with the
@option{-nographic} option. The typical command line is:
@example
-qemu-system-i386 -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
+@value{qemu_system} -kernel bzImage -hda rootdisk.img \
-append "root=/dev/hda console=ttyS0" -nographic
@end example
@@ -969,7 +980,7 @@ Network adapter that supports CDC ethernet and RNDIS protocols. @var{id}
specifies a netdev defined with @code{-netdev @dots{},id=@var{id}}.
For instance, user-mode networking can be used with
@example
-qemu-system-i386 [...] -netdev user,id=net0 -device usb-net,netdev=net0
+@value{qemu_system} [...] -netdev user,id=net0 -device usb-net,netdev=net0
@end example
@item usb-ccid
Smartcard reader device
@@ -988,7 +999,7 @@ no type is given, the HCI logic corresponds to @code{-bt hci,vlan=0}.
This USB device implements the USB Transport Layer of HCI. Example
usage:
@example
-@command{qemu-system-i386} [...@var{OPTIONS}...] @option{-usbdevice} bt:hci,vlan=3 @option{-bt} device:keyboard,vlan=3
+@command{@value{qemu_system}} [...@var{OPTIONS}...] @option{-usbdevice} bt:hci,vlan=3 @option{-bt} device:keyboard,vlan=3
@end example
@end table
@@ -1065,7 +1076,7 @@ For this setup it is recommended to restrict it to listen on a UNIX domain
socket only. For example
@example
-qemu-system-i386 [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc
+@value{qemu_system} [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc
@end example
This ensures that only users on local box with read/write access to that
@@ -1088,7 +1099,7 @@ is running the password is set with the monitor. Until the monitor is used to
set the password all clients will be rejected.
@example
-qemu-system-i386 [...OPTIONS...] -vnc :1,password -monitor stdio
+@value{qemu_system} [...OPTIONS...] -vnc :1,password -monitor stdio
(qemu) change vnc password
Password: ********
(qemu)
@@ -1105,7 +1116,7 @@ support provides a secure session, but no authentication. This allows any
client to connect, and provides an encrypted session.
@example
-qemu-system-i386 [...OPTIONS...] \
+@value{qemu_system} [...OPTIONS...] \
-object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=no \
-vnc :1,tls-creds=tls0 -monitor stdio
@end example
@@ -1127,7 +1138,7 @@ same syntax as previously, but with @code{verify-peer} set to @code{yes}
instead.
@example
-qemu-system-i386 [...OPTIONS...] \
+@value{qemu_system} [...OPTIONS...] \
-object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \
-vnc :1,tls-creds=tls0 -monitor stdio
@end example
@@ -1140,7 +1151,7 @@ Finally, the previous method can be combined with VNC password authentication
to provide two layers of authentication for clients.
@example
-qemu-system-i386 [...OPTIONS...] \
+@value{qemu_system} [...OPTIONS...] \
-object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \
-vnc :1,tls-creds=tls0,password -monitor stdio
(qemu) change vnc password
@@ -1165,7 +1176,7 @@ used for authentication, but assuming use of one supporting SSF,
then QEMU can be launched with:
@example
-qemu-system-i386 [...OPTIONS...] -vnc :1,sasl -monitor stdio
+@value{qemu_system} [...OPTIONS...] -vnc :1,sasl -monitor stdio
@end example
@node vnc_sec_certificate_sasl
@@ -1179,7 +1190,7 @@ credentials. This can be enabled, by combining the 'sasl' option
with the aforementioned TLS + x509 options:
@example
-qemu-system-i386 [...OPTIONS...] \
+@value{qemu_system} [...OPTIONS...] \
-object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server,verify-peer=yes \
-vnc :1,tls-creds=tls0,sasl -monitor stdio
@end example
@@ -1512,13 +1523,13 @@ To load server credentials with client certificate validation
enabled
@example
-$QEMU -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server
+@value{qemu_system} -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server
@end example
while to load client credentials use
@example
-$QEMU -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=client
+@value{qemu_system} -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=client
@end example
Network services which support TLS will all have a @code{tls-creds}
@@ -1526,7 +1537,7 @@ parameter which expects the ID of the TLS credentials object. For
example with VNC:
@example
-$QEMU -vnc 0.0.0.0:0,tls-creds=tls0
+@value{qemu_system} -vnc 0.0.0.0:0,tls-creds=tls0
@end example
@node tls_psk
@@ -1574,8 +1585,7 @@ QEMU has a primitive support to work with gdb, so that you can do
In order to use gdb, launch QEMU with the '-s' option. It will wait for a
gdb connection:
@example
-qemu-system-i386 -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
- -append "root=/dev/hda"
+@value{qemu_system} -s -kernel bzImage -hda rootdisk.img -append "root=/dev/hda"
Connected to host network interface: tun0
Waiting gdb connection on port 1234
@end example
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 8904733961..d46fa166d3 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -350,6 +350,79 @@ static void qemu_io_free(void *p)
qemu_vfree(p);
}
+/*
+ * qemu_io_alloc_from_file()
+ *
+ * Allocates the buffer and populates it with the content of the given file
+ * up to @len bytes. If the file length is less than @len, then the buffer
+ * is populated with the file content cyclically.
+ *
+ * @blk - the block backend where the buffer content is going to be written to
+ * @len - the buffer length
+ * @file_name - the file to read the content from
+ *
+ * Returns: the buffer pointer on success
+ * NULL on error
+ */
+static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
+ const char *file_name)
+{
+ char *buf, *buf_origin;
+ FILE *f = fopen(file_name, "r");
+ int pattern_len;
+
+ if (!f) {
+ perror(file_name);
+ return NULL;
+ }
+
+ if (qemuio_misalign) {
+ len += MISALIGN_OFFSET;
+ }
+
+ buf_origin = buf = blk_blockalign(blk, len);
+
+ if (qemuio_misalign) {
+ buf_origin += MISALIGN_OFFSET;
+ buf += MISALIGN_OFFSET;
+ len -= MISALIGN_OFFSET;
+ }
+
+ pattern_len = fread(buf_origin, 1, len, f);
+
+ if (ferror(f)) {
+ perror(file_name);
+ goto error;
+ }
+
+ if (pattern_len == 0) {
+ fprintf(stderr, "%s: file is empty\n", file_name);
+ goto error;
+ }
+
+ fclose(f);
+
+ if (len > pattern_len) {
+ len -= pattern_len;
+ buf += pattern_len;
+
+ while (len > 0) {
+ size_t len_to_copy = MIN(pattern_len, len);
+
+ memcpy(buf, buf_origin, len_to_copy);
+
+ len -= len_to_copy;
+ buf += len_to_copy;
+ }
+ }
+
+ return buf_origin;
+
+error:
+ qemu_io_free(buf_origin);
+ return NULL;
+}
+
static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
{
uint64_t i;
@@ -948,6 +1021,7 @@ static void write_help(void)
" -n, -- with -z, don't allow slow fallback\n"
" -p, -- ignored for backwards compatibility\n"
" -P, -- use different pattern to fill file\n"
+" -s, -- use a pattern file to fill the write buffer\n"
" -C, -- report statistics in a machine parsable format\n"
" -q, -- quiet mode, do not show I/O statistics\n"
" -u, -- with -z, allow unmapping\n"
@@ -964,7 +1038,7 @@ static const cmdinfo_t write_cmd = {
.perm = BLK_PERM_WRITE,
.argmin = 2,
.argmax = -1,
- .args = "[-bcCfnquz] [-P pattern] off len",
+ .args = "[-bcCfnquz] [-P pattern | -s source_file] off len",
.oneline = "writes a number of bytes at a specified offset",
.help = write_help,
};
@@ -973,7 +1047,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
{
struct timespec t1, t2;
bool Cflag = false, qflag = false, bflag = false;
- bool Pflag = false, zflag = false, cflag = false;
+ bool Pflag = false, zflag = false, cflag = false, sflag = false;
int flags = 0;
int c, cnt, ret;
char *buf = NULL;
@@ -982,8 +1056,9 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
/* Some compilers get confused and warn if this is not initialized. */
int64_t total = 0;
int pattern = 0xcd;
+ const char *file_name = NULL;
- while ((c = getopt(argc, argv, "bcCfnpP:quz")) != -1) {
+ while ((c = getopt(argc, argv, "bcCfnpP:qs:uz")) != -1) {
switch (c) {
case 'b':
bflag = true;
@@ -1013,6 +1088,10 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
case 'q':
qflag = true;
break;
+ case 's':
+ sflag = true;
+ file_name = optarg;
+ break;
case 'u':
flags |= BDRV_REQ_MAY_UNMAP;
break;
@@ -1050,8 +1129,9 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
return -EINVAL;
}
- if (zflag && Pflag) {
- printf("-z and -P cannot be specified at the same time\n");
+ if (zflag + Pflag + sflag > 1) {
+ printf("Only one of -z, -P, and -s "
+ "can be specified at the same time\n");
return -EINVAL;
}
@@ -1087,7 +1167,14 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
}
if (!zflag) {
- buf = qemu_io_alloc(blk, count, pattern);
+ if (sflag) {
+ buf = qemu_io_alloc_from_file(blk, count, file_name);
+ if (!buf) {
+ return -EINVAL;
+ }
+ } else {
+ buf = qemu_io_alloc(blk, count, pattern);
+ }
}
clock_gettime(CLOCK_MONOTONIC, &t1);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 049645491d..9032b6de2a 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -294,6 +294,7 @@ static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls,
[NBD_FLAG_CAN_MULTI_CONN_BIT] = "multi",
[NBD_FLAG_SEND_RESIZE_BIT] = "resize",
[NBD_FLAG_SEND_CACHE_BIT] = "cache",
+ [NBD_FLAG_SEND_FAST_ZERO_BIT] = "fast-zero",
};
printf(" size: %" PRIu64 "\n", list[i].size);
@@ -600,7 +601,7 @@ int main(int argc, char **argv)
BlockBackend *blk;
BlockDriverState *bs;
uint64_t dev_offset = 0;
- uint16_t nbdflags = 0;
+ bool readonly = false;
bool disconnect = false;
const char *bindto = NULL;
const char *port = NULL;
@@ -782,7 +783,7 @@ int main(int argc, char **argv)
}
/* fall through */
case 'r':
- nbdflags |= NBD_FLAG_READ_ONLY;
+ readonly = true;
flags &= ~BDRV_O_RDWR;
break;
case 'P':
@@ -1054,7 +1055,7 @@ int main(int argc, char **argv)
server = qio_net_listener_new();
if (socket_activation == 0) {
saddr = nbd_build_socket_address(sockpath, bindto, port);
- if (qio_net_listener_open_sync(server, saddr, &local_err) < 0) {
+ if (qio_net_listener_open_sync(server, saddr, 1, &local_err) < 0) {
object_unref(OBJECT(server));
error_report_err(local_err);
exit(EXIT_FAILURE);
@@ -1173,7 +1174,7 @@ int main(int argc, char **argv)
}
export = nbd_export_new(bs, dev_offset, fd_size, export_name,
- export_description, bitmap, nbdflags,
+ export_description, bitmap, readonly, shared > 1,
nbd_export_closed, writethrough, NULL,
&error_fatal);
diff --git a/qemu-options.hx b/qemu-options.hx
index ea0638e92d..bbfd936d29 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -254,10 +254,10 @@ This option defines a free-form string that can be used to describe @var{fd}.
You can open an image using pre-opened file descriptors from an fd set:
@example
-qemu-system-i386
--add-fd fd=3,set=2,opaque="rdwr:/path/to/file"
--add-fd fd=4,set=2,opaque="rdonly:/path/to/file"
--drive file=/dev/fdset/2,index=0,media=disk
+@value{qemu_system} \
+ -add-fd fd=3,set=2,opaque="rdwr:/path/to/file" \
+ -add-fd fd=4,set=2,opaque="rdonly:/path/to/file" \
+ -drive file=/dev/fdset/2,index=0,media=disk
@end example
ETEXI
@@ -283,7 +283,7 @@ STEXI
Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.:
@example
-qemu-system-i386 -global ide-hd.physical_block_size=4096 disk-image.img
+@value{qemu_system_x86} -global ide-hd.physical_block_size=4096 disk-image.img
@end example
In particular, you can use this to set driver properties for devices which are
@@ -337,11 +337,11 @@ bootindex options. The default is non-strict boot.
@example
# try to boot from network first, then from hard disk
-qemu-system-i386 -boot order=nc
+@value{qemu_system_x86} -boot order=nc
# boot from CD-ROM first, switch back to default order after reboot
-qemu-system-i386 -boot once=d
+@value{qemu_system_x86} -boot once=d
# boot with a splash picture for 5 seconds.
-qemu-system-i386 -boot menu=on,splash=/root/boot.bmp,splash-time=5000
+@value{qemu_system_x86} -boot menu=on,splash=/root/boot.bmp,splash-time=5000
@end example
Note: The legacy format '-boot @var{drives}' is still supported but its
@@ -370,7 +370,7 @@ For example, the following command-line sets the guest startup RAM size to
memory the guest can reach to 4GB:
@example
-qemu-system-x86_64 -m 1G,slots=3,maxmem=4G
+@value{qemu_system} -m 1G,slots=3,maxmem=4G
@end example
If @var{slots} and @var{maxmem} are not specified, memory hotplug won't
@@ -666,15 +666,15 @@ STEXI
@item -soundhw @var{card1}[,@var{card2},...] or -soundhw all
@findex -soundhw
Enable audio and selected sound hardware. Use 'help' to print all
-available sound hardware.
+available sound hardware. For example:
@example
-qemu-system-i386 -soundhw sb16,adlib disk.img
-qemu-system-i386 -soundhw es1370 disk.img
-qemu-system-i386 -soundhw ac97 disk.img
-qemu-system-i386 -soundhw hda disk.img
-qemu-system-i386 -soundhw all disk.img
-qemu-system-i386 -soundhw help
+@value{qemu_system_x86} -soundhw sb16,adlib disk.img
+@value{qemu_system_x86} -soundhw es1370 disk.img
+@value{qemu_system_x86} -soundhw ac97 disk.img
+@value{qemu_system_x86} -soundhw hda disk.img
+@value{qemu_system_x86} -soundhw all disk.img
+@value{qemu_system_x86} -soundhw help
@end example
Note that Linux's i810_audio OSS kernel (for AC97) module might
@@ -1149,50 +1149,50 @@ is off.
Instead of @option{-cdrom} you can use:
@example
-qemu-system-i386 -drive file=file,index=2,media=cdrom
+@value{qemu_system} -drive file=file,index=2,media=cdrom
@end example
Instead of @option{-hda}, @option{-hdb}, @option{-hdc}, @option{-hdd}, you can
use:
@example
-qemu-system-i386 -drive file=file,index=0,media=disk
-qemu-system-i386 -drive file=file,index=1,media=disk
-qemu-system-i386 -drive file=file,index=2,media=disk
-qemu-system-i386 -drive file=file,index=3,media=disk
+@value{qemu_system} -drive file=file,index=0,media=disk
+@value{qemu_system} -drive file=file,index=1,media=disk
+@value{qemu_system} -drive file=file,index=2,media=disk
+@value{qemu_system} -drive file=file,index=3,media=disk
@end example
You can open an image using pre-opened file descriptors from an fd set:
@example
-qemu-system-i386
--add-fd fd=3,set=2,opaque="rdwr:/path/to/file"
--add-fd fd=4,set=2,opaque="rdonly:/path/to/file"
--drive file=/dev/fdset/2,index=0,media=disk
+@value{qemu_system} \
+ -add-fd fd=3,set=2,opaque="rdwr:/path/to/file" \
+ -add-fd fd=4,set=2,opaque="rdonly:/path/to/file" \
+ -drive file=/dev/fdset/2,index=0,media=disk
@end example
You can connect a CDROM to the slave of ide0:
@example
-qemu-system-i386 -drive file=file,if=ide,index=1,media=cdrom
+@value{qemu_system_x86} -drive file=file,if=ide,index=1,media=cdrom
@end example
If you don't specify the "file=" argument, you define an empty drive:
@example
-qemu-system-i386 -drive if=ide,index=1,media=cdrom
+@value{qemu_system_x86} -drive if=ide,index=1,media=cdrom
@end example
Instead of @option{-fda}, @option{-fdb}, you can use:
@example
-qemu-system-i386 -drive file=file,index=0,if=floppy
-qemu-system-i386 -drive file=file,index=1,if=floppy
+@value{qemu_system_x86} -drive file=file,index=0,if=floppy
+@value{qemu_system_x86} -drive file=file,index=1,if=floppy
@end example
By default, @var{interface} is "ide" and @var{index} is automatically
incremented:
@example
-qemu-system-i386 -drive file=a -drive file=b"
+@value{qemu_system_x86} -drive file=a -drive file=b"
@end example
is interpreted like:
@example
-qemu-system-i386 -hda a -hdb b
+@value{qemu_system_x86} -hda a -hdb b
@end example
ETEXI
@@ -2272,8 +2272,8 @@ The following two example do exactly the same, to show how @option{-nic} can
be used to shorten the command line length (note that the e1000 is the default
on i386, so the @option{model=e1000} parameter could even be omitted here, too):
@example
-qemu-system-i386 -netdev user,id=n1,ipv6=off -device e1000,netdev=n1,mac=52:54:98:76:54:32
-qemu-system-i386 -nic user,ipv6=off,model=e1000,mac=52:54:98:76:54:32
+@value{qemu_system} -netdev user,id=n1,ipv6=off -device e1000,netdev=n1,mac=52:54:98:76:54:32
+@value{qemu_system} -nic user,ipv6=off,model=e1000,mac=52:54:98:76:54:32
@end example
@item -nic none
@@ -2344,7 +2344,7 @@ can not be resolved.
Example:
@example
-qemu-system-i386 -nic user,dnssearch=mgmt.example.org,dnssearch=example.org
+@value{qemu_system} -nic user,dnssearch=mgmt.example.org,dnssearch=example.org
@end example
@item domainname=@var{domain}
@@ -2368,7 +2368,7 @@ a guest from a local directory.
Example (using pxelinux):
@example
-qemu-system-i386 -hda linux.img -boot n -device e1000,netdev=n1 \
+@value{qemu_system} -hda linux.img -boot n -device e1000,netdev=n1 \
-netdev user,id=n1,tftp=/path/to/tftp/files,bootfile=/pxelinux.0
@end example
@@ -2402,7 +2402,7 @@ screen 0, use the following:
@example
# on the host
-qemu-system-i386 -nic user,hostfwd=tcp:127.0.0.1:6001-:6000
+@value{qemu_system} -nic user,hostfwd=tcp:127.0.0.1:6001-:6000
# this host xterm should open in the guest X11 server
xterm -display :1
@end example
@@ -2412,7 +2412,7 @@ the guest, use the following:
@example
# on the host
-qemu-system-i386 -nic user,hostfwd=tcp::5555-:23
+@value{qemu_system} -nic user,hostfwd=tcp::5555-:23
telnet localhost 5555
@end example
@@ -2431,7 +2431,7 @@ lifetime, like in the following example:
@example
# open 10.10.1.1:4321 on bootup, connect 10.0.2.100:1234 to it whenever
# the guest accesses it
-qemu-system-i386 -nic user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321
+@value{qemu_system} -nic user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321
@end example
Or you can execute a command on every TCP connection established by the guest,
@@ -2440,7 +2440,7 @@ so that QEMU behaves similar to an inetd process for that virtual server:
@example
# call "netcat 10.10.1.1 4321" on every TCP connection to 10.0.2.100:1234
# and connect the TCP stream to its stdin/stdout
-qemu-system-i386 -nic 'user,id=n1,guestfwd=tcp:10.0.2.100:1234-cmd:netcat 10.10.1.1 4321'
+@value{qemu_system} -nic 'user,id=n1,guestfwd=tcp:10.0.2.100:1234-cmd:netcat 10.10.1.1 4321'
@end example
@end table
@@ -2467,13 +2467,13 @@ Examples:
@example
#launch a QEMU instance with the default network script
-qemu-system-i386 linux.img -nic tap
+@value{qemu_system} linux.img -nic tap
@end example
@example
#launch a QEMU instance with two NICs, each one connected
#to a TAP device
-qemu-system-i386 linux.img \
+@value{qemu_system} linux.img \
-netdev tap,id=nd0,ifname=tap0 -device e1000,netdev=nd0 \
-netdev tap,id=nd1,ifname=tap1 -device rtl8139,netdev=nd1
@end example
@@ -2481,7 +2481,7 @@ qemu-system-i386 linux.img \
@example
#launch a QEMU instance with the default network helper to
#connect a TAP device to bridge br0
-qemu-system-i386 linux.img -device virtio-net-pci,netdev=n1 \
+@value{qemu_system} linux.img -device virtio-net-pci,netdev=n1 \
-netdev tap,id=n1,"helper=/path/to/qemu-bridge-helper"
@end example
@@ -2498,13 +2498,13 @@ Examples:
@example
#launch a QEMU instance with the default network helper to
#connect a TAP device to bridge br0
-qemu-system-i386 linux.img -netdev bridge,id=n1 -device virtio-net,netdev=n1
+@value{qemu_system} linux.img -netdev bridge,id=n1 -device virtio-net,netdev=n1
@end example
@example
#launch a QEMU instance with the default network helper to
#connect a TAP device to bridge qemubr0
-qemu-system-i386 linux.img -netdev bridge,br=qemubr0,id=n1 -device virtio-net,netdev=n1
+@value{qemu_system} linux.img -netdev bridge,br=qemubr0,id=n1 -device virtio-net,netdev=n1
@end example
@item -netdev socket,id=@var{id}[,fd=@var{h}][,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
@@ -2519,11 +2519,11 @@ specifies an already opened TCP socket.
Example:
@example
# launch a first QEMU instance
-qemu-system-i386 linux.img \
+@value{qemu_system} linux.img \
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \
-netdev socket,id=n1,listen=:1234
# connect the network of this instance to the network of the first instance
-qemu-system-i386 linux.img \
+@value{qemu_system} linux.img \
-device e1000,netdev=n2,mac=52:54:00:12:34:57 \
-netdev socket,id=n2,connect=127.0.0.1:1234
@end example
@@ -2548,15 +2548,15 @@ Use @option{fd=h} to specify an already opened UDP multicast socket.
Example:
@example
# launch one QEMU instance
-qemu-system-i386 linux.img \
+@value{qemu_system} linux.img \
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \
-netdev socket,id=n1,mcast=230.0.0.1:1234
# launch another QEMU instance on same "bus"
-qemu-system-i386 linux.img \
+@value{qemu_system} linux.img \
-device e1000,netdev=n2,mac=52:54:00:12:34:57 \
-netdev socket,id=n2,mcast=230.0.0.1:1234
# launch yet another QEMU instance on same "bus"
-qemu-system-i386 linux.img \
+@value{qemu_system} linux.img \
-device e1000,netdev=n3,mac=52:54:00:12:34:58 \
-netdev socket,id=n3,mcast=230.0.0.1:1234
@end example
@@ -2564,7 +2564,7 @@ qemu-system-i386 linux.img \
Example (User Mode Linux compat.):
@example
# launch QEMU instance (note mcast address selected is UML's default)
-qemu-system-i386 linux.img \
+@value{qemu_system} linux.img \
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \
-netdev socket,id=n1,mcast=239.192.168.1:1102
# launch UML
@@ -2573,7 +2573,7 @@ qemu-system-i386 linux.img \
Example (send packets from host's 1.2.3.4):
@example
-qemu-system-i386 linux.img \
+@value{qemu_system} linux.img \
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \
-netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4
@end example
@@ -2633,7 +2633,7 @@ brctl addif br-lan vmtunnel0
# on 4.3.2.1
# launch QEMU instance - if your network has reorder or is very lossy add ,pincounter
-qemu-system-i386 linux.img -device e1000,netdev=n1 \
+@value{qemu_system} linux.img -device e1000,netdev=n1 \
-netdev l2tpv3,id=n1,src=4.2.3.1,dst=1.2.3.4,udp,srcport=16384,dstport=16384,rxsession=0xffffffff,txsession=0xffffffff,counter
@end example
@@ -2650,7 +2650,7 @@ Example:
# launch vde switch
vde_switch -F -sock /tmp/myswitch
# launch QEMU instance
-qemu-system-i386 linux.img -nic vde,sock=/tmp/myswitch
+@value{qemu_system} linux.img -nic vde,sock=/tmp/myswitch
@end example
@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n]
@@ -3107,7 +3107,7 @@ and communicate. Requires the Linux @code{vhci} driver installed. Can
be used as following:
@example
-qemu-system-i386 [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5
+@value{qemu_system} [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5
@end example
@item -bt device:@var{dev}[,vlan=@var{n}]
@@ -3601,7 +3601,7 @@ connections will likely be TCP-based, but also UDP, pseudo TTY, or even
stdio are reasonable use case. The latter is allowing to start QEMU from
within gdb and establish the connection via a pipe:
@example
-(gdb) target remote | exec qemu-system-i386 -gdb stdio ...
+(gdb) target remote | exec @value{qemu_system} -gdb stdio ...
@end example
ETEXI
@@ -4332,6 +4332,13 @@ other options.
The @option{share} boolean option is @var{on} by default with memfd.
+@item -object rng-builtin,id=@var{id}
+
+Creates a random number generator backend which obtains entropy from
+QEMU builtin functions. The @option{id} parameter is a unique ID that
+will be used to reference this entropy backend from the @option{virtio-rng}
+device. By default, the @option{virtio-rng} device uses this RNG backend.
+
@item -object rng-random,id=@var{id},filename=@var{/dev/random}
Creates a random number generator backend which obtains entropy from
@@ -4571,7 +4578,7 @@ which specify the queue number of cryptodev backend, the default of
@example
- # qemu-system-x86_64 \
+ # @value{qemu_system} \
[...] \
-object cryptodev-backend-builtin,id=cryptodev0 \
-device virtio-crypto-pci,id=crypto0,cryptodev=cryptodev0 \
@@ -4591,7 +4598,7 @@ of cryptodev backend for multiqueue vhost-user, the default of @var{queues} is 1
@example
- # qemu-system-x86_64 \
+ # @value{qemu_system} \
[...] \
-chardev socket,id=chardev0,path=/path/to/socket \
-object cryptodev-vhost-user,id=cryptodev0,chardev=chardev0 \
@@ -4627,14 +4634,14 @@ The simplest (insecure) usage is to provide the secret inline
@example
- # $QEMU -object secret,id=sec0,data=letmein,format=raw
+ # @value{qemu_system} -object secret,id=sec0,data=letmein,format=raw
@end example
The simplest secure usage is to provide the secret via a file
# printf "letmein" > mypasswd.txt
- # $QEMU -object secret,id=sec0,file=mypasswd.txt,format=raw
+ # @value{qemu_system} -object secret,id=sec0,file=mypasswd.txt,format=raw
For greater security, AES-256-CBC should be used. To illustrate usage,
consider the openssl command line tool which can encrypt the data. Note
@@ -4670,7 +4677,7 @@ and specify that to be used to decrypt the user password. Pass the
contents of @code{iv.b64} to the second secret
@example
- # $QEMU \
+ # @value{qemu_system} \
-object secret,id=secmaster0,format=base64,file=key.b64 \
-object secret,id=sec0,keyid=secmaster0,format=base64,\
data=$SECRET,iv=$(<iv.b64)
@@ -4713,7 +4720,7 @@ negotiate keys used for attestation. The file must be encoded in base64.
e.g to launch a SEV guest
@example
- # $QEMU \
+ # @value{qemu_system_x86} \
......
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=5 \
-machine ...,memory-encryption=sev0
@@ -4735,7 +4742,7 @@ any commas in the distinguished name.
An example authorization object to validate a x509 distinguished name
would look like:
@example
- # $QEMU \
+ # @value{qemu_system} \
...
-object 'authz-simple,id=auth0,identity=CN=laptop.example.com,,O=Example Org,,L=London,,ST=London,,C=GB' \
...
@@ -4784,7 +4791,7 @@ a TLS x509 distinguished name, or a SASL username.
An example authorization object to validate a SASL username
would look like:
@example
- # $QEMU \
+ # @value{qemu_system} \
...
-object authz-simple,id=auth0,filename=/etc/qemu/vnc-sasl.acl,refresh=yes
...
@@ -4802,7 +4809,7 @@ An example authorization object to validate a TLS x509 distinguished
name would look like:
@example
- # $QEMU \
+ # @value{qemu_system} \
...
-object authz-pam,id=auth0,service=qemu-vnc
...
diff --git a/qga/channel-posix.c b/qga/channel-posix.c
index 5a925a9818..8fc205ad21 100644
--- a/qga/channel-posix.c
+++ b/qga/channel-posix.c
@@ -215,7 +215,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path,
return false;
}
- fd = socket_listen(addr, &local_err);
+ fd = socket_listen(addr, 1, &local_err);
qapi_free_SocketAddress(addr);
if (local_err != NULL) {
g_critical("%s", error_get_pretty(local_err));
diff --git a/roms/SLOF b/roms/SLOF
-Subproject 7bfe584e321946771692711ff83ad2b5850daca
+Subproject ea221600a116883137ef90b2b7ab7d2472bc4f1
diff --git a/roms/skiboot b/roms/skiboot
-Subproject 261ca8e779e5138869a45f174caa49be6a27450
+Subproject 3a6fdede6ce117facec0108afe716cf5d0472c3
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index d24c9441ee..aa9a354a0e 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -461,7 +461,7 @@ sub top_of_kernel_tree {
my @tree_check = (
"COPYING", "MAINTAINERS", "Makefile",
- "README", "docs", "VERSION",
+ "README.rst", "docs", "VERSION",
"vl.c"
);
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
index a256ce490b..a8a74d1dba 100644
--- a/scsi/qemu-pr-helper.c
+++ b/scsi/qemu-pr-helper.c
@@ -1005,7 +1005,8 @@ int main(int argc, char **argv)
.u.q_unix.path = socket_path,
};
server_ioc = qio_channel_socket_new();
- if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) {
+ if (qio_channel_socket_listen_sync(server_ioc, &saddr,
+ 1, &local_err) < 0) {
object_unref(OBJECT(server_ioc));
error_report_err(local_err);
return 1;
diff --git a/target/alpha/translate.c b/target/alpha/translate.c
index 1e29653aac..a69f58bf65 100644
--- a/target/alpha/translate.c
+++ b/target/alpha/translate.c
@@ -403,7 +403,7 @@ static inline void gen_store_mem(DisasContext *ctx,
static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb,
int32_t disp16, int mem_idx,
- TCGMemOp op)
+ MemOp op)
{
TCGLabel *lab_fail, *lab_done;
TCGv addr, val;
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index 5cafc1eb6c..cf26c16f5f 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -28,9 +28,33 @@ target/arm/decode-vfp-uncond.inc.c: $(SRC_PATH)/target/arm/vfp-uncond.decode $(D
$(PYTHON) $(DECODETREE) --static-decode disas_vfp_uncond -o $@ $<,\
"GEN", $(TARGET_DIR)$@)
+target/arm/decode-a32.inc.c: $(SRC_PATH)/target/arm/a32.decode $(DECODETREE)
+ $(call quiet-command,\
+ $(PYTHON) $(DECODETREE) --static-decode disas_a32 -o $@ $<,\
+ "GEN", $(TARGET_DIR)$@)
+
+target/arm/decode-a32-uncond.inc.c: $(SRC_PATH)/target/arm/a32-uncond.decode $(DECODETREE)
+ $(call quiet-command,\
+ $(PYTHON) $(DECODETREE) --static-decode disas_a32_uncond -o $@ $<,\
+ "GEN", $(TARGET_DIR)$@)
+
+target/arm/decode-t32.inc.c: $(SRC_PATH)/target/arm/t32.decode $(DECODETREE)
+ $(call quiet-command,\
+ $(PYTHON) $(DECODETREE) --static-decode disas_t32 -o $@ $<,\
+ "GEN", $(TARGET_DIR)$@)
+
+target/arm/decode-t16.inc.c: $(SRC_PATH)/target/arm/t16.decode $(DECODETREE)
+ $(call quiet-command,\
+ $(PYTHON) $(DECODETREE) -w 16 --static-decode disas_t16 -o $@ $<,\
+ "GEN", $(TARGET_DIR)$@)
+
target/arm/translate-sve.o: target/arm/decode-sve.inc.c
target/arm/translate.o: target/arm/decode-vfp.inc.c
target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c
+target/arm/translate.o: target/arm/decode-a32.inc.c
+target/arm/translate.o: target/arm/decode-a32-uncond.inc.c
+target/arm/translate.o: target/arm/decode-t32.inc.c
+target/arm/translate.o: target/arm/decode-t16.inc.c
obj-y += tlb_helper.o debug_helper.o
obj-y += translate.o op_helper.o
diff --git a/target/arm/a32-uncond.decode b/target/arm/a32-uncond.decode
new file mode 100644
index 0000000000..60ccfc598d
--- /dev/null
+++ b/target/arm/a32-uncond.decode
@@ -0,0 +1,74 @@
+# A32 unconditional instructions
+#
+# Copyright (c) 2019 Linaro, Ltd
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+#
+# This file is processed by scripts/decodetree.py
+#
+# All insns that have 0xf in insn[31:28] are decoded here.
+# All of those that have a COND field in insn[31:28] are in a32.decode
+#
+
+&empty !extern
+&i !extern imm
+&setend E
+
+# Branch with Link and Exchange
+
+%imm24h 0:s24 24:1 !function=times_2
+
+BLX_i 1111 101 . ........................ &i imm=%imm24h
+
+# System Instructions
+
+&rfe rn w pu
+&srs mode w pu
+&cps mode imod M A I F
+
+RFE 1111 100 pu:2 0 w:1 1 rn:4 0000 1010 0000 0000 &rfe
+SRS 1111 100 pu:2 1 w:1 0 1101 0000 0101 000 mode:5 &srs
+CPS 1111 0001 0000 imod:2 M:1 0 0000 000 A:1 I:1 F:1 0 mode:5 \
+ &cps
+
+# Clear-Exclusive, Barriers
+
+# QEMU does not require the option field for the barriers.
+CLREX 1111 0101 0111 1111 1111 0000 0001 1111
+DSB 1111 0101 0111 1111 1111 0000 0100 ----
+DMB 1111 0101 0111 1111 1111 0000 0101 ----
+ISB 1111 0101 0111 1111 1111 0000 0110 ----
+SB 1111 0101 0111 1111 1111 0000 0111 0000
+
+# Set Endianness
+SETEND 1111 0001 0000 0001 0000 00 E:1 0 0000 0000 &setend
+
+# Preload instructions
+
+PLD 1111 0101 -101 ---- 1111 ---- ---- ---- # (imm, lit) 5te
+PLDW 1111 0101 -001 ---- 1111 ---- ---- ---- # (imm, lit) 7mp
+PLI 1111 0100 -101 ---- 1111 ---- ---- ---- # (imm, lit) 7
+
+PLD 1111 0111 -101 ---- 1111 ----- -- 0 ---- # (register) 5te
+PLDW 1111 0111 -001 ---- 1111 ----- -- 0 ---- # (register) 7mp
+PLI 1111 0110 -101 ---- 1111 ----- -- 0 ---- # (register) 7
+
+# Unallocated memory hints
+#
+# Since these are v7MP nops, and PLDW is v7MP and implemented as nop,
+# (ab)use the PLDW helper.
+
+PLDW 1111 0100 -001 ---- ---- ---- ---- ----
+PLDW 1111 0110 -001 ---- ---- ---- ---0 ----
diff --git a/target/arm/a32.decode b/target/arm/a32.decode
new file mode 100644
index 0000000000..0bd952c069
--- /dev/null
+++ b/target/arm/a32.decode
@@ -0,0 +1,534 @@
+# A32 conditional instructions
+#
+# Copyright (c) 2019 Linaro, Ltd
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+#
+# This file is processed by scripts/decodetree.py
+#
+# All of the insn that have a COND field in insn[31:28] are here.
+# All insns that have 0xf in insn[31:28] are in a32-uncond.decode.
+#
+
+&empty
+&s_rrr_shi s rd rn rm shim shty
+&s_rrr_shr s rn rd rm rs shty
+&s_rri_rot s rn rd imm rot
+&s_rrrr s rd rn rm ra
+&rrrr rd rn rm ra
+&rrr_rot rd rn rm rot
+&rrr rd rn rm
+&rr rd rm
+&ri rd imm
+&r rm
+&i imm
+&msr_reg rn r mask
+&mrs_reg rd r
+&msr_bank rn r sysm
+&mrs_bank rd r sysm
+&ldst_rr p w u rn rt rm shimm shtype
+&ldst_ri p w u rn rt imm
+&ldst_block rn i b u w list
+&strex rn rd rt rt2 imm
+&ldrex rn rt rt2 imm
+&bfx rd rn lsb widthm1
+&bfi rd rn lsb msb
+&sat rd rn satimm imm sh
+&pkh rd rn rm imm tb
+
+# Data-processing (register)
+
+@s_rrr_shi ---- ... .... s:1 rn:4 rd:4 shim:5 shty:2 . rm:4 \
+ &s_rrr_shi
+@s_rxr_shi ---- ... .... s:1 .... rd:4 shim:5 shty:2 . rm:4 \
+ &s_rrr_shi rn=0
+@S_xrr_shi ---- ... .... . rn:4 .... shim:5 shty:2 . rm:4 \
+ &s_rrr_shi s=1 rd=0
+
+AND_rrri .... 000 0000 . .... .... ..... .. 0 .... @s_rrr_shi
+EOR_rrri .... 000 0001 . .... .... ..... .. 0 .... @s_rrr_shi
+SUB_rrri .... 000 0010 . .... .... ..... .. 0 .... @s_rrr_shi
+RSB_rrri .... 000 0011 . .... .... ..... .. 0 .... @s_rrr_shi
+ADD_rrri .... 000 0100 . .... .... ..... .. 0 .... @s_rrr_shi
+ADC_rrri .... 000 0101 . .... .... ..... .. 0 .... @s_rrr_shi
+SBC_rrri .... 000 0110 . .... .... ..... .. 0 .... @s_rrr_shi
+RSC_rrri .... 000 0111 . .... .... ..... .. 0 .... @s_rrr_shi
+TST_xrri .... 000 1000 1 .... 0000 ..... .. 0 .... @S_xrr_shi
+TEQ_xrri .... 000 1001 1 .... 0000 ..... .. 0 .... @S_xrr_shi
+CMP_xrri .... 000 1010 1 .... 0000 ..... .. 0 .... @S_xrr_shi
+CMN_xrri .... 000 1011 1 .... 0000 ..... .. 0 .... @S_xrr_shi
+ORR_rrri .... 000 1100 . .... .... ..... .. 0 .... @s_rrr_shi
+MOV_rxri .... 000 1101 . 0000 .... ..... .. 0 .... @s_rxr_shi
+BIC_rrri .... 000 1110 . .... .... ..... .. 0 .... @s_rrr_shi
+MVN_rxri .... 000 1111 . 0000 .... ..... .. 0 .... @s_rxr_shi
+
+%imm16 16:4 0:12
+@mov16 ---- .... .... .... rd:4 ............ &ri imm=%imm16
+
+MOVW .... 0011 0000 .... .... ............ @mov16
+MOVT .... 0011 0100 .... .... ............ @mov16
+
+# Data-processing (register-shifted register)
+
+@s_rrr_shr ---- ... .... s:1 rn:4 rd:4 rs:4 . shty:2 . rm:4 \
+ &s_rrr_shr
+@s_rxr_shr ---- ... .... s:1 .... rd:4 rs:4 . shty:2 . rm:4 \
+ &s_rrr_shr rn=0
+@S_xrr_shr ---- ... .... . rn:4 .... rs:4 . shty:2 . rm:4 \
+ &s_rrr_shr rd=0 s=1
+
+AND_rrrr .... 000 0000 . .... .... .... 0 .. 1 .... @s_rrr_shr
+EOR_rrrr .... 000 0001 . .... .... .... 0 .. 1 .... @s_rrr_shr
+SUB_rrrr .... 000 0010 . .... .... .... 0 .. 1 .... @s_rrr_shr
+RSB_rrrr .... 000 0011 . .... .... .... 0 .. 1 .... @s_rrr_shr
+ADD_rrrr .... 000 0100 . .... .... .... 0 .. 1 .... @s_rrr_shr
+ADC_rrrr .... 000 0101 . .... .... .... 0 .. 1 .... @s_rrr_shr
+SBC_rrrr .... 000 0110 . .... .... .... 0 .. 1 .... @s_rrr_shr
+RSC_rrrr .... 000 0111 . .... .... .... 0 .. 1 .... @s_rrr_shr
+TST_xrrr .... 000 1000 1 .... 0000 .... 0 .. 1 .... @S_xrr_shr
+TEQ_xrrr .... 000 1001 1 .... 0000 .... 0 .. 1 .... @S_xrr_shr
+CMP_xrrr .... 000 1010 1 .... 0000 .... 0 .. 1 .... @S_xrr_shr
+CMN_xrrr .... 000 1011 1 .... 0000 .... 0 .. 1 .... @S_xrr_shr
+ORR_rrrr .... 000 1100 . .... .... .... 0 .. 1 .... @s_rrr_shr
+MOV_rxrr .... 000 1101 . 0000 .... .... 0 .. 1 .... @s_rxr_shr
+BIC_rrrr .... 000 1110 . .... .... .... 0 .. 1 .... @s_rrr_shr
+MVN_rxrr .... 000 1111 . 0000 .... .... 0 .. 1 .... @s_rxr_shr
+
+# Data-processing (immediate)
+
+%a32extrot 8:4 !function=times_2
+
+@s_rri_rot ---- ... .... s:1 rn:4 rd:4 .... imm:8 \
+ &s_rri_rot rot=%a32extrot
+@s_rxi_rot ---- ... .... s:1 .... rd:4 .... imm:8 \
+ &s_rri_rot rot=%a32extrot rn=0
+@S_xri_rot ---- ... .... . rn:4 .... .... imm:8 \
+ &s_rri_rot rot=%a32extrot rd=0 s=1
+
+AND_rri .... 001 0000 . .... .... ............ @s_rri_rot
+EOR_rri .... 001 0001 . .... .... ............ @s_rri_rot
+SUB_rri .... 001 0010 . .... .... ............ @s_rri_rot
+RSB_rri .... 001 0011 . .... .... ............ @s_rri_rot
+ADD_rri .... 001 0100 . .... .... ............ @s_rri_rot
+ADC_rri .... 001 0101 . .... .... ............ @s_rri_rot
+SBC_rri .... 001 0110 . .... .... ............ @s_rri_rot
+RSC_rri .... 001 0111 . .... .... ............ @s_rri_rot
+TST_xri .... 001 1000 1 .... 0000 ............ @S_xri_rot
+TEQ_xri .... 001 1001 1 .... 0000 ............ @S_xri_rot
+CMP_xri .... 001 1010 1 .... 0000 ............ @S_xri_rot
+CMN_xri .... 001 1011 1 .... 0000 ............ @S_xri_rot
+ORR_rri .... 001 1100 . .... .... ............ @s_rri_rot
+MOV_rxi .... 001 1101 . 0000 .... ............ @s_rxi_rot
+BIC_rri .... 001 1110 . .... .... ............ @s_rri_rot
+MVN_rxi .... 001 1111 . 0000 .... ............ @s_rxi_rot
+
+# Multiply and multiply accumulate
+
+@s_rdamn ---- .... ... s:1 rd:4 ra:4 rm:4 .... rn:4 &s_rrrr
+@s_rd0mn ---- .... ... s:1 rd:4 .... rm:4 .... rn:4 &s_rrrr ra=0
+@rdamn ---- .... ... . rd:4 ra:4 rm:4 .... rn:4 &rrrr
+@rd0mn ---- .... ... . rd:4 .... rm:4 .... rn:4 &rrrr ra=0
+
+MUL .... 0000 000 . .... 0000 .... 1001 .... @s_rd0mn
+MLA .... 0000 001 . .... .... .... 1001 .... @s_rdamn
+UMAAL .... 0000 010 0 .... .... .... 1001 .... @rdamn
+MLS .... 0000 011 0 .... .... .... 1001 .... @rdamn
+UMULL .... 0000 100 . .... .... .... 1001 .... @s_rdamn
+UMLAL .... 0000 101 . .... .... .... 1001 .... @s_rdamn
+SMULL .... 0000 110 . .... .... .... 1001 .... @s_rdamn
+SMLAL .... 0000 111 . .... .... .... 1001 .... @s_rdamn
+
+# Saturating addition and subtraction
+
+@rndm ---- .... .... rn:4 rd:4 .... .... rm:4 &rrr
+
+QADD .... 0001 0000 .... .... 0000 0101 .... @rndm
+QSUB .... 0001 0010 .... .... 0000 0101 .... @rndm
+QDADD .... 0001 0100 .... .... 0000 0101 .... @rndm
+QDSUB .... 0001 0110 .... .... 0000 0101 .... @rndm
+
+# Halfword multiply and multiply accumulate
+
+SMLABB .... 0001 0000 .... .... .... 1000 .... @rdamn
+SMLABT .... 0001 0000 .... .... .... 1100 .... @rdamn
+SMLATB .... 0001 0000 .... .... .... 1010 .... @rdamn
+SMLATT .... 0001 0000 .... .... .... 1110 .... @rdamn
+SMLAWB .... 0001 0010 .... .... .... 1000 .... @rdamn
+SMULWB .... 0001 0010 .... 0000 .... 1010 .... @rd0mn
+SMLAWT .... 0001 0010 .... .... .... 1100 .... @rdamn
+SMULWT .... 0001 0010 .... 0000 .... 1110 .... @rd0mn
+SMLALBB .... 0001 0100 .... .... .... 1000 .... @rdamn
+SMLALBT .... 0001 0100 .... .... .... 1100 .... @rdamn
+SMLALTB .... 0001 0100 .... .... .... 1010 .... @rdamn
+SMLALTT .... 0001 0100 .... .... .... 1110 .... @rdamn
+SMULBB .... 0001 0110 .... 0000 .... 1000 .... @rd0mn
+SMULBT .... 0001 0110 .... 0000 .... 1100 .... @rd0mn
+SMULTB .... 0001 0110 .... 0000 .... 1010 .... @rd0mn
+SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn
+
+# MSR (immediate) and hints
+
+&msr_i r mask rot imm
+@msr_i ---- .... .... mask:4 .... rot:4 imm:8 &msr_i
+
+{
+ {
+ YIELD ---- 0011 0010 0000 1111 ---- 0000 0001
+ WFE ---- 0011 0010 0000 1111 ---- 0000 0010
+ WFI ---- 0011 0010 0000 1111 ---- 0000 0011
+
+ # TODO: Implement SEV, SEVL; may help SMP performance.
+ # SEV ---- 0011 0010 0000 1111 ---- 0000 0100
+ # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101
+
+ # The canonical nop ends in 00000000, but the whole of the
+ # rest of the space executes as nop if otherwise unsupported.
+ NOP ---- 0011 0010 0000 1111 ---- ---- ----
+ }
+ # Note mask = 0 is covered by NOP
+ MSR_imm .... 0011 0010 .... 1111 .... .... .... @msr_i r=0
+}
+MSR_imm .... 0011 0110 .... 1111 .... .... .... @msr_i r=1
+
+# Cyclic Redundancy Check
+
+CRC32B .... 0001 0000 .... .... 0000 0100 .... @rndm
+CRC32H .... 0001 0010 .... .... 0000 0100 .... @rndm
+CRC32W .... 0001 0100 .... .... 0000 0100 .... @rndm
+CRC32CB .... 0001 0000 .... .... 0010 0100 .... @rndm
+CRC32CH .... 0001 0010 .... .... 0010 0100 .... @rndm
+CRC32CW .... 0001 0100 .... .... 0010 0100 .... @rndm
+
+# Miscellaneous instructions
+
+%sysm 8:1 16:4
+%imm16_8_0 8:12 0:4
+
+@rm ---- .... .... .... .... .... .... rm:4 &r
+@rdm ---- .... .... .... rd:4 .... .... rm:4 &rr
+@i16 ---- .... .... .... .... .... .... .... &i imm=%imm16_8_0
+
+MRS_bank ---- 0001 0 r:1 00 .... rd:4 001. 0000 0000 &mrs_bank %sysm
+MSR_bank ---- 0001 0 r:1 10 .... 1111 001. 0000 rn:4 &msr_bank %sysm
+
+MRS_reg ---- 0001 0 r:1 00 1111 rd:4 0000 0000 0000 &mrs_reg
+MSR_reg ---- 0001 0 r:1 10 mask:4 1111 0000 0000 rn:4 &msr_reg
+
+BX .... 0001 0010 1111 1111 1111 0001 .... @rm
+BXJ .... 0001 0010 1111 1111 1111 0010 .... @rm
+BLX_r .... 0001 0010 1111 1111 1111 0011 .... @rm
+
+CLZ .... 0001 0110 1111 .... 1111 0001 .... @rdm
+
+ERET ---- 0001 0110 0000 0000 0000 0110 1110
+
+HLT .... 0001 0000 .... .... .... 0111 .... @i16
+BKPT .... 0001 0010 .... .... .... 0111 .... @i16
+HVC .... 0001 0100 .... .... .... 0111 .... @i16
+SMC ---- 0001 0110 0000 0000 0000 0111 imm:4 &i
+
+# Load/Store Dual, Half, Signed Byte (register)
+
+@ldst_rr_p1w ---- ...1 u:1 . w:1 . rn:4 rt:4 .... .... rm:4 \
+ &ldst_rr p=1 shimm=0 shtype=0
+@ldst_rr_pw0 ---- ...0 u:1 . 0 . rn:4 rt:4 .... .... rm:4 \
+ &ldst_rr p=0 w=0 shimm=0 shtype=0
+
+STRH_rr .... 000. .0.0 .... .... 0000 1011 .... @ldst_rr_pw0
+STRH_rr .... 000. .0.0 .... .... 0000 1011 .... @ldst_rr_p1w
+
+LDRD_rr .... 000. .0.0 .... .... 0000 1101 .... @ldst_rr_pw0
+LDRD_rr .... 000. .0.0 .... .... 0000 1101 .... @ldst_rr_p1w
+
+STRD_rr .... 000. .0.0 .... .... 0000 1111 .... @ldst_rr_pw0
+STRD_rr .... 000. .0.0 .... .... 0000 1111 .... @ldst_rr_p1w
+
+LDRH_rr .... 000. .0.1 .... .... 0000 1011 .... @ldst_rr_pw0
+LDRH_rr .... 000. .0.1 .... .... 0000 1011 .... @ldst_rr_p1w
+
+LDRSB_rr .... 000. .0.1 .... .... 0000 1101 .... @ldst_rr_pw0
+LDRSB_rr .... 000. .0.1 .... .... 0000 1101 .... @ldst_rr_p1w
+
+LDRSH_rr .... 000. .0.1 .... .... 0000 1111 .... @ldst_rr_pw0
+LDRSH_rr .... 000. .0.1 .... .... 0000 1111 .... @ldst_rr_p1w
+
+# Note the unpriv load/stores use the previously invalid P=0, W=1 encoding,
+# and act as normal post-indexed (P=0, W=0).
+@ldst_rr_p0w1 ---- ...0 u:1 . 1 . rn:4 rt:4 .... .... rm:4 \
+ &ldst_rr p=0 w=0 shimm=0 shtype=0
+
+STRHT_rr .... 000. .0.0 .... .... 0000 1011 .... @ldst_rr_p0w1
+LDRHT_rr .... 000. .0.1 .... .... 0000 1011 .... @ldst_rr_p0w1
+LDRSBT_rr .... 000. .0.1 .... .... 0000 1101 .... @ldst_rr_p0w1
+LDRSHT_rr .... 000. .0.1 .... .... 0000 1111 .... @ldst_rr_p0w1
+
+# Load/Store word and unsigned byte (register)
+
+@ldst_rs_p1w ---- ...1 u:1 . w:1 . rn:4 rt:4 shimm:5 shtype:2 . rm:4 \
+ &ldst_rr p=1
+@ldst_rs_pw0 ---- ...0 u:1 . 0 . rn:4 rt:4 shimm:5 shtype:2 . rm:4 \
+ &ldst_rr p=0 w=0
+
+STR_rr .... 011. .0.0 .... .... .... ...0 .... @ldst_rs_pw0
+STR_rr .... 011. .0.0 .... .... .... ...0 .... @ldst_rs_p1w
+STRB_rr .... 011. .1.0 .... .... .... ...0 .... @ldst_rs_pw0
+STRB_rr .... 011. .1.0 .... .... .... ...0 .... @ldst_rs_p1w
+
+LDR_rr .... 011. .0.1 .... .... .... ...0 .... @ldst_rs_pw0
+LDR_rr .... 011. .0.1 .... .... .... ...0 .... @ldst_rs_p1w
+LDRB_rr .... 011. .1.1 .... .... .... ...0 .... @ldst_rs_pw0
+LDRB_rr .... 011. .1.1 .... .... .... ...0 .... @ldst_rs_p1w
+
+@ldst_rs_p0w1 ---- ...0 u:1 . 1 . rn:4 rt:4 shimm:5 shtype:2 . rm:4 \
+ &ldst_rr p=0 w=0
+
+STRT_rr .... 011. .0.0 .... .... .... ...0 .... @ldst_rs_p0w1
+STRBT_rr .... 011. .1.0 .... .... .... ...0 .... @ldst_rs_p0w1
+LDRT_rr .... 011. .0.1 .... .... .... ...0 .... @ldst_rs_p0w1
+LDRBT_rr .... 011. .1.1 .... .... .... ...0 .... @ldst_rs_p0w1
+
+# Load/Store Dual, Half, Signed Byte (immediate)
+
+%imm8s_8_0 8:4 0:4
+@ldst_ri8_p1w ---- ...1 u:1 . w:1 . rn:4 rt:4 .... .... .... \
+ &ldst_ri imm=%imm8s_8_0 p=1
+@ldst_ri8_pw0 ---- ...0 u:1 . 0 . rn:4 rt:4 .... .... .... \
+ &ldst_ri imm=%imm8s_8_0 p=0 w=0
+
+STRH_ri .... 000. .1.0 .... .... .... 1011 .... @ldst_ri8_pw0
+STRH_ri .... 000. .1.0 .... .... .... 1011 .... @ldst_ri8_p1w
+
+LDRD_ri_a32 .... 000. .1.0 .... .... .... 1101 .... @ldst_ri8_pw0
+LDRD_ri_a32 .... 000. .1.0 .... .... .... 1101 .... @ldst_ri8_p1w
+
+STRD_ri_a32 .... 000. .1.0 .... .... .... 1111 .... @ldst_ri8_pw0
+STRD_ri_a32 .... 000. .1.0 .... .... .... 1111 .... @ldst_ri8_p1w
+
+LDRH_ri .... 000. .1.1 .... .... .... 1011 .... @ldst_ri8_pw0
+LDRH_ri .... 000. .1.1 .... .... .... 1011 .... @ldst_ri8_p1w
+
+LDRSB_ri .... 000. .1.1 .... .... .... 1101 .... @ldst_ri8_pw0
+LDRSB_ri .... 000. .1.1 .... .... .... 1101 .... @ldst_ri8_p1w
+
+LDRSH_ri .... 000. .1.1 .... .... .... 1111 .... @ldst_ri8_pw0
+LDRSH_ri .... 000. .1.1 .... .... .... 1111 .... @ldst_ri8_p1w
+
+# Note the unpriv load/stores use the previously invalid P=0, W=1 encoding,
+# and act as normal post-indexed (P=0, W=0).
+@ldst_ri8_p0w1 ---- ...0 u:1 . 1 . rn:4 rt:4 .... .... .... \
+ &ldst_ri imm=%imm8s_8_0 p=0 w=0
+
+STRHT_ri .... 000. .1.0 .... .... .... 1011 .... @ldst_ri8_p0w1
+LDRHT_ri .... 000. .1.1 .... .... .... 1011 .... @ldst_ri8_p0w1
+LDRSBT_ri .... 000. .1.1 .... .... .... 1101 .... @ldst_ri8_p0w1
+LDRSHT_ri .... 000. .1.1 .... .... .... 1111 .... @ldst_ri8_p0w1
+
+# Load/Store word and unsigned byte (immediate)
+
+@ldst_ri12_p1w ---- ...1 u:1 . w:1 . rn:4 rt:4 imm:12 &ldst_ri p=1
+@ldst_ri12_pw0 ---- ...0 u:1 . 0 . rn:4 rt:4 imm:12 &ldst_ri p=0 w=0
+
+STR_ri .... 010. .0.0 .... .... ............ @ldst_ri12_p1w
+STR_ri .... 010. .0.0 .... .... ............ @ldst_ri12_pw0
+STRB_ri .... 010. .1.0 .... .... ............ @ldst_ri12_p1w
+STRB_ri .... 010. .1.0 .... .... ............ @ldst_ri12_pw0
+
+LDR_ri .... 010. .0.1 .... .... ............ @ldst_ri12_p1w
+LDR_ri .... 010. .0.1 .... .... ............ @ldst_ri12_pw0
+LDRB_ri .... 010. .1.1 .... .... ............ @ldst_ri12_p1w
+LDRB_ri .... 010. .1.1 .... .... ............ @ldst_ri12_pw0
+
+@ldst_ri12_p0w1 ---- ...0 u:1 . 1 . rn:4 rt:4 imm:12 &ldst_ri p=0 w=0
+
+STRT_ri .... 010. .0.0 .... .... ............ @ldst_ri12_p0w1
+STRBT_ri .... 010. .1.0 .... .... ............ @ldst_ri12_p0w1
+LDRT_ri .... 010. .0.1 .... .... ............ @ldst_ri12_p0w1
+LDRBT_ri .... 010. .1.1 .... .... ............ @ldst_ri12_p0w1
+
+# Synchronization primitives
+
+@swp ---- .... .... rn:4 rt:4 .... .... rt2:4
+
+SWP .... 0001 0000 .... .... 0000 1001 .... @swp
+SWPB .... 0001 0100 .... .... 0000 1001 .... @swp
+
+# Load/Store Exclusive and Load-Acquire/Store-Release
+#
+# Note rt2 for STREXD/LDREXD is set by the helper after checking rt is even.
+
+@strex ---- .... .... rn:4 rd:4 .... .... rt:4 \
+ &strex imm=0 rt2=15
+@ldrex ---- .... .... rn:4 rt:4 .... .... .... \
+ &ldrex imm=0 rt2=15
+@stl ---- .... .... rn:4 .... .... .... rt:4 \
+ &ldrex imm=0 rt2=15
+
+STREX .... 0001 1000 .... .... 1111 1001 .... @strex
+STREXD_a32 .... 0001 1010 .... .... 1111 1001 .... @strex
+STREXB .... 0001 1100 .... .... 1111 1001 .... @strex
+STREXH .... 0001 1110 .... .... 1111 1001 .... @strex
+
+STLEX .... 0001 1000 .... .... 1110 1001 .... @strex
+STLEXD_a32 .... 0001 1010 .... .... 1110 1001 .... @strex
+STLEXB .... 0001 1100 .... .... 1110 1001 .... @strex
+STLEXH .... 0001 1110 .... .... 1110 1001 .... @strex
+
+STL .... 0001 1000 .... 1111 1100 1001 .... @stl
+STLB .... 0001 1100 .... 1111 1100 1001 .... @stl
+STLH .... 0001 1110 .... 1111 1100 1001 .... @stl
+
+LDREX .... 0001 1001 .... .... 1111 1001 1111 @ldrex
+LDREXD_a32 .... 0001 1011 .... .... 1111 1001 1111 @ldrex
+LDREXB .... 0001 1101 .... .... 1111 1001 1111 @ldrex
+LDREXH .... 0001 1111 .... .... 1111 1001 1111 @ldrex
+
+LDAEX .... 0001 1001 .... .... 1110 1001 1111 @ldrex
+LDAEXD_a32 .... 0001 1011 .... .... 1110 1001 1111 @ldrex
+LDAEXB .... 0001 1101 .... .... 1110 1001 1111 @ldrex
+LDAEXH .... 0001 1111 .... .... 1110 1001 1111 @ldrex
+
+LDA .... 0001 1001 .... .... 1100 1001 1111 @ldrex
+LDAB .... 0001 1101 .... .... 1100 1001 1111 @ldrex
+LDAH .... 0001 1111 .... .... 1100 1001 1111 @ldrex
+
+# Media instructions
+
+# usad8 is usada8 w/ ra=15
+USADA8 ---- 0111 1000 rd:4 ra:4 rm:4 0001 rn:4
+
+# ubfx and sbfx
+@bfx ---- .... ... widthm1:5 rd:4 lsb:5 ... rn:4 &bfx
+
+SBFX .... 0111 101 ..... .... ..... 101 .... @bfx
+UBFX .... 0111 111 ..... .... ..... 101 .... @bfx
+
+# bfc is bfi w/ rn=15
+BFCI ---- 0111 110 msb:5 rd:4 lsb:5 001 rn:4 &bfi
+
+# While we could get UDEF by not including this, add the pattern for
+# documentation and to conflict with any other typos in this file.
+UDF 1110 0111 1111 ---- ---- ---- 1111 ----
+
+# Parallel addition and subtraction
+
+SADD16 .... 0110 0001 .... .... 1111 0001 .... @rndm
+SASX .... 0110 0001 .... .... 1111 0011 .... @rndm
+SSAX .... 0110 0001 .... .... 1111 0101 .... @rndm
+SSUB16 .... 0110 0001 .... .... 1111 0111 .... @rndm
+SADD8 .... 0110 0001 .... .... 1111 1001 .... @rndm
+SSUB8 .... 0110 0001 .... .... 1111 1111 .... @rndm
+
+QADD16 .... 0110 0010 .... .... 1111 0001 .... @rndm
+QASX .... 0110 0010 .... .... 1111 0011 .... @rndm
+QSAX .... 0110 0010 .... .... 1111 0101 .... @rndm
+QSUB16 .... 0110 0010 .... .... 1111 0111 .... @rndm
+QADD8 .... 0110 0010 .... .... 1111 1001 .... @rndm
+QSUB8 .... 0110 0010 .... .... 1111 1111 .... @rndm
+
+SHADD16 .... 0110 0011 .... .... 1111 0001 .... @rndm
+SHASX .... 0110 0011 .... .... 1111 0011 .... @rndm
+SHSAX .... 0110 0011 .... .... 1111 0101 .... @rndm
+SHSUB16 .... 0110 0011 .... .... 1111 0111 .... @rndm
+SHADD8 .... 0110 0011 .... .... 1111 1001 .... @rndm
+SHSUB8 .... 0110 0011 .... .... 1111 1111 .... @rndm
+
+UADD16 .... 0110 0101 .... .... 1111 0001 .... @rndm
+UASX .... 0110 0101 .... .... 1111 0011 .... @rndm
+USAX .... 0110 0101 .... .... 1111 0101 .... @rndm
+USUB16 .... 0110 0101 .... .... 1111 0111 .... @rndm
+UADD8 .... 0110 0101 .... .... 1111 1001 .... @rndm
+USUB8 .... 0110 0101 .... .... 1111 1111 .... @rndm
+
+UQADD16 .... 0110 0110 .... .... 1111 0001 .... @rndm
+UQASX .... 0110 0110 .... .... 1111 0011 .... @rndm
+UQSAX .... 0110 0110 .... .... 1111 0101 .... @rndm
+UQSUB16 .... 0110 0110 .... .... 1111 0111 .... @rndm
+UQADD8 .... 0110 0110 .... .... 1111 1001 .... @rndm
+UQSUB8 .... 0110 0110 .... .... 1111 1111 .... @rndm
+
+UHADD16 .... 0110 0111 .... .... 1111 0001 .... @rndm
+UHASX .... 0110 0111 .... .... 1111 0011 .... @rndm
+UHSAX .... 0110 0111 .... .... 1111 0101 .... @rndm
+UHSUB16 .... 0110 0111 .... .... 1111 0111 .... @rndm
+UHADD8 .... 0110 0111 .... .... 1111 1001 .... @rndm
+UHSUB8 .... 0110 0111 .... .... 1111 1111 .... @rndm
+
+# Packing, unpacking, saturation, and reversal
+
+PKH ---- 0110 1000 rn:4 rd:4 imm:5 tb:1 01 rm:4 &pkh
+
+@sat ---- .... ... satimm:5 rd:4 imm:5 sh:1 .. rn:4 &sat
+@sat16 ---- .... .... satimm:4 rd:4 .... .... rn:4 \
+ &sat imm=0 sh=0
+
+SSAT .... 0110 101. .... .... .... ..01 .... @sat
+USAT .... 0110 111. .... .... .... ..01 .... @sat
+
+SSAT16 .... 0110 1010 .... .... 1111 0011 .... @sat16
+USAT16 .... 0110 1110 .... .... 1111 0011 .... @sat16
+
+@rrr_rot ---- .... .... rn:4 rd:4 rot:2 ...... rm:4 &rrr_rot
+
+SXTAB16 .... 0110 1000 .... .... ..00 0111 .... @rrr_rot
+SXTAB .... 0110 1010 .... .... ..00 0111 .... @rrr_rot
+SXTAH .... 0110 1011 .... .... ..00 0111 .... @rrr_rot
+UXTAB16 .... 0110 1100 .... .... ..00 0111 .... @rrr_rot
+UXTAB .... 0110 1110 .... .... ..00 0111 .... @rrr_rot
+UXTAH .... 0110 1111 .... .... ..00 0111 .... @rrr_rot
+
+SEL .... 0110 1000 .... .... 1111 1011 .... @rndm
+REV .... 0110 1011 1111 .... 1111 0011 .... @rdm
+REV16 .... 0110 1011 1111 .... 1111 1011 .... @rdm
+REVSH .... 0110 1111 1111 .... 1111 1011 .... @rdm
+RBIT .... 0110 1111 1111 .... 1111 0011 .... @rdm
+
+# Signed multiply, signed and unsigned divide
+
+@rdmn ---- .... .... rd:4 .... rm:4 .... rn:4 &rrr
+
+SMLAD .... 0111 0000 .... .... .... 0001 .... @rdamn
+SMLADX .... 0111 0000 .... .... .... 0011 .... @rdamn
+SMLSD .... 0111 0000 .... .... .... 0101 .... @rdamn
+SMLSDX .... 0111 0000 .... .... .... 0111 .... @rdamn
+
+SDIV .... 0111 0001 .... 1111 .... 0001 .... @rdmn
+UDIV .... 0111 0011 .... 1111 .... 0001 .... @rdmn
+
+SMLALD .... 0111 0100 .... .... .... 0001 .... @rdamn
+SMLALDX .... 0111 0100 .... .... .... 0011 .... @rdamn
+SMLSLD .... 0111 0100 .... .... .... 0101 .... @rdamn
+SMLSLDX .... 0111 0100 .... .... .... 0111 .... @rdamn
+
+SMMLA .... 0111 0101 .... .... .... 0001 .... @rdamn
+SMMLAR .... 0111 0101 .... .... .... 0011 .... @rdamn
+SMMLS .... 0111 0101 .... .... .... 1101 .... @rdamn
+SMMLSR .... 0111 0101 .... .... .... 1111 .... @rdamn
+
+# Block data transfer
+
+STM ---- 100 b:1 i:1 u:1 w:1 0 rn:4 list:16 &ldst_block
+LDM_a32 ---- 100 b:1 i:1 u:1 w:1 1 rn:4 list:16 &ldst_block
+
+# Branch, branch with link
+
+%imm26 0:s24 !function=times_4
+@branch ---- .... ........................ &i imm=%imm26
+
+B .... 1010 ........................ @branch
+BL .... 1011 ........................ @branch
+
+# Supervisor call
+
+SVC ---- 1111 imm:24 &i
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 0981303170..297ad5e47a 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -2212,6 +2212,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
* IO indicates that this register does I/O and therefore its accesses
* need to be surrounded by gen_io_start()/gen_io_end(). In particular,
* registers which implement clocks or timers require this.
+ * RAISES_EXC is for when the read or write hook might raise an exception;
+ * the generated code will synchronize the CPU state before calling the hook
+ * so that it is safe for the hook to call raise_exception().
*/
#define ARM_CP_SPECIAL 0x0001
#define ARM_CP_CONST 0x0002
@@ -2230,10 +2233,11 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
#define ARM_CP_FPU 0x1000
#define ARM_CP_SVE 0x2000
#define ARM_CP_NO_GDB 0x4000
+#define ARM_CP_RAISES_EXC 0x8000
/* Used only as a terminator for ARMCPRegInfo lists */
#define ARM_CP_SENTINEL 0xffff
/* Mask of only the flag bits in a type field */
-#define ARM_CP_FLAG_MASK 0x70ff
+#define ARM_CP_FLAG_MASK 0xf0ff
/* Valid values for ARMCPRegInfo state field, indicating which of
* the AArch32 and AArch64 execution states this register is visible in.
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 7e0d5398ab..507026c915 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2946,6 +2946,73 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs,
&prot, &page_size, &fi, &cacheattrs);
+ if (ret) {
+ /*
+ * Some kinds of translation fault must cause exceptions rather
+ * than being reported in the PAR.
+ */
+ int current_el = arm_current_el(env);
+ int target_el;
+ uint32_t syn, fsr, fsc;
+ bool take_exc = false;
+
+ if (fi.s1ptw && current_el == 1 && !arm_is_secure(env)
+ && (mmu_idx == ARMMMUIdx_S1NSE1 || mmu_idx == ARMMMUIdx_S1NSE0)) {
+ /*
+ * Synchronous stage 2 fault on an access made as part of the
+ * translation table walk for AT S1E0* or AT S1E1* insn
+ * executed from NS EL1. If this is a synchronous external abort
+ * and SCR_EL3.EA == 1, then we take a synchronous external abort
+ * to EL3. Otherwise the fault is taken as an exception to EL2,
+ * and HPFAR_EL2 holds the faulting IPA.
+ */
+ if (fi.type == ARMFault_SyncExternalOnWalk &&
+ (env->cp15.scr_el3 & SCR_EA)) {
+ target_el = 3;
+ } else {
+ env->cp15.hpfar_el2 = extract64(fi.s2addr, 12, 47) << 4;
+ target_el = 2;
+ }
+ take_exc = true;
+ } else if (fi.type == ARMFault_SyncExternalOnWalk) {
+ /*
+ * Synchronous external aborts during a translation table walk
+ * are taken as Data Abort exceptions.
+ */
+ if (fi.stage2) {
+ if (current_el == 3) {
+ target_el = 3;
+ } else {
+ target_el = 2;
+ }
+ } else {
+ target_el = exception_target_el(env);
+ }
+ take_exc = true;
+ }
+
+ if (take_exc) {
+ /* Construct FSR and FSC using same logic as arm_deliver_fault() */
+ if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
+ arm_s1_regime_using_lpae_format(env, mmu_idx)) {
+ fsr = arm_fi_to_lfsc(&fi);
+ fsc = extract32(fsr, 0, 6);
+ } else {
+ fsr = arm_fi_to_sfsc(&fi);
+ fsc = 0x3f;
+ }
+ /*
+ * Report exception with ESR indicating a fault due to a
+ * translation table walk for a cache maintenance instruction.
+ */
+ syn = syn_data_abort_no_iss(current_el == target_el,
+ fi.ea, 1, fi.s1ptw, 1, fsc);
+ env->exception.vaddress = value;
+ env->exception.fsr = fsr;
+ raise_exception(env, EXCP_DATA_ABORT, syn, target_el);
+ }
+ }
+
if (is_a64(env)) {
format64 = true;
} else if (arm_feature(env, ARM_FEATURE_LPAE)) {
@@ -3150,7 +3217,7 @@ static const ARMCPRegInfo vapa_cp_reginfo[] = {
/* This underdecoding is safe because the reginfo is NO_RAW. */
{ .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY,
.access = PL1_W, .accessfn = ats_access,
- .writefn = ats_write, .type = ARM_CP_NO_RAW },
+ .writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
#endif
REGINFO_SENTINEL
};
@@ -4283,35 +4350,45 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
/* 64 bit address translation operations */
{ .name = "AT_S1E1R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0,
- .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1,
- .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2,
- .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3,
- .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4,
- .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "AT_S12E1W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 5,
- .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "AT_S12E0R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 6,
- .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "AT_S12E0W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 7,
- .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
/* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present */
{ .name = "AT_S1E3R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 0,
- .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "AT_S1E3W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 1,
- .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
+ .writefn = ats_write64 },
{ .name = "PAR_EL1", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0,
@@ -4893,11 +4970,11 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .name = "AT_S1E2R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0,
.access = PL2_W, .accessfn = at_s1e2_access,
- .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 },
{ .name = "AT_S1E2W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1,
.access = PL2_W, .accessfn = at_s1e2_access,
- .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
+ .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 },
/* The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE
* if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3
* with SCR.NS == 0 outside Monitor mode is UNPREDICTABLE; we choose
@@ -4905,10 +4982,10 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
*/
{ .name = "ATS1HR", .cp = 15, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0,
.access = PL2_W,
- .writefn = ats1h_write, .type = ARM_CP_NO_RAW },
+ .writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
{ .name = "ATS1HW", .cp = 15, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1,
.access = PL2_W,
- .writefn = ats1h_write, .type = ARM_CP_NO_RAW },
+ .writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
{ .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0,
/* ARMv7 requires bit 0 and 1 to reset to 1. ARMv8 defines the
diff --git a/target/arm/t16.decode b/target/arm/t16.decode
new file mode 100644
index 0000000000..43b9a267a1
--- /dev/null
+++ b/target/arm/t16.decode
@@ -0,0 +1,281 @@
+# Thumb1 instructions
+#
+# Copyright (c) 2019 Linaro, Ltd
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+#
+# This file is processed by scripts/decodetree.py
+#
+
+&empty !extern
+&s_rrr_shi !extern s rd rn rm shim shty
+&s_rrr_shr !extern s rn rd rm rs shty
+&s_rri_rot !extern s rn rd imm rot
+&s_rrrr !extern s rd rn rm ra
+&rrr_rot !extern rd rn rm rot
+&rr !extern rd rm
+&ri !extern rd imm
+&r !extern rm
+&i !extern imm
+&ldst_rr !extern p w u rn rt rm shimm shtype
+&ldst_ri !extern p w u rn rt imm
+&ldst_block !extern rn i b u w list
+&setend !extern E
+&cps !extern mode imod M A I F
+&ci !extern cond imm
+
+# Set S if the instruction is outside of an IT block.
+%s !function=t16_setflags
+
+# Data-processing (two low registers)
+
+%reg_0 0:3
+
+@lll_noshr ...... .... rm:3 rd:3 \
+ &s_rrr_shi %s rn=%reg_0 shim=0 shty=0
+@xll_noshr ...... .... rm:3 rn:3 \
+ &s_rrr_shi s=1 rd=0 shim=0 shty=0
+@lxl_shr ...... .... rs:3 rd:3 \
+ &s_rrr_shr %s rm=%reg_0 rn=0
+
+AND_rrri 010000 0000 ... ... @lll_noshr
+EOR_rrri 010000 0001 ... ... @lll_noshr
+MOV_rxrr 010000 0010 ... ... @lxl_shr shty=0 # LSL
+MOV_rxrr 010000 0011 ... ... @lxl_shr shty=1 # LSR
+MOV_rxrr 010000 0100 ... ... @lxl_shr shty=2 # ASR
+ADC_rrri 010000 0101 ... ... @lll_noshr
+SBC_rrri 010000 0110 ... ... @lll_noshr
+MOV_rxrr 010000 0111 ... ... @lxl_shr shty=3 # ROR
+TST_xrri 010000 1000 ... ... @xll_noshr
+RSB_rri 010000 1001 rn:3 rd:3 &s_rri_rot %s imm=0 rot=0
+CMP_xrri 010000 1010 ... ... @xll_noshr
+CMN_xrri 010000 1011 ... ... @xll_noshr
+ORR_rrri 010000 1100 ... ... @lll_noshr
+MUL 010000 1101 rn:3 rd:3 &s_rrrr %s rm=%reg_0 ra=0
+BIC_rrri 010000 1110 ... ... @lll_noshr
+MVN_rxri 010000 1111 ... ... @lll_noshr
+
+# Load/store (register offset)
+
+@ldst_rr ....... rm:3 rn:3 rt:3 \
+ &ldst_rr p=1 w=0 u=1 shimm=0 shtype=0
+
+STR_rr 0101 000 ... ... ... @ldst_rr
+STRH_rr 0101 001 ... ... ... @ldst_rr
+STRB_rr 0101 010 ... ... ... @ldst_rr
+LDRSB_rr 0101 011 ... ... ... @ldst_rr
+LDR_rr 0101 100 ... ... ... @ldst_rr
+LDRH_rr 0101 101 ... ... ... @ldst_rr
+LDRB_rr 0101 110 ... ... ... @ldst_rr
+LDRSH_rr 0101 111 ... ... ... @ldst_rr
+
+# Load/store word/byte (immediate offset)
+
+%imm5_6x4 6:5 !function=times_4
+
+@ldst_ri_1 ..... imm:5 rn:3 rt:3 \
+ &ldst_ri p=1 w=0 u=1
+@ldst_ri_4 ..... ..... rn:3 rt:3 \
+ &ldst_ri p=1 w=0 u=1 imm=%imm5_6x4
+
+STR_ri 01100 ..... ... ... @ldst_ri_4
+LDR_ri 01101 ..... ... ... @ldst_ri_4
+STRB_ri 01110 ..... ... ... @ldst_ri_1
+LDRB_ri 01111 ..... ... ... @ldst_ri_1
+
+# Load/store halfword (immediate offset)
+
+%imm5_6x2 6:5 !function=times_2
+@ldst_ri_2 ..... ..... rn:3 rt:3 \
+ &ldst_ri p=1 w=0 u=1 imm=%imm5_6x2
+
+STRH_ri 10000 ..... ... ... @ldst_ri_2
+LDRH_ri 10001 ..... ... ... @ldst_ri_2
+
+# Load/store (SP-relative)
+
+%imm8_0x4 0:8 !function=times_4
+@ldst_spec_i ..... rt:3 ........ \
+ &ldst_ri p=1 w=0 u=1 imm=%imm8_0x4
+
+STR_ri 10010 ... ........ @ldst_spec_i rn=13
+LDR_ri 10011 ... ........ @ldst_spec_i rn=13
+
+# Load (PC-relative)
+
+LDR_ri 01001 ... ........ @ldst_spec_i rn=15
+
+# Add PC/SP (immediate)
+
+ADR 10100 rd:3 ........ imm=%imm8_0x4
+ADD_rri 10101 rd:3 ........ \
+ &s_rri_rot rn=13 s=0 rot=0 imm=%imm8_0x4 # SP
+
+# Load/store multiple
+
+@ldstm ..... rn:3 list:8 &ldst_block i=1 b=0 u=0 w=1
+
+STM 11000 ... ........ @ldstm
+LDM_t16 11001 ... ........ @ldstm
+
+# Shift (immediate)
+
+@shift_i ..... shim:5 rm:3 rd:3 &s_rrr_shi %s rn=%reg_0
+
+MOV_rxri 000 00 ..... ... ... @shift_i shty=0 # LSL
+MOV_rxri 000 01 ..... ... ... @shift_i shty=1 # LSR
+MOV_rxri 000 10 ..... ... ... @shift_i shty=2 # ASR
+
+# Add/subtract (three low registers)
+
+@addsub_3 ....... rm:3 rn:3 rd:3 \
+ &s_rrr_shi %s shim=0 shty=0
+
+ADD_rrri 0001100 ... ... ... @addsub_3
+SUB_rrri 0001101 ... ... ... @addsub_3
+
+# Add/subtract (two low registers and immediate)
+
+@addsub_2i ....... imm:3 rn:3 rd:3 \
+ &s_rri_rot %s rot=0
+
+ADD_rri 0001 110 ... ... ... @addsub_2i
+SUB_rri 0001 111 ... ... ... @addsub_2i
+
+# Add, subtract, compare, move (one low register and immediate)
+
+%reg_8 8:3
+@arith_1i ..... rd:3 imm:8 \
+ &s_rri_rot rot=0 rn=%reg_8
+
+MOV_rxi 00100 ... ........ @arith_1i %s
+CMP_xri 00101 ... ........ @arith_1i s=1
+ADD_rri 00110 ... ........ @arith_1i %s
+SUB_rri 00111 ... ........ @arith_1i %s
+
+# Add, compare, move (two high registers)
+
+%reg_0_7 7:1 0:3
+@addsub_2h .... .... . rm:4 ... \
+ &s_rrr_shi rd=%reg_0_7 rn=%reg_0_7 shim=0 shty=0
+
+ADD_rrri 0100 0100 . .... ... @addsub_2h s=0
+CMP_xrri 0100 0101 . .... ... @addsub_2h s=1
+MOV_rxri 0100 0110 . .... ... @addsub_2h s=0
+
+# Adjust SP (immediate)
+
+%imm7_0x4 0:7 !function=times_4
+@addsub_sp_i .... .... . ....... \
+ &s_rri_rot s=0 rd=13 rn=13 rot=0 imm=%imm7_0x4
+
+ADD_rri 1011 0000 0 ....... @addsub_sp_i
+SUB_rri 1011 0000 1 ....... @addsub_sp_i
+
+# Branch and exchange
+
+@branchr .... .... . rm:4 ... &r
+
+BX 0100 0111 0 .... 000 @branchr
+BLX_r 0100 0111 1 .... 000 @branchr
+BXNS 0100 0111 0 .... 100 @branchr
+BLXNS 0100 0111 1 .... 100 @branchr
+
+# Extend
+
+@extend .... .... .. rm:3 rd:3 &rrr_rot rn=15 rot=0
+
+SXTAH 1011 0010 00 ... ... @extend
+SXTAB 1011 0010 01 ... ... @extend
+UXTAH 1011 0010 10 ... ... @extend
+UXTAB 1011 0010 11 ... ... @extend
+
+# Change processor state
+
+%imod 4:1 !function=plus_2
+
+SETEND 1011 0110 010 1 E:1 000 &setend
+{
+ CPS 1011 0110 011 . 0 A:1 I:1 F:1 &cps mode=0 M=0 %imod
+ CPS_v7m 1011 0110 011 im:1 00 I:1 F:1
+}
+
+# Reverse bytes
+
+@rdm .... .... .. rm:3 rd:3 &rr
+
+REV 1011 1010 00 ... ... @rdm
+REV16 1011 1010 01 ... ... @rdm
+REVSH 1011 1010 11 ... ... @rdm
+
+# Hints
+
+{
+ {
+ YIELD 1011 1111 0001 0000
+ WFE 1011 1111 0010 0000
+ WFI 1011 1111 0011 0000
+
+ # TODO: Implement SEV, SEVL; may help SMP performance.
+ # SEV 1011 1111 0100 0000
+ # SEVL 1011 1111 0101 0000
+
+ # The canonical nop has the second nibble as 0000, but the whole of the
+ # rest of the space is a reserved hint, behaves as nop.
+ NOP 1011 1111 ---- 0000
+ }
+ IT 1011 1111 cond_mask:8
+}
+
+# Miscellaneous 16-bit instructions
+
+%imm6_9_3 9:1 3:5 !function=times_2
+
+HLT 1011 1010 10 imm:6 &i
+BKPT 1011 1110 imm:8 &i
+CBZ 1011 nz:1 0.1 ..... rn:3 imm=%imm6_9_3
+
+# Push and Pop
+
+%push_list 0:9 !function=t16_push_list
+%pop_list 0:9 !function=t16_pop_list
+
+STM 1011 010 ......... \
+ &ldst_block i=0 b=1 u=0 w=1 rn=13 list=%push_list
+LDM_t16 1011 110 ......... \
+ &ldst_block i=1 b=0 u=0 w=1 rn=13 list=%pop_list
+
+# Conditional branches, Supervisor call
+
+%imm8_0x2 0:s8 !function=times_2
+
+{
+ UDF 1101 1110 ---- ----
+ SVC 1101 1111 imm:8 &i
+ B_cond_thumb 1101 cond:4 ........ &ci imm=%imm8_0x2
+}
+
+# Unconditional Branch
+
+%imm11_0x2 0:s11 !function=times_2
+
+B 11100 ........... &i imm=%imm11_0x2
+
+# thumb_insn_is_16bit() ensures we won't be decoding these as
+# T16 instructions for a Thumb2 CPU, so these patterns must be
+# a Thumb1 split BL/BLX.
+BLX_suffix 11101 imm:11 &i
+BL_BLX_prefix 11110 imm:s11 &i
+BL_suffix 11111 imm:11 &i
diff --git a/target/arm/t32.decode b/target/arm/t32.decode
new file mode 100644
index 0000000000..c63082fc9c
--- /dev/null
+++ b/target/arm/t32.decode
@@ -0,0 +1,631 @@
+# Thumb2 instructions
+#
+# Copyright (c) 2019 Linaro, Ltd
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+#
+# This file is processed by scripts/decodetree.py
+#
+
+&empty !extern
+&s_rrr_shi !extern s rd rn rm shim shty
+&s_rrr_shr !extern s rn rd rm rs shty
+&s_rri_rot !extern s rn rd imm rot
+&s_rrrr !extern s rd rn rm ra
+&rrrr !extern rd rn rm ra
+&rrr_rot !extern rd rn rm rot
+&rrr !extern rd rn rm
+&rr !extern rd rm
+&ri !extern rd imm
+&r !extern rm
+&i !extern imm
+&msr_reg !extern rn r mask
+&mrs_reg !extern rd r
+&msr_bank !extern rn r sysm
+&mrs_bank !extern rd r sysm
+&ldst_rr !extern p w u rn rt rm shimm shtype
+&ldst_ri !extern p w u rn rt imm
+&ldst_block !extern rn i b u w list
+&strex !extern rn rd rt rt2 imm
+&ldrex !extern rn rt rt2 imm
+&bfx !extern rd rn lsb widthm1
+&bfi !extern rd rn lsb msb
+&sat !extern rd rn satimm imm sh
+&pkh !extern rd rn rm imm tb
+&cps !extern mode imod M A I F
+
+# Data-processing (register)
+
+%imm5_12_6 12:3 6:2
+
+@s_rrr_shi ....... .... s:1 rn:4 .... rd:4 .. shty:2 rm:4 \
+ &s_rrr_shi shim=%imm5_12_6
+@s_rxr_shi ....... .... s:1 .... .... rd:4 .. shty:2 rm:4 \
+ &s_rrr_shi shim=%imm5_12_6 rn=0
+@S_xrr_shi ....... .... . rn:4 .... .... .. shty:2 rm:4 \
+ &s_rrr_shi shim=%imm5_12_6 s=1 rd=0
+
+{
+ TST_xrri 1110101 0000 1 .... 0 ... 1111 .... .... @S_xrr_shi
+ AND_rrri 1110101 0000 . .... 0 ... .... .... .... @s_rrr_shi
+}
+BIC_rrri 1110101 0001 . .... 0 ... .... .... .... @s_rrr_shi
+{
+ MOV_rxri 1110101 0010 . 1111 0 ... .... .... .... @s_rxr_shi
+ ORR_rrri 1110101 0010 . .... 0 ... .... .... .... @s_rrr_shi
+}
+{
+ MVN_rxri 1110101 0011 . 1111 0 ... .... .... .... @s_rxr_shi
+ ORN_rrri 1110101 0011 . .... 0 ... .... .... .... @s_rrr_shi
+}
+{
+ TEQ_xrri 1110101 0100 1 .... 0 ... 1111 .... .... @S_xrr_shi
+ EOR_rrri 1110101 0100 . .... 0 ... .... .... .... @s_rrr_shi
+}
+PKH 1110101 0110 0 rn:4 0 ... rd:4 .. tb:1 0 rm:4 \
+ &pkh imm=%imm5_12_6
+{
+ CMN_xrri 1110101 1000 1 .... 0 ... 1111 .... .... @S_xrr_shi
+ ADD_rrri 1110101 1000 . .... 0 ... .... .... .... @s_rrr_shi
+}
+ADC_rrri 1110101 1010 . .... 0 ... .... .... .... @s_rrr_shi
+SBC_rrri 1110101 1011 . .... 0 ... .... .... .... @s_rrr_shi
+{
+ CMP_xrri 1110101 1101 1 .... 0 ... 1111 .... .... @S_xrr_shi
+ SUB_rrri 1110101 1101 . .... 0 ... .... .... .... @s_rrr_shi
+}
+RSB_rrri 1110101 1110 . .... 0 ... .... .... .... @s_rrr_shi
+
+# Data-processing (register-shifted register)
+
+MOV_rxrr 1111 1010 0 shty:2 s:1 rm:4 1111 rd:4 0000 rs:4 \
+ &s_rrr_shr rn=0
+
+# Data-processing (immediate)
+
+%t32extrot 26:1 12:3 0:8 !function=t32_expandimm_rot
+%t32extimm 26:1 12:3 0:8 !function=t32_expandimm_imm
+
+@s_rri_rot ....... .... s:1 rn:4 . ... rd:4 ........ \
+ &s_rri_rot imm=%t32extimm rot=%t32extrot
+@s_rxi_rot ....... .... s:1 .... . ... rd:4 ........ \
+ &s_rri_rot imm=%t32extimm rot=%t32extrot rn=0
+@S_xri_rot ....... .... . rn:4 . ... .... ........ \
+ &s_rri_rot imm=%t32extimm rot=%t32extrot s=1 rd=0
+
+{
+ TST_xri 1111 0.0 0000 1 .... 0 ... 1111 ........ @S_xri_rot
+ AND_rri 1111 0.0 0000 . .... 0 ... .... ........ @s_rri_rot
+}
+BIC_rri 1111 0.0 0001 . .... 0 ... .... ........ @s_rri_rot
+{
+ MOV_rxi 1111 0.0 0010 . 1111 0 ... .... ........ @s_rxi_rot
+ ORR_rri 1111 0.0 0010 . .... 0 ... .... ........ @s_rri_rot
+}
+{
+ MVN_rxi 1111 0.0 0011 . 1111 0 ... .... ........ @s_rxi_rot
+ ORN_rri 1111 0.0 0011 . .... 0 ... .... ........ @s_rri_rot
+}
+{
+ TEQ_xri 1111 0.0 0100 1 .... 0 ... 1111 ........ @S_xri_rot
+ EOR_rri 1111 0.0 0100 . .... 0 ... .... ........ @s_rri_rot
+}
+{
+ CMN_xri 1111 0.0 1000 1 .... 0 ... 1111 ........ @S_xri_rot
+ ADD_rri 1111 0.0 1000 . .... 0 ... .... ........ @s_rri_rot
+}
+ADC_rri 1111 0.0 1010 . .... 0 ... .... ........ @s_rri_rot
+SBC_rri 1111 0.0 1011 . .... 0 ... .... ........ @s_rri_rot
+{
+ CMP_xri 1111 0.0 1101 1 .... 0 ... 1111 ........ @S_xri_rot
+ SUB_rri 1111 0.0 1101 . .... 0 ... .... ........ @s_rri_rot
+}
+RSB_rri 1111 0.0 1110 . .... 0 ... .... ........ @s_rri_rot
+
+# Data processing (plain binary immediate)
+
+%imm12_26_12_0 26:1 12:3 0:8
+%neg12_26_12_0 26:1 12:3 0:8 !function=negate
+@s0_rri_12 .... ... .... . rn:4 . ... rd:4 ........ \
+ &s_rri_rot imm=%imm12_26_12_0 rot=0 s=0
+
+{
+ ADR 1111 0.1 0000 0 1111 0 ... rd:4 ........ \
+ &ri imm=%imm12_26_12_0
+ ADD_rri 1111 0.1 0000 0 .... 0 ... .... ........ @s0_rri_12
+}
+{
+ ADR 1111 0.1 0101 0 1111 0 ... rd:4 ........ \
+ &ri imm=%neg12_26_12_0
+ SUB_rri 1111 0.1 0101 0 .... 0 ... .... ........ @s0_rri_12
+}
+
+# Move Wide
+
+%imm16_26_16_12_0 16:4 26:1 12:3 0:8
+@mov16 .... .... .... .... .... rd:4 .... .... \
+ &ri imm=%imm16_26_16_12_0
+
+MOVW 1111 0.10 0100 .... 0 ... .... ........ @mov16
+MOVT 1111 0.10 1100 .... 0 ... .... ........ @mov16
+
+# Saturate, bitfield
+
+@sat .... .... .. sh:1 . rn:4 . ... rd:4 .. . satimm:5 \
+ &sat imm=%imm5_12_6
+@sat16 .... .... .. . . rn:4 . ... rd:4 .. . satimm:5 \
+ &sat sh=0 imm=0
+
+{
+ SSAT16 1111 0011 001 0 .... 0 000 .... 00 0 ..... @sat16
+ SSAT 1111 0011 00. 0 .... 0 ... .... .. 0 ..... @sat
+}
+{
+ USAT16 1111 0011 101 0 .... 0 000 .... 00 0 ..... @sat16
+ USAT 1111 0011 10. 0 .... 0 ... .... .. 0 ..... @sat
+}
+
+@bfx .... .... ... . rn:4 . ... rd:4 .. . widthm1:5 \
+ &bfx lsb=%imm5_12_6
+@bfi .... .... ... . rn:4 . ... rd:4 .. . msb:5 \
+ &bfi lsb=%imm5_12_6
+
+SBFX 1111 0011 010 0 .... 0 ... .... ..0..... @bfx
+UBFX 1111 0011 110 0 .... 0 ... .... ..0..... @bfx
+
+# bfc is bfi w/ rn=15
+BFCI 1111 0011 011 0 .... 0 ... .... ..0..... @bfi
+
+# Multiply and multiply accumulate
+
+@s0_rnadm .... .... .... rn:4 ra:4 rd:4 .... rm:4 &s_rrrr s=0
+@s0_rn0dm .... .... .... rn:4 .... rd:4 .... rm:4 &s_rrrr ra=0 s=0
+@rnadm .... .... .... rn:4 ra:4 rd:4 .... rm:4 &rrrr
+@rn0dm .... .... .... rn:4 .... rd:4 .... rm:4 &rrrr ra=0
+@rndm .... .... .... rn:4 .... rd:4 .... rm:4 &rrr
+@rdm .... .... .... .... .... rd:4 .... rm:4 &rr
+
+{
+ MUL 1111 1011 0000 .... 1111 .... 0000 .... @s0_rn0dm
+ MLA 1111 1011 0000 .... .... .... 0000 .... @s0_rnadm
+}
+MLS 1111 1011 0000 .... .... .... 0001 .... @rnadm
+SMULL 1111 1011 1000 .... .... .... 0000 .... @s0_rnadm
+UMULL 1111 1011 1010 .... .... .... 0000 .... @s0_rnadm
+SMLAL 1111 1011 1100 .... .... .... 0000 .... @s0_rnadm
+UMLAL 1111 1011 1110 .... .... .... 0000 .... @s0_rnadm
+UMAAL 1111 1011 1110 .... .... .... 0110 .... @rnadm
+{
+ SMULWB 1111 1011 0011 .... 1111 .... 0000 .... @rn0dm
+ SMLAWB 1111 1011 0011 .... .... .... 0000 .... @rnadm
+}
+{
+ SMULWT 1111 1011 0011 .... 1111 .... 0001 .... @rn0dm
+ SMLAWT 1111 1011 0011 .... .... .... 0001 .... @rnadm
+}
+{
+ SMULBB 1111 1011 0001 .... 1111 .... 0000 .... @rn0dm
+ SMLABB 1111 1011 0001 .... .... .... 0000 .... @rnadm
+}
+{
+ SMULBT 1111 1011 0001 .... 1111 .... 0001 .... @rn0dm
+ SMLABT 1111 1011 0001 .... .... .... 0001 .... @rnadm
+}
+{
+ SMULTB 1111 1011 0001 .... 1111 .... 0010 .... @rn0dm
+ SMLATB 1111 1011 0001 .... .... .... 0010 .... @rnadm
+}
+{
+ SMULTT 1111 1011 0001 .... 1111 .... 0011 .... @rn0dm
+ SMLATT 1111 1011 0001 .... .... .... 0011 .... @rnadm
+}
+SMLALBB 1111 1011 1100 .... .... .... 1000 .... @rnadm
+SMLALBT 1111 1011 1100 .... .... .... 1001 .... @rnadm
+SMLALTB 1111 1011 1100 .... .... .... 1010 .... @rnadm
+SMLALTT 1111 1011 1100 .... .... .... 1011 .... @rnadm
+
+# usad8 is usada8 w/ ra=15
+USADA8 1111 1011 0111 .... .... .... 0000 .... @rnadm
+
+SMLAD 1111 1011 0010 .... .... .... 0000 .... @rnadm
+SMLADX 1111 1011 0010 .... .... .... 0001 .... @rnadm
+SMLSD 1111 1011 0100 .... .... .... 0000 .... @rnadm
+SMLSDX 1111 1011 0100 .... .... .... 0001 .... @rnadm
+
+SMLALD 1111 1011 1100 .... .... .... 1100 .... @rnadm
+SMLALDX 1111 1011 1100 .... .... .... 1101 .... @rnadm
+SMLSLD 1111 1011 1101 .... .... .... 1100 .... @rnadm
+SMLSLDX 1111 1011 1101 .... .... .... 1101 .... @rnadm
+
+SMMLA 1111 1011 0101 .... .... .... 0000 .... @rnadm
+SMMLAR 1111 1011 0101 .... .... .... 0001 .... @rnadm
+SMMLS 1111 1011 0110 .... .... .... 0000 .... @rnadm
+SMMLSR 1111 1011 0110 .... .... .... 0001 .... @rnadm
+
+SDIV 1111 1011 1001 .... 1111 .... 1111 .... @rndm
+UDIV 1111 1011 1011 .... 1111 .... 1111 .... @rndm
+
+# Data-processing (two source registers)
+
+QADD 1111 1010 1000 .... 1111 .... 1000 .... @rndm
+QSUB 1111 1010 1000 .... 1111 .... 1010 .... @rndm
+QDADD 1111 1010 1000 .... 1111 .... 1001 .... @rndm
+QDSUB 1111 1010 1000 .... 1111 .... 1011 .... @rndm
+
+CRC32B 1111 1010 1100 .... 1111 .... 1000 .... @rndm
+CRC32H 1111 1010 1100 .... 1111 .... 1001 .... @rndm
+CRC32W 1111 1010 1100 .... 1111 .... 1010 .... @rndm
+CRC32CB 1111 1010 1101 .... 1111 .... 1000 .... @rndm
+CRC32CH 1111 1010 1101 .... 1111 .... 1001 .... @rndm
+CRC32CW 1111 1010 1101 .... 1111 .... 1010 .... @rndm
+
+SEL 1111 1010 1010 .... 1111 .... 1000 .... @rndm
+
+# Note rn != rm is CONSTRAINED UNPREDICTABLE; we choose to ignore rn.
+REV 1111 1010 1001 ---- 1111 .... 1000 .... @rdm
+REV16 1111 1010 1001 ---- 1111 .... 1001 .... @rdm
+RBIT 1111 1010 1001 ---- 1111 .... 1010 .... @rdm
+REVSH 1111 1010 1001 ---- 1111 .... 1011 .... @rdm
+CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
+
+# Branches and miscellaneous control
+
+%msr_sysm 4:1 8:4
+%mrs_sysm 4:1 16:4
+%imm16_16_0 16:4 0:12
+%imm21 26:s1 11:1 13:1 16:6 0:11 !function=times_2
+&ci cond imm
+
+{
+ # Group insn[25:23] = 111, which is cond=111x for the branch below,
+ # or unconditional, which would be illegal for the branch.
+ {
+ # Hints
+ {
+ YIELD 1111 0011 1010 1111 1000 0000 0000 0001
+ WFE 1111 0011 1010 1111 1000 0000 0000 0010
+ WFI 1111 0011 1010 1111 1000 0000 0000 0011
+
+ # TODO: Implement SEV, SEVL; may help SMP performance.
+ # SEV 1111 0011 1010 1111 1000 0000 0000 0100
+ # SEVL 1111 0011 1010 1111 1000 0000 0000 0101
+
+ # The canonical nop ends in 0000 0000, but the whole rest
+ # of the space is "reserved hint, behaves as nop".
+ NOP 1111 0011 1010 1111 1000 0000 ---- ----
+ }
+
+ # If imod == '00' && M == '0' then SEE "Hint instructions", above.
+ CPS 1111 0011 1010 1111 1000 0 imod:2 M:1 A:1 I:1 F:1 mode:5 \
+ &cps
+
+ # Miscellaneous control
+ {
+ CLREX 1111 0011 1011 1111 1000 1111 0010 1111
+ DSB 1111 0011 1011 1111 1000 1111 0100 ----
+ DMB 1111 0011 1011 1111 1000 1111 0101 ----
+ ISB 1111 0011 1011 1111 1000 1111 0110 ----
+ SB 1111 0011 1011 1111 1000 1111 0111 0000
+ }
+
+ # Note that the v7m insn overlaps both the normal and banked insn.
+ {
+ MRS_bank 1111 0011 111 r:1 .... 1000 rd:4 001. 0000 \
+ &mrs_bank sysm=%mrs_sysm
+ MRS_reg 1111 0011 111 r:1 1111 1000 rd:4 0000 0000 &mrs_reg
+ MRS_v7m 1111 0011 111 0 1111 1000 rd:4 sysm:8
+ }
+ {
+ MSR_bank 1111 0011 100 r:1 rn:4 1000 .... 001. 0000 \
+ &msr_bank sysm=%msr_sysm
+ MSR_reg 1111 0011 100 r:1 rn:4 1000 mask:4 0000 0000 &msr_reg
+ MSR_v7m 1111 0011 100 0 rn:4 1000 mask:2 00 sysm:8
+ }
+ BXJ 1111 0011 1100 rm:4 1000 1111 0000 0000 &r
+ {
+ # At v6T2, this is the T5 encoding of SUBS PC, LR, #IMM, and works as for
+ # every other encoding of SUBS. With v7VE, IMM=0 is redefined as ERET.
+ # The distinction between the two only matters for Hyp mode.
+ ERET 1111 0011 1101 1110 1000 1111 0000 0000
+ SUB_rri 1111 0011 1101 1110 1000 1111 imm:8 \
+ &s_rri_rot rot=0 s=1 rd=15 rn=14
+ }
+ SMC 1111 0111 1111 imm:4 1000 0000 0000 0000 &i
+ HVC 1111 0111 1110 .... 1000 .... .... .... \
+ &i imm=%imm16_16_0
+ UDF 1111 0111 1111 ---- 1010 ---- ---- ----
+ }
+ B_cond_thumb 1111 0. cond:4 ...... 10.0 ............ &ci imm=%imm21
+}
+
+# Load/store (register, immediate, literal)
+
+@ldst_rr .... .... .... rn:4 rt:4 ...... shimm:2 rm:4 \
+ &ldst_rr p=1 w=0 u=1 shtype=0
+@ldst_ri_idx .... .... .... rn:4 rt:4 . p:1 u:1 . imm:8 \
+ &ldst_ri w=1
+@ldst_ri_neg .... .... .... rn:4 rt:4 .... imm:8 \
+ &ldst_ri p=1 w=0 u=0
+@ldst_ri_unp .... .... .... rn:4 rt:4 .... imm:8 \
+ &ldst_ri p=1 w=0 u=1
+@ldst_ri_pos .... .... .... rn:4 rt:4 imm:12 \
+ &ldst_ri p=1 w=0 u=1
+@ldst_ri_lit .... .... u:1 ... .... rt:4 imm:12 \
+ &ldst_ri p=1 w=0 rn=15
+
+STRB_rr 1111 1000 0000 .... .... 000000 .. .... @ldst_rr
+STRB_ri 1111 1000 0000 .... .... 1..1 ........ @ldst_ri_idx
+STRB_ri 1111 1000 0000 .... .... 1100 ........ @ldst_ri_neg
+STRBT_ri 1111 1000 0000 .... .... 1110 ........ @ldst_ri_unp
+STRB_ri 1111 1000 1000 .... .... ............ @ldst_ri_pos
+
+STRH_rr 1111 1000 0010 .... .... 000000 .. .... @ldst_rr
+STRH_ri 1111 1000 0010 .... .... 1..1 ........ @ldst_ri_idx
+STRH_ri 1111 1000 0010 .... .... 1100 ........ @ldst_ri_neg
+STRHT_ri 1111 1000 0010 .... .... 1110 ........ @ldst_ri_unp
+STRH_ri 1111 1000 1010 .... .... ............ @ldst_ri_pos
+
+STR_rr 1111 1000 0100 .... .... 000000 .. .... @ldst_rr
+STR_ri 1111 1000 0100 .... .... 1..1 ........ @ldst_ri_idx
+STR_ri 1111 1000 0100 .... .... 1100 ........ @ldst_ri_neg
+STRT_ri 1111 1000 0100 .... .... 1110 ........ @ldst_ri_unp
+STR_ri 1111 1000 1100 .... .... ............ @ldst_ri_pos
+
+# Note that Load, unsigned (literal) overlaps all other load encodings.
+{
+ {
+ NOP 1111 1000 -001 1111 1111 ------------ # PLD
+ LDRB_ri 1111 1000 .001 1111 .... ............ @ldst_ri_lit
+ }
+ {
+ NOP 1111 1000 1001 ---- 1111 ------------ # PLD
+ LDRB_ri 1111 1000 1001 .... .... ............ @ldst_ri_pos
+ }
+ LDRB_ri 1111 1000 0001 .... .... 1..1 ........ @ldst_ri_idx
+ {
+ NOP 1111 1000 0001 ---- 1111 1100 -------- # PLD
+ LDRB_ri 1111 1000 0001 .... .... 1100 ........ @ldst_ri_neg
+ }
+ LDRBT_ri 1111 1000 0001 .... .... 1110 ........ @ldst_ri_unp
+ {
+ NOP 1111 1000 0001 ---- 1111 000000 -- ---- # PLD
+ LDRB_rr 1111 1000 0001 .... .... 000000 .. .... @ldst_rr
+ }
+}
+{
+ {
+ NOP 1111 1000 -011 1111 1111 ------------ # PLD
+ LDRH_ri 1111 1000 .011 1111 .... ............ @ldst_ri_lit
+ }
+ {
+ NOP 1111 1000 1011 ---- 1111 ------------ # PLDW
+ LDRH_ri 1111 1000 1011 .... .... ............ @ldst_ri_pos
+ }
+ LDRH_ri 1111 1000 0011 .... .... 1..1 ........ @ldst_ri_idx
+ {
+ NOP 1111 1000 0011 ---- 1111 1100 -------- # PLDW
+ LDRH_ri 1111 1000 0011 .... .... 1100 ........ @ldst_ri_neg
+ }
+ LDRHT_ri 1111 1000 0011 .... .... 1110 ........ @ldst_ri_unp
+ {
+ NOP 1111 1000 0011 ---- 1111 000000 -- ---- # PLDW
+ LDRH_rr 1111 1000 0011 .... .... 000000 .. .... @ldst_rr
+ }
+}
+{
+ LDR_ri 1111 1000 .101 1111 .... ............ @ldst_ri_lit
+ LDR_ri 1111 1000 1101 .... .... ............ @ldst_ri_pos
+ LDR_ri 1111 1000 0101 .... .... 1..1 ........ @ldst_ri_idx
+ LDR_ri 1111 1000 0101 .... .... 1100 ........ @ldst_ri_neg
+ LDRT_ri 1111 1000 0101 .... .... 1110 ........ @ldst_ri_unp
+ LDR_rr 1111 1000 0101 .... .... 000000 .. .... @ldst_rr
+}
+# NOPs here are PLI.
+{
+ {
+ NOP 1111 1001 -001 1111 1111 ------------
+ LDRSB_ri 1111 1001 .001 1111 .... ............ @ldst_ri_lit
+ }
+ {
+ NOP 1111 1001 1001 ---- 1111 ------------
+ LDRSB_ri 1111 1001 1001 .... .... ............ @ldst_ri_pos
+ }
+ LDRSB_ri 1111 1001 0001 .... .... 1..1 ........ @ldst_ri_idx
+ {
+ NOP 1111 1001 0001 ---- 1111 1100 --------
+ LDRSB_ri 1111 1001 0001 .... .... 1100 ........ @ldst_ri_neg
+ }
+ LDRSBT_ri 1111 1001 0001 .... .... 1110 ........ @ldst_ri_unp
+ {
+ NOP 1111 1001 0001 ---- 1111 000000 -- ----
+ LDRSB_rr 1111 1001 0001 .... .... 000000 .. .... @ldst_rr
+ }
+}
+# NOPs here are unallocated memory hints, treated as NOP.
+{
+ {
+ NOP 1111 1001 -011 1111 1111 ------------
+ LDRSH_ri 1111 1001 .011 1111 .... ............ @ldst_ri_lit
+ }
+ {
+ NOP 1111 1001 1011 ---- 1111 ------------
+ LDRSH_ri 1111 1001 1011 .... .... ............ @ldst_ri_pos
+ }
+ LDRSH_ri 1111 1001 0011 .... .... 1..1 ........ @ldst_ri_idx
+ {
+ NOP 1111 1001 0011 ---- 1111 1100 --------
+ LDRSH_ri 1111 1001 0011 .... .... 1100 ........ @ldst_ri_neg
+ }
+ LDRSHT_ri 1111 1001 0011 .... .... 1110 ........ @ldst_ri_unp
+ {
+ NOP 1111 1001 0011 ---- 1111 000000 -- ----
+ LDRSH_rr 1111 1001 0011 .... .... 000000 .. .... @ldst_rr
+ }
+}
+
+%imm8x4 0:8 !function=times_4
+&ldst_ri2 p w u rn rt rt2 imm
+@ldstd_ri8 .... .... u:1 ... rn:4 rt:4 rt2:4 ........ \
+ &ldst_ri2 imm=%imm8x4
+
+STRD_ri_t32 1110 1000 .110 .... .... .... ........ @ldstd_ri8 w=1 p=0
+LDRD_ri_t32 1110 1000 .111 .... .... .... ........ @ldstd_ri8 w=1 p=0
+
+STRD_ri_t32 1110 1001 .100 .... .... .... ........ @ldstd_ri8 w=0 p=1
+LDRD_ri_t32 1110 1001 .101 .... .... .... ........ @ldstd_ri8 w=0 p=1
+
+STRD_ri_t32 1110 1001 .110 .... .... .... ........ @ldstd_ri8 w=1 p=1
+{
+ SG 1110 1001 0111 1111 1110 1001 01111111
+ LDRD_ri_t32 1110 1001 .111 .... .... .... ........ @ldstd_ri8 w=1 p=1
+}
+
+# Load/Store Exclusive, Load-Acquire/Store-Release, and Table Branch
+
+@strex_i .... .... .... rn:4 rt:4 rd:4 .... .... \
+ &strex rt2=15 imm=%imm8x4
+@strex_0 .... .... .... rn:4 rt:4 .... .... rd:4 \
+ &strex rt2=15 imm=0
+@strex_d .... .... .... rn:4 rt:4 rt2:4 .... rd:4 \
+ &strex imm=0
+
+@ldrex_i .... .... .... rn:4 rt:4 .... .... .... \
+ &ldrex rt2=15 imm=%imm8x4
+@ldrex_0 .... .... .... rn:4 rt:4 .... .... .... \
+ &ldrex rt2=15 imm=0
+@ldrex_d .... .... .... rn:4 rt:4 rt2:4 .... .... \
+ &ldrex imm=0
+
+{
+ TT 1110 1000 0100 rn:4 1111 rd:4 A:1 T:1 000000
+ STREX 1110 1000 0100 .... .... .... .... .... @strex_i
+}
+STREXB 1110 1000 1100 .... .... 1111 0100 .... @strex_0
+STREXH 1110 1000 1100 .... .... 1111 0101 .... @strex_0
+STREXD_t32 1110 1000 1100 .... .... .... 0111 .... @strex_d
+
+STLEX 1110 1000 1100 .... .... 1111 1110 .... @strex_0
+STLEXB 1110 1000 1100 .... .... 1111 1100 .... @strex_0
+STLEXH 1110 1000 1100 .... .... 1111 1101 .... @strex_0
+STLEXD_t32 1110 1000 1100 .... .... .... 1111 .... @strex_d
+
+STL 1110 1000 1100 .... .... 1111 1010 1111 @ldrex_0
+STLB 1110 1000 1100 .... .... 1111 1000 1111 @ldrex_0
+STLH 1110 1000 1100 .... .... 1111 1001 1111 @ldrex_0
+
+LDREX 1110 1000 0101 .... .... 1111 .... .... @ldrex_i
+LDREXB 1110 1000 1101 .... .... 1111 0100 1111 @ldrex_0
+LDREXH 1110 1000 1101 .... .... 1111 0101 1111 @ldrex_0
+LDREXD_t32 1110 1000 1101 .... .... .... 0111 1111 @ldrex_d
+
+LDAEX 1110 1000 1101 .... .... 1111 1110 1111 @ldrex_0
+LDAEXB 1110 1000 1101 .... .... 1111 1100 1111 @ldrex_0
+LDAEXH 1110 1000 1101 .... .... 1111 1101 1111 @ldrex_0
+LDAEXD_t32 1110 1000 1101 .... .... .... 1111 1111 @ldrex_d
+
+LDA 1110 1000 1101 .... .... 1111 1010 1111 @ldrex_0
+LDAB 1110 1000 1101 .... .... 1111 1000 1111 @ldrex_0
+LDAH 1110 1000 1101 .... .... 1111 1001 1111 @ldrex_0
+
+&tbranch rn rm
+@tbranch .... .... .... rn:4 .... .... .... rm:4 &tbranch
+
+TBB 1110 1000 1101 .... 1111 0000 0000 .... @tbranch
+TBH 1110 1000 1101 .... 1111 0000 0001 .... @tbranch
+
+# Parallel addition and subtraction
+
+SADD8 1111 1010 1000 .... 1111 .... 0000 .... @rndm
+QADD8 1111 1010 1000 .... 1111 .... 0001 .... @rndm
+SHADD8 1111 1010 1000 .... 1111 .... 0010 .... @rndm
+UADD8 1111 1010 1000 .... 1111 .... 0100 .... @rndm
+UQADD8 1111 1010 1000 .... 1111 .... 0101 .... @rndm
+UHADD8 1111 1010 1000 .... 1111 .... 0110 .... @rndm
+
+SADD16 1111 1010 1001 .... 1111 .... 0000 .... @rndm
+QADD16 1111 1010 1001 .... 1111 .... 0001 .... @rndm
+SHADD16 1111 1010 1001 .... 1111 .... 0010 .... @rndm
+UADD16 1111 1010 1001 .... 1111 .... 0100 .... @rndm
+UQADD16 1111 1010 1001 .... 1111 .... 0101 .... @rndm
+UHADD16 1111 1010 1001 .... 1111 .... 0110 .... @rndm
+
+SASX 1111 1010 1010 .... 1111 .... 0000 .... @rndm
+QASX 1111 1010 1010 .... 1111 .... 0001 .... @rndm
+SHASX 1111 1010 1010 .... 1111 .... 0010 .... @rndm
+UASX 1111 1010 1010 .... 1111 .... 0100 .... @rndm
+UQASX 1111 1010 1010 .... 1111 .... 0101 .... @rndm
+UHASX 1111 1010 1010 .... 1111 .... 0110 .... @rndm
+
+SSUB8 1111 1010 1100 .... 1111 .... 0000 .... @rndm
+QSUB8 1111 1010 1100 .... 1111 .... 0001 .... @rndm
+SHSUB8 1111 1010 1100 .... 1111 .... 0010 .... @rndm
+USUB8 1111 1010 1100 .... 1111 .... 0100 .... @rndm
+UQSUB8 1111 1010 1100 .... 1111 .... 0101 .... @rndm
+UHSUB8 1111 1010 1100 .... 1111 .... 0110 .... @rndm
+
+SSUB16 1111 1010 1101 .... 1111 .... 0000 .... @rndm
+QSUB16 1111 1010 1101 .... 1111 .... 0001 .... @rndm
+SHSUB16 1111 1010 1101 .... 1111 .... 0010 .... @rndm
+USUB16 1111 1010 1101 .... 1111 .... 0100 .... @rndm
+UQSUB16 1111 1010 1101 .... 1111 .... 0101 .... @rndm
+UHSUB16 1111 1010 1101 .... 1111 .... 0110 .... @rndm
+
+SSAX 1111 1010 1110 .... 1111 .... 0000 .... @rndm
+QSAX 1111 1010 1110 .... 1111 .... 0001 .... @rndm
+SHSAX 1111 1010 1110 .... 1111 .... 0010 .... @rndm
+USAX 1111 1010 1110 .... 1111 .... 0100 .... @rndm
+UQSAX 1111 1010 1110 .... 1111 .... 0101 .... @rndm
+UHSAX 1111 1010 1110 .... 1111 .... 0110 .... @rndm
+
+# Register extends
+
+@rrr_rot .... .... .... rn:4 .... rd:4 .. rot:2 rm:4 &rrr_rot
+
+SXTAH 1111 1010 0000 .... 1111 .... 10.. .... @rrr_rot
+UXTAH 1111 1010 0001 .... 1111 .... 10.. .... @rrr_rot
+SXTAB16 1111 1010 0010 .... 1111 .... 10.. .... @rrr_rot
+UXTAB16 1111 1010 0011 .... 1111 .... 10.. .... @rrr_rot
+SXTAB 1111 1010 0100 .... 1111 .... 10.. .... @rrr_rot
+UXTAB 1111 1010 0101 .... 1111 .... 10.. .... @rrr_rot
+
+# Load/store multiple
+
+@ldstm .... .... .. w:1 . rn:4 list:16 &ldst_block u=0
+
+STM_t32 1110 1000 10.0 .... ................ @ldstm i=1 b=0
+STM_t32 1110 1001 00.0 .... ................ @ldstm i=0 b=1
+LDM_t32 1110 1000 10.1 .... ................ @ldstm i=1 b=0
+LDM_t32 1110 1001 00.1 .... ................ @ldstm i=0 b=1
+
+&rfe !extern rn w pu
+@rfe .... .... .. w:1 . rn:4 ................ &rfe
+
+RFE 1110 1000 00.1 .... 1100000000000000 @rfe pu=2
+RFE 1110 1001 10.1 .... 1100000000000000 @rfe pu=1
+
+&srs !extern mode w pu
+@srs .... .... .. w:1 . .... ........... mode:5 &srs
+
+SRS 1110 1000 00.0 1101 1100 0000 000. .... @srs pu=2
+SRS 1110 1001 10.0 1101 1100 0000 000. .... @srs pu=1
+
+# Branches
+
+%imm24 26:s1 13:1 11:1 16:10 0:11 !function=t32_branch24
+@branch24 ................................ &i imm=%imm24
+
+B 1111 0. .......... 10.1 ............ @branch24
+BL 1111 0. .......... 11.1 ............ @branch24
+BLX_i 1111 0. .......... 11.0 ............ @branch24
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 6fd0b779d3..2d6cd09634 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -85,7 +85,7 @@ typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64);
typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
-typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, TCGMemOp);
+typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp);
/* initialize TCG globals. */
void a64_translate_init(void)
@@ -338,6 +338,13 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
}
}
+void unallocated_encoding(DisasContext *s)
+{
+ /* Unallocated and reserved encodings are uncategorized */
+ gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(),
+ default_exception_el(s));
+}
+
static void init_tmp_a64_array(DisasContext *s)
{
#ifdef CONFIG_DEBUG_TCG
@@ -433,7 +440,7 @@ TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
* Dn, Sn, Hn or Bn).
* (Note that this is not the same mapping as for A32; see cpu.h)
*/
-static inline int fp_reg_offset(DisasContext *s, int regno, TCGMemOp size)
+static inline int fp_reg_offset(DisasContext *s, int regno, MemOp size)
{
return vec_reg_offset(s, regno, 0, size);
}
@@ -849,7 +856,7 @@ static void do_gpr_ld_memidx(DisasContext *s,
bool iss_valid, unsigned int iss_srt,
bool iss_sf, bool iss_ar)
{
- TCGMemOp memop = s->be_data + size;
+ MemOp memop = s->be_data + size;
g_assert(size <= 3);
@@ -926,7 +933,7 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
TCGv_i64 tmphi;
if (size < 4) {
- TCGMemOp memop = s->be_data + size;
+ MemOp memop = s->be_data + size;
tmphi = tcg_const_i64(0);
tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
} else {
@@ -967,7 +974,7 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
/* Get value of an element within a vector register */
static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
- int element, TCGMemOp memop)
+ int element, MemOp memop)
{
int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE);
switch (memop) {
@@ -999,7 +1006,7 @@ static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
}
static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
- int element, TCGMemOp memop)
+ int element, MemOp memop)
{
int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE);
switch (memop) {
@@ -1026,7 +1033,7 @@ static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
/* Set value of an element within a vector register */
static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
- int element, TCGMemOp memop)
+ int element, MemOp memop)
{
int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE);
switch (memop) {
@@ -1048,7 +1055,7 @@ static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
}
static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src,
- int destidx, int element, TCGMemOp memop)
+ int destidx, int element, MemOp memop)
{
int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE);
switch (memop) {
@@ -1068,7 +1075,7 @@ static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src,
/* Store from vector register to memory */
static void do_vec_st(DisasContext *s, int srcidx, int element,
- TCGv_i64 tcg_addr, int size, TCGMemOp endian)
+ TCGv_i64 tcg_addr, int size, MemOp endian)
{
TCGv_i64 tcg_tmp = tcg_temp_new_i64();
@@ -1080,7 +1087,7 @@ static void do_vec_st(DisasContext *s, int srcidx, int element,
/* Load from memory to vector register */
static void do_vec_ld(DisasContext *s, int destidx, int element,
- TCGv_i64 tcg_addr, int size, TCGMemOp endian)
+ TCGv_i64 tcg_addr, int size, MemOp endian)
{
TCGv_i64 tcg_tmp = tcg_temp_new_i64();
@@ -1707,6 +1714,12 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
tcg_temp_free_ptr(tmpptr);
tcg_temp_free_i32(tcg_syn);
tcg_temp_free_i32(tcg_isread);
+ } else if (ri->type & ARM_CP_RAISES_EXC) {
+ /*
+ * The readfn or writefn might raise an exception;
+ * synchronize the CPU state in case it does.
+ */
+ gen_a64_set_pc_im(s->pc_curr);
}
/* Handle special cases first */
@@ -2176,7 +2189,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
TCGv_i64 addr, int size, bool is_pair)
{
int idx = get_mem_index(s);
- TCGMemOp memop = s->be_data;
+ MemOp memop = s->be_data;
g_assert(size <= 3);
if (is_pair) {
@@ -3262,7 +3275,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
bool is_postidx = extract32(insn, 23, 1);
bool is_q = extract32(insn, 30, 1);
TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
- TCGMemOp endian = s->be_data;
+ MemOp endian = s->be_data;
int ebytes; /* bytes per element */
int elements; /* elements per vector */
@@ -5431,7 +5444,7 @@ static void disas_fp_csel(DisasContext *s, uint32_t insn)
unsigned int mos, type, rm, cond, rn, rd;
TCGv_i64 t_true, t_false, t_zero;
DisasCompare64 c;
- TCGMemOp sz;
+ MemOp sz;
mos = extract32(insn, 29, 3);
type = extract32(insn, 22, 2);
@@ -6243,7 +6256,7 @@ static void disas_fp_imm(DisasContext *s, uint32_t insn)
int mos = extract32(insn, 29, 3);
uint64_t imm;
TCGv_i64 tcg_res;
- TCGMemOp sz;
+ MemOp sz;
if (mos || imm5) {
unallocated_encoding(s);
@@ -7006,7 +7019,7 @@ static TCGv_i32 do_reduction_op(DisasContext *s, int fpopcode, int rn,
{
if (esize == size) {
int element;
- TCGMemOp msize = esize == 16 ? MO_16 : MO_32;
+ MemOp msize = esize == 16 ? MO_16 : MO_32;
TCGv_i32 tcg_elem;
/* We should have one register left here */
@@ -7998,7 +8011,7 @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q,
int shift = (2 * esize) - immhb;
int elements = is_scalar ? 1 : (64 / esize);
bool round = extract32(opcode, 0, 1);
- TCGMemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN);
+ MemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN);
TCGv_i64 tcg_rn, tcg_rd, tcg_round;
TCGv_i32 tcg_rd_narrowed;
TCGv_i64 tcg_final;
@@ -8157,7 +8170,7 @@ static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q,
}
};
NeonGenTwoOpEnvFn *genfn = fns[src_unsigned][dst_unsigned][size];
- TCGMemOp memop = scalar ? size : MO_32;
+ MemOp memop = scalar ? size : MO_32;
int maxpass = scalar ? 1 : is_q ? 4 : 2;
for (pass = 0; pass < maxpass; pass++) {
@@ -8201,7 +8214,7 @@ static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn,
TCGv_ptr tcg_fpst = get_fpstatus_ptr(size == MO_16);
TCGv_i32 tcg_shift = NULL;
- TCGMemOp mop = size | (is_signed ? MO_SIGN : 0);
+ MemOp mop = size | (is_signed ? MO_SIGN : 0);
int pass;
if (fracbits || size == MO_64) {
@@ -9980,7 +9993,7 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u,
int dsize = is_q ? 128 : 64;
int esize = 8 << size;
int elements = dsize/esize;
- TCGMemOp memop = size | (is_u ? 0 : MO_SIGN);
+ MemOp memop = size | (is_u ? 0 : MO_SIGN);
TCGv_i64 tcg_rn = new_tmp_a64(s);
TCGv_i64 tcg_rd = new_tmp_a64(s);
TCGv_i64 tcg_round;
@@ -10323,7 +10336,7 @@ static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size,
TCGv_i64 tcg_op1 = tcg_temp_new_i64();
TCGv_i64 tcg_op2 = tcg_temp_new_i64();
TCGv_i64 tcg_passres;
- TCGMemOp memop = MO_32 | (is_u ? 0 : MO_SIGN);
+ MemOp memop = MO_32 | (is_u ? 0 : MO_SIGN);
int elt = pass + is_q * 2;
@@ -11803,7 +11816,7 @@ static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u,
if (size == 2) {
/* 32 + 32 -> 64 op */
- TCGMemOp memop = size + (u ? 0 : MO_SIGN);
+ MemOp memop = size + (u ? 0 : MO_SIGN);
for (pass = 0; pass < maxpass; pass++) {
TCGv_i64 tcg_op1 = tcg_temp_new_i64();
@@ -12825,7 +12838,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn)
switch (is_fp) {
case 1: /* normal fp */
- /* convert insn encoded size to TCGMemOp size */
+ /* convert insn encoded size to MemOp size */
switch (size) {
case 0: /* half-precision */
size = MO_16;
@@ -12873,7 +12886,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn)
return;
}
- /* Given TCGMemOp size, adjust register and indexing. */
+ /* Given MemOp size, adjust register and indexing. */
switch (size) {
case MO_16:
index = h << 2 | l << 1 | m;
@@ -13170,7 +13183,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn)
TCGv_i64 tcg_res[2];
int pass;
bool satop = extract32(opcode, 0, 1);
- TCGMemOp memop = MO_32;
+ MemOp memop = MO_32;
if (satop || !u) {
memop |= MO_SIGN;
diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h
index 12ad8ac6ed..4c2c91ae1b 100644
--- a/target/arm/translate-a64.h
+++ b/target/arm/translate-a64.h
@@ -18,6 +18,8 @@
#ifndef TARGET_ARM_TRANSLATE_A64_H
#define TARGET_ARM_TRANSLATE_A64_H
+void unallocated_encoding(DisasContext *s);
+
#define unsupported_encoding(s, insn) \
do { \
qemu_log_mask(LOG_UNIMP, \
@@ -62,7 +64,7 @@ static inline void assert_fp_access_checked(DisasContext *s)
* the FP/vector register Qn.
*/
static inline int vec_reg_offset(DisasContext *s, int regno,
- int element, TCGMemOp size)
+ int element, MemOp size)
{
int element_size = 1 << size;
int offs = element * element_size;
diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c
index fa068b0e47..5d7edd0907 100644
--- a/target/arm/translate-sve.c
+++ b/target/arm/translate-sve.c
@@ -4567,7 +4567,7 @@ static bool trans_STR_pri(DisasContext *s, arg_rri *a)
*/
/* The memory mode of the dtype. */
-static const TCGMemOp dtype_mop[16] = {
+static const MemOp dtype_mop[16] = {
MO_UB, MO_UB, MO_UB, MO_UB,
MO_SL, MO_UW, MO_UW, MO_UW,
MO_SW, MO_SW, MO_UL, MO_UL,
diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c
index 3e8ea80493..9ae980bef6 100644
--- a/target/arm/translate-vfp.inc.c
+++ b/target/arm/translate-vfp.inc.c
@@ -880,8 +880,10 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
/* gpreg to fpreg */
tmp = load_reg(s, a->rt);
neon_store_reg32(tmp, a->vm);
+ tcg_temp_free_i32(tmp);
tmp = load_reg(s, a->rt2);
neon_store_reg32(tmp, a->vm + 1);
+ tcg_temp_free_i32(tmp);
}
return true;
diff --git a/target/arm/translate.c b/target/arm/translate.c
index cbe19b7a62..34bb280e3d 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -114,7 +114,7 @@ typedef enum ISSInfo {
} ISSInfo;
/* Save the syndrome information for a Data Abort */
-static void disas_set_da_iss(DisasContext *s, TCGMemOp memop, ISSInfo issinfo)
+static void disas_set_da_iss(DisasContext *s, MemOp memop, ISSInfo issinfo)
{
uint32_t syn;
int sas = memop & MO_SIZE;
@@ -355,7 +355,7 @@ static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
}
/* Byteswap each halfword. */
-static void gen_rev16(TCGv_i32 var)
+static void gen_rev16(TCGv_i32 dest, TCGv_i32 var)
{
TCGv_i32 tmp = tcg_temp_new_i32();
TCGv_i32 mask = tcg_const_i32(0x00ff00ff);
@@ -363,17 +363,17 @@ static void gen_rev16(TCGv_i32 var)
tcg_gen_and_i32(tmp, tmp, mask);
tcg_gen_and_i32(var, var, mask);
tcg_gen_shli_i32(var, var, 8);
- tcg_gen_or_i32(var, var, tmp);
+ tcg_gen_or_i32(dest, var, tmp);
tcg_temp_free_i32(mask);
tcg_temp_free_i32(tmp);
}
/* Byteswap low halfword and sign extend. */
-static void gen_revsh(TCGv_i32 var)
+static void gen_revsh(TCGv_i32 dest, TCGv_i32 var)
{
tcg_gen_ext16u_i32(var, var);
tcg_gen_bswap16_i32(var, var);
- tcg_gen_ext16s_i32(var, var);
+ tcg_gen_ext16s_i32(dest, var);
}
/* 32x32->64 multiply. Marks inputs as dead. */
@@ -426,7 +426,7 @@ static void gen_swap_half(TCGv_i32 var)
t0 = (t0 + t1) ^ tmp;
*/
-static void gen_add16(TCGv_i32 t0, TCGv_i32 t1)
+static void gen_add16(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
{
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_xor_i32(tmp, t0, t1);
@@ -434,15 +434,8 @@ static void gen_add16(TCGv_i32 t0, TCGv_i32 t1)
tcg_gen_andi_i32(t0, t0, ~0x8000);
tcg_gen_andi_i32(t1, t1, ~0x8000);
tcg_gen_add_i32(t0, t0, t1);
- tcg_gen_xor_i32(t0, t0, tmp);
+ tcg_gen_xor_i32(dest, t0, tmp);
tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(t1);
-}
-
-/* Set CF to the top bit of var. */
-static void gen_set_CF_bit31(TCGv_i32 var)
-{
- tcg_gen_shri_i32(cpu_CF, var, 31);
}
/* Set N and Z flags from var. */
@@ -452,13 +445,6 @@ static inline void gen_logic_CC(TCGv_i32 var)
tcg_gen_mov_i32(cpu_ZF, var);
}
-/* T0 += T1 + CF. */
-static void gen_adc(TCGv_i32 t0, TCGv_i32 t1)
-{
- tcg_gen_add_i32(t0, t0, t1);
- tcg_gen_add_i32(t0, t0, cpu_CF);
-}
-
/* dest = T0 + T1 + CF. */
static void gen_add_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
{
@@ -654,99 +640,6 @@ static inline void gen_arm_shift_reg(TCGv_i32 var, int shiftop,
tcg_temp_free_i32(shift);
}
-#define PAS_OP(pfx) \
- switch (op2) { \
- case 0: gen_pas_helper(glue(pfx,add16)); break; \
- case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
- case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
- case 3: gen_pas_helper(glue(pfx,sub16)); break; \
- case 4: gen_pas_helper(glue(pfx,add8)); break; \
- case 7: gen_pas_helper(glue(pfx,sub8)); break; \
- }
-static void gen_arm_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
-{
- TCGv_ptr tmp;
-
- switch (op1) {
-#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
- case 1:
- tmp = tcg_temp_new_ptr();
- tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
- PAS_OP(s)
- tcg_temp_free_ptr(tmp);
- break;
- case 5:
- tmp = tcg_temp_new_ptr();
- tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
- PAS_OP(u)
- tcg_temp_free_ptr(tmp);
- break;
-#undef gen_pas_helper
-#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
- case 2:
- PAS_OP(q);
- break;
- case 3:
- PAS_OP(sh);
- break;
- case 6:
- PAS_OP(uq);
- break;
- case 7:
- PAS_OP(uh);
- break;
-#undef gen_pas_helper
- }
-}
-#undef PAS_OP
-
-/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */
-#define PAS_OP(pfx) \
- switch (op1) { \
- case 0: gen_pas_helper(glue(pfx,add8)); break; \
- case 1: gen_pas_helper(glue(pfx,add16)); break; \
- case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
- case 4: gen_pas_helper(glue(pfx,sub8)); break; \
- case 5: gen_pas_helper(glue(pfx,sub16)); break; \
- case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
- }
-static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
-{
- TCGv_ptr tmp;
-
- switch (op2) {
-#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
- case 0:
- tmp = tcg_temp_new_ptr();
- tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
- PAS_OP(s)
- tcg_temp_free_ptr(tmp);
- break;
- case 4:
- tmp = tcg_temp_new_ptr();
- tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
- PAS_OP(u)
- tcg_temp_free_ptr(tmp);
- break;
-#undef gen_pas_helper
-#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
- case 1:
- PAS_OP(q);
- break;
- case 2:
- PAS_OP(sh);
- break;
- case 5:
- PAS_OP(uq);
- break;
- case 6:
- PAS_OP(uh);
- break;
-#undef gen_pas_helper
- }
-}
-#undef PAS_OP
-
/*
* Generate a conditional based on ARM condition code cc.
* This is common between ARM and Aarch64 targets.
@@ -857,25 +750,6 @@ void arm_gen_test_cc(int cc, TCGLabel *label)
arm_free_cc(&cmp);
}
-static const uint8_t table_logic_cc[16] = {
- 1, /* and */
- 1, /* xor */
- 0, /* sub */
- 0, /* rsb */
- 0, /* add */
- 0, /* adc */
- 0, /* sbc */
- 0, /* rsc */
- 1, /* andl */
- 1, /* xorl */
- 0, /* cmp */
- 0, /* cmn */
- 1, /* orr */
- 1, /* mov */
- 1, /* bic */
- 1, /* mvn */
-};
-
static inline void gen_set_condexec(DisasContext *s)
{
if (s->condexec_mask) {
@@ -891,21 +765,6 @@ static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
tcg_gen_movi_i32(cpu_R[15], val);
}
-/* Set PC and Thumb state from an immediate address. */
-static inline void gen_bx_im(DisasContext *s, uint32_t addr)
-{
- TCGv_i32 tmp;
-
- s->base.is_jmp = DISAS_JUMP;
- if (s->thumb != (addr & 1)) {
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, addr & 1);
- tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, thumb));
- tcg_temp_free_i32(tmp);
- }
- tcg_gen_movi_i32(cpu_R[15], addr & ~1);
-}
-
/* Set PC and Thumb state from var. var is marked as dead. */
static inline void gen_bx(DisasContext *s, TCGv_i32 var)
{
@@ -915,10 +774,27 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
store_cpu_field(var, thumb);
}
-/* Set PC and Thumb state from var. var is marked as dead.
+/*
+ * Set PC and Thumb state from var. var is marked as dead.
* For M-profile CPUs, include logic to detect exception-return
* branches and handle them. This is needed for Thumb POP/LDM to PC, LDR to PC,
* and BX reg, and no others, and happens only for code in Handler mode.
+ * The Security Extension also requires us to check for the FNC_RETURN
+ * which signals a function return from non-secure state; this can happen
+ * in both Handler and Thread mode.
+ * To avoid having to do multiple comparisons in inline generated code,
+ * we make the check we do here loose, so it will match for EXC_RETURN
+ * in Thread mode. For system emulation do_v7m_exception_exit() checks
+ * for these spurious cases and returns without doing anything (giving
+ * the same behaviour as for a branch to a non-magic address).
+ *
+ * In linux-user mode it is unclear what the right behaviour for an
+ * attempted FNC_RETURN should be, because in real hardware this will go
+ * directly to Secure code (ie not the Linux kernel) which will then treat
+ * the error in any way it chooses. For QEMU we opt to make the FNC_RETURN
+ * attempt behave the way it would on a CPU without the security extension,
+ * which is to say "like a normal branch". That means we can simply treat
+ * all branches as normal with no magic address behaviour.
*/
static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
{
@@ -926,10 +802,12 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
* s->base.is_jmp that we need to do the rest of the work later.
*/
gen_bx(s, var);
+#ifndef CONFIG_USER_ONLY
if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY) ||
(s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M))) {
s->base.is_jmp = DISAS_BX_EXCRET;
}
+#endif
}
static inline void gen_bx_excret_final_code(DisasContext *s)
@@ -1042,7 +920,7 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var)
* that the address argument is TCGv_i32 rather than TCGv.
*/
-static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, TCGMemOp op)
+static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op)
{
TCGv addr = tcg_temp_new();
tcg_gen_extu_i32_tl(addr, a32);
@@ -1055,7 +933,7 @@ static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, TCGMemOp op)
}
static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
- int index, TCGMemOp opc)
+ int index, MemOp opc)
{
TCGv addr;
@@ -1070,7 +948,7 @@ static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
}
static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
- int index, TCGMemOp opc)
+ int index, MemOp opc)
{
TCGv addr;
@@ -1089,14 +967,6 @@ static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \
TCGv_i32 a32, int index) \
{ \
gen_aa32_ld_i32(s, val, a32, index, OPC | s->be_data); \
-} \
-static inline void gen_aa32_ld##SUFF##_iss(DisasContext *s, \
- TCGv_i32 val, \
- TCGv_i32 a32, int index, \
- ISSInfo issinfo) \
-{ \
- gen_aa32_ld##SUFF(s, val, a32, index); \
- disas_set_da_iss(s, OPC, issinfo); \
}
#define DO_GEN_ST(SUFF, OPC) \
@@ -1104,14 +974,6 @@ static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \
TCGv_i32 a32, int index) \
{ \
gen_aa32_st_i32(s, val, a32, index, OPC | s->be_data); \
-} \
-static inline void gen_aa32_st##SUFF##_iss(DisasContext *s, \
- TCGv_i32 val, \
- TCGv_i32 a32, int index, \
- ISSInfo issinfo) \
-{ \
- gen_aa32_st##SUFF(s, val, a32, index); \
- disas_set_da_iss(s, OPC, issinfo | ISSIsWrite); \
}
static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val)
@@ -1123,7 +985,7 @@ static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val)
}
static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
- int index, TCGMemOp opc)
+ int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
tcg_gen_qemu_ld_i64(val, addr, index, opc);
@@ -1138,7 +1000,7 @@ static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
}
static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
- int index, TCGMemOp opc)
+ int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
@@ -1160,9 +1022,7 @@ static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
gen_aa32_st_i64(s, val, a32, index, MO_Q | s->be_data);
}
-DO_GEN_LD(8s, MO_SB)
DO_GEN_LD(8u, MO_UB)
-DO_GEN_LD(16s, MO_SW)
DO_GEN_LD(16u, MO_UW)
DO_GEN_LD(32u, MO_UL)
DO_GEN_ST(8, MO_UB)
@@ -1231,7 +1091,7 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
s->base.is_jmp = DISAS_NORETURN;
}
-void unallocated_encoding(DisasContext *s)
+static void unallocated_encoding(DisasContext *s)
{
/* Unallocated and reserved encodings are uncategorized */
gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(),
@@ -1271,62 +1131,6 @@ static inline void gen_hlt(DisasContext *s, int imm)
unallocated_encoding(s);
}
-static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
- TCGv_i32 var)
-{
- int val, rm, shift, shiftop;
- TCGv_i32 offset;
-
- if (!(insn & (1 << 25))) {
- /* immediate */
- val = insn & 0xfff;
- if (!(insn & (1 << 23)))
- val = -val;
- if (val != 0)
- tcg_gen_addi_i32(var, var, val);
- } else {
- /* shift/register */
- rm = (insn) & 0xf;
- shift = (insn >> 7) & 0x1f;
- shiftop = (insn >> 5) & 3;
- offset = load_reg(s, rm);
- gen_arm_shift_im(offset, shiftop, shift, 0);
- if (!(insn & (1 << 23)))
- tcg_gen_sub_i32(var, var, offset);
- else
- tcg_gen_add_i32(var, var, offset);
- tcg_temp_free_i32(offset);
- }
-}
-
-static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
- int extra, TCGv_i32 var)
-{
- int val, rm;
- TCGv_i32 offset;
-
- if (insn & (1 << 22)) {
- /* immediate */
- val = (insn & 0xf) | ((insn >> 4) & 0xf0);
- if (!(insn & (1 << 23)))
- val = -val;
- val += extra;
- if (val != 0)
- tcg_gen_addi_i32(var, var, val);
- } else {
- /* register */
- if (extra)
- tcg_gen_addi_i32(var, var, extra);
- rm = (insn) & 0xf;
- offset = load_reg(s, rm);
- if (!(insn & (1 << 23)))
- tcg_gen_sub_i32(var, var, offset);
- else
- tcg_gen_add_i32(var, var, offset);
- tcg_temp_free_i32(offset);
- }
-}
-
static TCGv_ptr get_fpstatus_ptr(int neon)
{
TCGv_ptr statusptr = tcg_temp_new_ptr();
@@ -1369,7 +1173,7 @@ neon_reg_offset (int reg, int n)
* where 0 is the least significant end of the register.
*/
static inline long
-neon_element_offset(int reg, int element, TCGMemOp size)
+neon_element_offset(int reg, int element, MemOp size)
{
int element_size = 1 << size;
int ofs = element * element_size;
@@ -1391,7 +1195,7 @@ static TCGv_i32 neon_load_reg(int reg, int pass)
return tmp;
}
-static void neon_load_element(TCGv_i32 var, int reg, int ele, TCGMemOp mop)
+static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
{
long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
@@ -1410,7 +1214,7 @@ static void neon_load_element(TCGv_i32 var, int reg, int ele, TCGMemOp mop)
}
}
-static void neon_load_element64(TCGv_i64 var, int reg, int ele, TCGMemOp mop)
+static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop)
{
long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
@@ -1438,7 +1242,7 @@ static void neon_store_reg(int reg, int pass, TCGv_i32 var)
tcg_temp_free_i32(var);
}
-static void neon_store_element(int reg, int ele, TCGMemOp size, TCGv_i32 var)
+static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var)
{
long offset = neon_element_offset(reg, ele, size);
@@ -1457,7 +1261,7 @@ static void neon_store_element(int reg, int ele, TCGMemOp size, TCGv_i32 var)
}
}
-static void neon_store_element64(int reg, int ele, TCGMemOp size, TCGv_i64 var)
+static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var)
{
long offset = neon_element_offset(reg, ele, size);
@@ -2906,9 +2710,8 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest)
{
if (unlikely(is_singlestepping(s))) {
/* An indirect jump so that we still trigger the debug exception. */
- if (s->thumb)
- dest |= 1;
- gen_bx_im(s, dest);
+ gen_set_pc_im(s, dest);
+ s->base.is_jmp = DISAS_JUMP;
} else {
gen_goto_tb(s, 0, dest);
}
@@ -3224,46 +3027,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
gen_rfe(s, pc, load_cpu_field(spsr));
}
-/*
- * For WFI we will halt the vCPU until an IRQ. For WFE and YIELD we
- * only call the helper when running single threaded TCG code to ensure
- * the next round-robin scheduled vCPU gets a crack. In MTTCG mode we
- * just skip this instruction. Currently the SEV/SEVL instructions
- * which are *one* of many ways to wake the CPU from WFE are not
- * implemented so we can't sleep like WFI does.
- */
-static void gen_nop_hint(DisasContext *s, int val)
-{
- switch (val) {
- /* When running in MTTCG we don't generate jumps to the yield and
- * WFE helpers as it won't affect the scheduling of other vCPUs.
- * If we wanted to more completely model WFE/SEV so we don't busy
- * spin unnecessarily we would need to do something more involved.
- */
- case 1: /* yield */
- if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
- gen_set_pc_im(s, s->base.pc_next);
- s->base.is_jmp = DISAS_YIELD;
- }
- break;
- case 3: /* wfi */
- gen_set_pc_im(s, s->base.pc_next);
- s->base.is_jmp = DISAS_WFI;
- break;
- case 2: /* wfe */
- if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
- gen_set_pc_im(s, s->base.pc_next);
- s->base.is_jmp = DISAS_WFE;
- }
- break;
- case 4: /* sev */
- case 5: /* sevl */
- /* TODO: Implement SEV, SEVL and WFE. May help SMP performance. */
- default: /* nop */
- break;
- }
-}
-
#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
static inline void gen_neon_add(int size, TCGv_i32 t0, TCGv_i32 t1)
@@ -3523,7 +3286,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
int n;
int vec_size;
int mmu_idx;
- TCGMemOp endian;
+ MemOp endian;
TCGv_i32 addr;
TCGv_i32 tmp;
TCGv_i32 tmp2;
@@ -6511,7 +6274,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
}
break;
case NEON_2RM_VREV16:
- gen_rev16(tmp);
+ gen_rev16(tmp, tmp);
break;
case NEON_2RM_VCLS:
switch (size) {
@@ -6830,7 +6593,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
} else if ((insn & 0x380) == 0) {
/* VDUP */
int element;
- TCGMemOp size;
+ MemOp size;
if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
return 1;
@@ -7191,6 +6954,13 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
tcg_temp_free_ptr(tmpptr);
tcg_temp_free_i32(tcg_syn);
tcg_temp_free_i32(tcg_isread);
+ } else if (ri->type & ARM_CP_RAISES_EXC) {
+ /*
+ * The readfn or writefn might raise an exception;
+ * synchronize the CPU state in case it does.
+ */
+ gen_set_condexec(s);
+ gen_set_pc_im(s, s->pc_curr);
}
/* Handle special cases first */
@@ -7345,21 +7115,6 @@ static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
store_reg(s, rhigh, tmp);
}
-/* load a 32-bit value from a register and perform a 64-bit accumulate. */
-static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
-{
- TCGv_i64 tmp;
- TCGv_i32 tmp2;
-
- /* Load value and extend to 64 bits. */
- tmp = tcg_temp_new_i64();
- tmp2 = load_reg(s, rlow);
- tcg_gen_extu_i32_i64(tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- tcg_gen_add_i64(val, val, tmp);
- tcg_temp_free_i64(tmp);
-}
-
/* load and add a 64-bit value from a register pair. */
static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
{
@@ -7395,7 +7150,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
TCGv_i32 addr, int size)
{
TCGv_i32 tmp = tcg_temp_new_i32();
- TCGMemOp opc = size | MO_ALIGN | s->be_data;
+ MemOp opc = size | MO_ALIGN | s->be_data;
s->is_ldex = true;
@@ -7449,7 +7204,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
TCGv taddr;
TCGLabel *done_label;
TCGLabel *fail_label;
- TCGMemOp opc = size | MO_ALIGN | s->be_data;
+ MemOp opc = size | MO_ALIGN | s->be_data;
/* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) {
[addr] = {Rt};
@@ -7657,14 +7412,3055 @@ static void arm_skip_unless(DisasContext *s, uint32_t cond)
arm_gen_test_cc(cond ^ 1, s->condlabel);
}
-static void disas_arm_insn(DisasContext *s, unsigned int insn)
+
+/*
+ * Constant expanders for the decoders.
+ */
+
+static int negate(DisasContext *s, int x)
+{
+ return -x;
+}
+
+static int plus_2(DisasContext *s, int x)
+{
+ return x + 2;
+}
+
+static int times_2(DisasContext *s, int x)
+{
+ return x * 2;
+}
+
+static int times_4(DisasContext *s, int x)
+{
+ return x * 4;
+}
+
+/* Return only the rotation part of T32ExpandImm. */
+static int t32_expandimm_rot(DisasContext *s, int x)
+{
+ return x & 0xc00 ? extract32(x, 7, 5) : 0;
+}
+
+/* Return the unrotated immediate from T32ExpandImm. */
+static int t32_expandimm_imm(DisasContext *s, int x)
+{
+ int imm = extract32(x, 0, 8);
+
+ switch (extract32(x, 8, 4)) {
+ case 0: /* XY */
+ /* Nothing to do. */
+ break;
+ case 1: /* 00XY00XY */
+ imm *= 0x00010001;
+ break;
+ case 2: /* XY00XY00 */
+ imm *= 0x01000100;
+ break;
+ case 3: /* XYXYXYXY */
+ imm *= 0x01010101;
+ break;
+ default:
+ /* Rotated constant. */
+ imm |= 0x80;
+ break;
+ }
+ return imm;
+}
+
+static int t32_branch24(DisasContext *s, int x)
+{
+ /* Convert J1:J2 at x[22:21] to I2:I1, which involves I=J^~S. */
+ x ^= !(x < 0) * (3 << 21);
+ /* Append the final zero. */
+ return x << 1;
+}
+
+static int t16_setflags(DisasContext *s)
+{
+ return s->condexec_mask == 0;
+}
+
+static int t16_push_list(DisasContext *s, int x)
+{
+ return (x & 0xff) | (x & 0x100) << (14 - 8);
+}
+
+static int t16_pop_list(DisasContext *s, int x)
+{
+ return (x & 0xff) | (x & 0x100) << (15 - 8);
+}
+
+/*
+ * Include the generated decoders.
+ */
+
+#include "decode-a32.inc.c"
+#include "decode-a32-uncond.inc.c"
+#include "decode-t32.inc.c"
+#include "decode-t16.inc.c"
+
+/* Helpers to swap operands for reverse-subtract. */
+static void gen_rsb(TCGv_i32 dst, TCGv_i32 a, TCGv_i32 b)
+{
+ tcg_gen_sub_i32(dst, b, a);
+}
+
+static void gen_rsb_CC(TCGv_i32 dst, TCGv_i32 a, TCGv_i32 b)
+{
+ gen_sub_CC(dst, b, a);
+}
+
+static void gen_rsc(TCGv_i32 dest, TCGv_i32 a, TCGv_i32 b)
+{
+ gen_sub_carry(dest, b, a);
+}
+
+static void gen_rsc_CC(TCGv_i32 dest, TCGv_i32 a, TCGv_i32 b)
+{
+ gen_sbc_CC(dest, b, a);
+}
+
+/*
+ * Helpers for the data processing routines.
+ *
+ * After the computation store the results back.
+ * This may be suppressed altogether (STREG_NONE), require a runtime
+ * check against the stack limits (STREG_SP_CHECK), or generate an
+ * exception return. Oh, or store into a register.
+ *
+ * Always return true, indicating success for a trans_* function.
+ */
+typedef enum {
+ STREG_NONE,
+ STREG_NORMAL,
+ STREG_SP_CHECK,
+ STREG_EXC_RET,
+} StoreRegKind;
+
+static bool store_reg_kind(DisasContext *s, int rd,
+ TCGv_i32 val, StoreRegKind kind)
+{
+ switch (kind) {
+ case STREG_NONE:
+ tcg_temp_free_i32(val);
+ return true;
+ case STREG_NORMAL:
+ /* See ALUWritePC: Interworking only from a32 mode. */
+ if (s->thumb) {
+ store_reg(s, rd, val);
+ } else {
+ store_reg_bx(s, rd, val);
+ }
+ return true;
+ case STREG_SP_CHECK:
+ store_sp_checked(s, val);
+ return true;
+ case STREG_EXC_RET:
+ gen_exception_return(s, val);
+ return true;
+ }
+ g_assert_not_reached();
+}
+
+/*
+ * Data Processing (register)
+ *
+ * Operate, with set flags, one register source,
+ * one immediate shifted register source, and a destination.
+ */
+static bool op_s_rrr_shi(DisasContext *s, arg_s_rrr_shi *a,
+ void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32),
+ int logic_cc, StoreRegKind kind)
+{
+ TCGv_i32 tmp1, tmp2;
+
+ tmp2 = load_reg(s, a->rm);
+ gen_arm_shift_im(tmp2, a->shty, a->shim, logic_cc);
+ tmp1 = load_reg(s, a->rn);
+
+ gen(tmp1, tmp1, tmp2);
+ tcg_temp_free_i32(tmp2);
+
+ if (logic_cc) {
+ gen_logic_CC(tmp1);
+ }
+ return store_reg_kind(s, a->rd, tmp1, kind);
+}
+
+static bool op_s_rxr_shi(DisasContext *s, arg_s_rrr_shi *a,
+ void (*gen)(TCGv_i32, TCGv_i32),
+ int logic_cc, StoreRegKind kind)
{
- unsigned int cond, val, op1, i, shift, rm, rs, rn, rd, sh;
TCGv_i32 tmp;
- TCGv_i32 tmp2;
- TCGv_i32 tmp3;
+
+ tmp = load_reg(s, a->rm);
+ gen_arm_shift_im(tmp, a->shty, a->shim, logic_cc);
+
+ gen(tmp, tmp);
+ if (logic_cc) {
+ gen_logic_CC(tmp);
+ }
+ return store_reg_kind(s, a->rd, tmp, kind);
+}
+
+/*
+ * Data-processing (register-shifted register)
+ *
+ * Operate, with set flags, one register source,
+ * one register shifted register source, and a destination.
+ */
+static bool op_s_rrr_shr(DisasContext *s, arg_s_rrr_shr *a,
+ void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32),
+ int logic_cc, StoreRegKind kind)
+{
+ TCGv_i32 tmp1, tmp2;
+
+ tmp1 = load_reg(s, a->rs);
+ tmp2 = load_reg(s, a->rm);
+ gen_arm_shift_reg(tmp2, a->shty, tmp1, logic_cc);
+ tmp1 = load_reg(s, a->rn);
+
+ gen(tmp1, tmp1, tmp2);
+ tcg_temp_free_i32(tmp2);
+
+ if (logic_cc) {
+ gen_logic_CC(tmp1);
+ }
+ return store_reg_kind(s, a->rd, tmp1, kind);
+}
+
+static bool op_s_rxr_shr(DisasContext *s, arg_s_rrr_shr *a,
+ void (*gen)(TCGv_i32, TCGv_i32),
+ int logic_cc, StoreRegKind kind)
+{
+ TCGv_i32 tmp1, tmp2;
+
+ tmp1 = load_reg(s, a->rs);
+ tmp2 = load_reg(s, a->rm);
+ gen_arm_shift_reg(tmp2, a->shty, tmp1, logic_cc);
+
+ gen(tmp2, tmp2);
+ if (logic_cc) {
+ gen_logic_CC(tmp2);
+ }
+ return store_reg_kind(s, a->rd, tmp2, kind);
+}
+
+/*
+ * Data-processing (immediate)
+ *
+ * Operate, with set flags, one register source,
+ * one rotated immediate, and a destination.
+ *
+ * Note that logic_cc && a->rot setting CF based on the msb of the
+ * immediate is the reason why we must pass in the unrotated form
+ * of the immediate.
+ */
+static bool op_s_rri_rot(DisasContext *s, arg_s_rri_rot *a,
+ void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32),
+ int logic_cc, StoreRegKind kind)
+{
+ TCGv_i32 tmp1, tmp2;
+ uint32_t imm;
+
+ imm = ror32(a->imm, a->rot);
+ if (logic_cc && a->rot) {
+ tcg_gen_movi_i32(cpu_CF, imm >> 31);
+ }
+ tmp2 = tcg_const_i32(imm);
+ tmp1 = load_reg(s, a->rn);
+
+ gen(tmp1, tmp1, tmp2);
+ tcg_temp_free_i32(tmp2);
+
+ if (logic_cc) {
+ gen_logic_CC(tmp1);
+ }
+ return store_reg_kind(s, a->rd, tmp1, kind);
+}
+
+static bool op_s_rxi_rot(DisasContext *s, arg_s_rri_rot *a,
+ void (*gen)(TCGv_i32, TCGv_i32),
+ int logic_cc, StoreRegKind kind)
+{
+ TCGv_i32 tmp;
+ uint32_t imm;
+
+ imm = ror32(a->imm, a->rot);
+ if (logic_cc && a->rot) {
+ tcg_gen_movi_i32(cpu_CF, imm >> 31);
+ }
+ tmp = tcg_const_i32(imm);
+
+ gen(tmp, tmp);
+ if (logic_cc) {
+ gen_logic_CC(tmp);
+ }
+ return store_reg_kind(s, a->rd, tmp, kind);
+}
+
+#define DO_ANY3(NAME, OP, L, K) \
+ static bool trans_##NAME##_rrri(DisasContext *s, arg_s_rrr_shi *a) \
+ { StoreRegKind k = (K); return op_s_rrr_shi(s, a, OP, L, k); } \
+ static bool trans_##NAME##_rrrr(DisasContext *s, arg_s_rrr_shr *a) \
+ { StoreRegKind k = (K); return op_s_rrr_shr(s, a, OP, L, k); } \
+ static bool trans_##NAME##_rri(DisasContext *s, arg_s_rri_rot *a) \
+ { StoreRegKind k = (K); return op_s_rri_rot(s, a, OP, L, k); }
+
+#define DO_ANY2(NAME, OP, L, K) \
+ static bool trans_##NAME##_rxri(DisasContext *s, arg_s_rrr_shi *a) \
+ { StoreRegKind k = (K); return op_s_rxr_shi(s, a, OP, L, k); } \
+ static bool trans_##NAME##_rxrr(DisasContext *s, arg_s_rrr_shr *a) \
+ { StoreRegKind k = (K); return op_s_rxr_shr(s, a, OP, L, k); } \
+ static bool trans_##NAME##_rxi(DisasContext *s, arg_s_rri_rot *a) \
+ { StoreRegKind k = (K); return op_s_rxi_rot(s, a, OP, L, k); }
+
+#define DO_CMP2(NAME, OP, L) \
+ static bool trans_##NAME##_xrri(DisasContext *s, arg_s_rrr_shi *a) \
+ { return op_s_rrr_shi(s, a, OP, L, STREG_NONE); } \
+ static bool trans_##NAME##_xrrr(DisasContext *s, arg_s_rrr_shr *a) \
+ { return op_s_rrr_shr(s, a, OP, L, STREG_NONE); } \
+ static bool trans_##NAME##_xri(DisasContext *s, arg_s_rri_rot *a) \
+ { return op_s_rri_rot(s, a, OP, L, STREG_NONE); }
+
+DO_ANY3(AND, tcg_gen_and_i32, a->s, STREG_NORMAL)
+DO_ANY3(EOR, tcg_gen_xor_i32, a->s, STREG_NORMAL)
+DO_ANY3(ORR, tcg_gen_or_i32, a->s, STREG_NORMAL)
+DO_ANY3(BIC, tcg_gen_andc_i32, a->s, STREG_NORMAL)
+
+DO_ANY3(RSB, a->s ? gen_rsb_CC : gen_rsb, false, STREG_NORMAL)
+DO_ANY3(ADC, a->s ? gen_adc_CC : gen_add_carry, false, STREG_NORMAL)
+DO_ANY3(SBC, a->s ? gen_sbc_CC : gen_sub_carry, false, STREG_NORMAL)
+DO_ANY3(RSC, a->s ? gen_rsc_CC : gen_rsc, false, STREG_NORMAL)
+
+DO_CMP2(TST, tcg_gen_and_i32, true)
+DO_CMP2(TEQ, tcg_gen_xor_i32, true)
+DO_CMP2(CMN, gen_add_CC, false)
+DO_CMP2(CMP, gen_sub_CC, false)
+
+DO_ANY3(ADD, a->s ? gen_add_CC : tcg_gen_add_i32, false,
+ a->rd == 13 && a->rn == 13 ? STREG_SP_CHECK : STREG_NORMAL)
+
+/*
+ * Note for the computation of StoreRegKind we return out of the
+ * middle of the functions that are expanded by DO_ANY3, and that
+ * we modify a->s via that parameter before it is used by OP.
+ */
+DO_ANY3(SUB, a->s ? gen_sub_CC : tcg_gen_sub_i32, false,
+ ({
+ StoreRegKind ret = STREG_NORMAL;
+ if (a->rd == 15 && a->s) {
+ /*
+ * See ALUExceptionReturn:
+ * In User mode, UNPREDICTABLE; we choose UNDEF.
+ * In Hyp mode, UNDEFINED.
+ */
+ if (IS_USER(s) || s->current_el == 2) {
+ unallocated_encoding(s);
+ return true;
+ }
+ /* There is no writeback of nzcv to PSTATE. */
+ a->s = 0;
+ ret = STREG_EXC_RET;
+ } else if (a->rd == 13 && a->rn == 13) {
+ ret = STREG_SP_CHECK;
+ }
+ ret;
+ }))
+
+DO_ANY2(MOV, tcg_gen_mov_i32, a->s,
+ ({
+ StoreRegKind ret = STREG_NORMAL;
+ if (a->rd == 15 && a->s) {
+ /*
+ * See ALUExceptionReturn:
+ * In User mode, UNPREDICTABLE; we choose UNDEF.
+ * In Hyp mode, UNDEFINED.
+ */
+ if (IS_USER(s) || s->current_el == 2) {
+ unallocated_encoding(s);
+ return true;
+ }
+ /* There is no writeback of nzcv to PSTATE. */
+ a->s = 0;
+ ret = STREG_EXC_RET;
+ } else if (a->rd == 13) {
+ ret = STREG_SP_CHECK;
+ }
+ ret;
+ }))
+
+DO_ANY2(MVN, tcg_gen_not_i32, a->s, STREG_NORMAL)
+
+/*
+ * ORN is only available with T32, so there is no register-shifted-register
+ * form of the insn. Using the DO_ANY3 macro would create an unused function.
+ */
+static bool trans_ORN_rrri(DisasContext *s, arg_s_rrr_shi *a)
+{
+ return op_s_rrr_shi(s, a, tcg_gen_orc_i32, a->s, STREG_NORMAL);
+}
+
+static bool trans_ORN_rri(DisasContext *s, arg_s_rri_rot *a)
+{
+ return op_s_rri_rot(s, a, tcg_gen_orc_i32, a->s, STREG_NORMAL);
+}
+
+#undef DO_ANY3
+#undef DO_ANY2
+#undef DO_CMP2
+
+static bool trans_ADR(DisasContext *s, arg_ri *a)
+{
+ store_reg_bx(s, a->rd, add_reg_for_lit(s, 15, a->imm));
+ return true;
+}
+
+static bool trans_MOVW(DisasContext *s, arg_MOVW *a)
+{
+ TCGv_i32 tmp;
+
+ if (!ENABLE_ARCH_6T2) {
+ return false;
+ }
+
+ tmp = tcg_const_i32(a->imm);
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_MOVT(DisasContext *s, arg_MOVW *a)
+{
+ TCGv_i32 tmp;
+
+ if (!ENABLE_ARCH_6T2) {
+ return false;
+ }
+
+ tmp = load_reg(s, a->rd);
+ tcg_gen_ext16u_i32(tmp, tmp);
+ tcg_gen_ori_i32(tmp, tmp, a->imm << 16);
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+/*
+ * Multiply and multiply accumulate
+ */
+
+static bool op_mla(DisasContext *s, arg_s_rrrr *a, bool add)
+{
+ TCGv_i32 t1, t2;
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ tcg_gen_mul_i32(t1, t1, t2);
+ tcg_temp_free_i32(t2);
+ if (add) {
+ t2 = load_reg(s, a->ra);
+ tcg_gen_add_i32(t1, t1, t2);
+ tcg_temp_free_i32(t2);
+ }
+ if (a->s) {
+ gen_logic_CC(t1);
+ }
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool trans_MUL(DisasContext *s, arg_MUL *a)
+{
+ return op_mla(s, a, false);
+}
+
+static bool trans_MLA(DisasContext *s, arg_MLA *a)
+{
+ return op_mla(s, a, true);
+}
+
+static bool trans_MLS(DisasContext *s, arg_MLS *a)
+{
+ TCGv_i32 t1, t2;
+
+ if (!ENABLE_ARCH_6T2) {
+ return false;
+ }
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ tcg_gen_mul_i32(t1, t1, t2);
+ tcg_temp_free_i32(t2);
+ t2 = load_reg(s, a->ra);
+ tcg_gen_sub_i32(t1, t2, t1);
+ tcg_temp_free_i32(t2);
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool op_mlal(DisasContext *s, arg_s_rrrr *a, bool uns, bool add)
+{
+ TCGv_i32 t0, t1, t2, t3;
+
+ t0 = load_reg(s, a->rm);
+ t1 = load_reg(s, a->rn);
+ if (uns) {
+ tcg_gen_mulu2_i32(t0, t1, t0, t1);
+ } else {
+ tcg_gen_muls2_i32(t0, t1, t0, t1);
+ }
+ if (add) {
+ t2 = load_reg(s, a->ra);
+ t3 = load_reg(s, a->rd);
+ tcg_gen_add2_i32(t0, t1, t0, t1, t2, t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
+ }
+ if (a->s) {
+ gen_logicq_cc(t0, t1);
+ }
+ store_reg(s, a->ra, t0);
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool trans_UMULL(DisasContext *s, arg_UMULL *a)
+{
+ return op_mlal(s, a, true, false);
+}
+
+static bool trans_SMULL(DisasContext *s, arg_SMULL *a)
+{
+ return op_mlal(s, a, false, false);
+}
+
+static bool trans_UMLAL(DisasContext *s, arg_UMLAL *a)
+{
+ return op_mlal(s, a, true, true);
+}
+
+static bool trans_SMLAL(DisasContext *s, arg_SMLAL *a)
+{
+ return op_mlal(s, a, false, true);
+}
+
+static bool trans_UMAAL(DisasContext *s, arg_UMAAL *a)
+{
+ TCGv_i32 t0, t1, t2, zero;
+
+ if (s->thumb
+ ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
+ : !ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t0 = load_reg(s, a->rm);
+ t1 = load_reg(s, a->rn);
+ tcg_gen_mulu2_i32(t0, t1, t0, t1);
+ zero = tcg_const_i32(0);
+ t2 = load_reg(s, a->ra);
+ tcg_gen_add2_i32(t0, t1, t0, t1, t2, zero);
+ tcg_temp_free_i32(t2);
+ t2 = load_reg(s, a->rd);
+ tcg_gen_add2_i32(t0, t1, t0, t1, t2, zero);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(zero);
+ store_reg(s, a->ra, t0);
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+/*
+ * Saturating addition and subtraction
+ */
+
+static bool op_qaddsub(DisasContext *s, arg_rrr *a, bool add, bool doub)
+{
+ TCGv_i32 t0, t1;
+
+ if (s->thumb
+ ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
+ : !ENABLE_ARCH_5TE) {
+ return false;
+ }
+
+ t0 = load_reg(s, a->rm);
+ t1 = load_reg(s, a->rn);
+ if (doub) {
+ gen_helper_add_saturate(t1, cpu_env, t1, t1);
+ }
+ if (add) {
+ gen_helper_add_saturate(t0, cpu_env, t0, t1);
+ } else {
+ gen_helper_sub_saturate(t0, cpu_env, t0, t1);
+ }
+ tcg_temp_free_i32(t1);
+ store_reg(s, a->rd, t0);
+ return true;
+}
+
+#define DO_QADDSUB(NAME, ADD, DOUB) \
+static bool trans_##NAME(DisasContext *s, arg_rrr *a) \
+{ \
+ return op_qaddsub(s, a, ADD, DOUB); \
+}
+
+DO_QADDSUB(QADD, true, false)
+DO_QADDSUB(QSUB, false, false)
+DO_QADDSUB(QDADD, true, true)
+DO_QADDSUB(QDSUB, false, true)
+
+#undef DO_QADDSUB
+
+/*
+ * Halfword multiply and multiply accumulate
+ */
+
+static bool op_smlaxxx(DisasContext *s, arg_rrrr *a,
+ int add_long, bool nt, bool mt)
+{
+ TCGv_i32 t0, t1, tl, th;
+
+ if (s->thumb
+ ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
+ : !ENABLE_ARCH_5TE) {
+ return false;
+ }
+
+ t0 = load_reg(s, a->rn);
+ t1 = load_reg(s, a->rm);
+ gen_mulxy(t0, t1, nt, mt);
+ tcg_temp_free_i32(t1);
+
+ switch (add_long) {
+ case 0:
+ store_reg(s, a->rd, t0);
+ break;
+ case 1:
+ t1 = load_reg(s, a->ra);
+ gen_helper_add_setq(t0, cpu_env, t0, t1);
+ tcg_temp_free_i32(t1);
+ store_reg(s, a->rd, t0);
+ break;
+ case 2:
+ tl = load_reg(s, a->ra);
+ th = load_reg(s, a->rd);
+ t1 = tcg_const_i32(0);
+ tcg_gen_add2_i32(tl, th, tl, th, t0, t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ store_reg(s, a->ra, tl);
+ store_reg(s, a->rd, th);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return true;
+}
+
+#define DO_SMLAX(NAME, add, nt, mt) \
+static bool trans_##NAME(DisasContext *s, arg_rrrr *a) \
+{ \
+ return op_smlaxxx(s, a, add, nt, mt); \
+}
+
+DO_SMLAX(SMULBB, 0, 0, 0)
+DO_SMLAX(SMULBT, 0, 0, 1)
+DO_SMLAX(SMULTB, 0, 1, 0)
+DO_SMLAX(SMULTT, 0, 1, 1)
+
+DO_SMLAX(SMLABB, 1, 0, 0)
+DO_SMLAX(SMLABT, 1, 0, 1)
+DO_SMLAX(SMLATB, 1, 1, 0)
+DO_SMLAX(SMLATT, 1, 1, 1)
+
+DO_SMLAX(SMLALBB, 2, 0, 0)
+DO_SMLAX(SMLALBT, 2, 0, 1)
+DO_SMLAX(SMLALTB, 2, 1, 0)
+DO_SMLAX(SMLALTT, 2, 1, 1)
+
+#undef DO_SMLAX
+
+static bool op_smlawx(DisasContext *s, arg_rrrr *a, bool add, bool mt)
+{
+ TCGv_i32 t0, t1;
+
+ if (!ENABLE_ARCH_5TE) {
+ return false;
+ }
+
+ t0 = load_reg(s, a->rn);
+ t1 = load_reg(s, a->rm);
+ /*
+ * Since the nominal result is product<47:16>, shift the 16-bit
+ * input up by 16 bits, so that the result is at product<63:32>.
+ */
+ if (mt) {
+ tcg_gen_andi_i32(t1, t1, 0xffff0000);
+ } else {
+ tcg_gen_shli_i32(t1, t1, 16);
+ }
+ tcg_gen_muls2_i32(t0, t1, t0, t1);
+ tcg_temp_free_i32(t0);
+ if (add) {
+ t0 = load_reg(s, a->ra);
+ gen_helper_add_setq(t1, cpu_env, t1, t0);
+ tcg_temp_free_i32(t0);
+ }
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+#define DO_SMLAWX(NAME, add, mt) \
+static bool trans_##NAME(DisasContext *s, arg_rrrr *a) \
+{ \
+ return op_smlawx(s, a, add, mt); \
+}
+
+DO_SMLAWX(SMULWB, 0, 0)
+DO_SMLAWX(SMULWT, 0, 1)
+DO_SMLAWX(SMLAWB, 1, 0)
+DO_SMLAWX(SMLAWT, 1, 1)
+
+#undef DO_SMLAWX
+
+/*
+ * MSR (immediate) and hints
+ */
+
+static bool trans_YIELD(DisasContext *s, arg_YIELD *a)
+{
+ /*
+ * When running single-threaded TCG code, use the helper to ensure that
+ * the next round-robin scheduled vCPU gets a crack. When running in
+ * MTTCG we don't generate jumps to the helper as it won't affect the
+ * scheduling of other vCPUs.
+ */
+ if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
+ gen_set_pc_im(s, s->base.pc_next);
+ s->base.is_jmp = DISAS_YIELD;
+ }
+ return true;
+}
+
+static bool trans_WFE(DisasContext *s, arg_WFE *a)
+{
+ /*
+ * When running single-threaded TCG code, use the helper to ensure that
+ * the next round-robin scheduled vCPU gets a crack. In MTTCG mode we
+ * just skip this instruction. Currently the SEV/SEVL instructions,
+ * which are *one* of many ways to wake the CPU from WFE, are not
+ * implemented so we can't sleep like WFI does.
+ */
+ if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
+ gen_set_pc_im(s, s->base.pc_next);
+ s->base.is_jmp = DISAS_WFE;
+ }
+ return true;
+}
+
+static bool trans_WFI(DisasContext *s, arg_WFI *a)
+{
+ /* For WFI, halt the vCPU until an IRQ. */
+ gen_set_pc_im(s, s->base.pc_next);
+ s->base.is_jmp = DISAS_WFI;
+ return true;
+}
+
+static bool trans_NOP(DisasContext *s, arg_NOP *a)
+{
+ return true;
+}
+
+static bool trans_MSR_imm(DisasContext *s, arg_MSR_imm *a)
+{
+ uint32_t val = ror32(a->imm, a->rot * 2);
+ uint32_t mask = msr_mask(s, a->mask, a->r);
+
+ if (gen_set_psr_im(s, mask, a->r, val)) {
+ unallocated_encoding(s);
+ }
+ return true;
+}
+
+/*
+ * Cyclic Redundancy Check
+ */
+
+static bool op_crc32(DisasContext *s, arg_rrr *a, bool c, MemOp sz)
+{
+ TCGv_i32 t1, t2, t3;
+
+ if (!dc_isar_feature(aa32_crc32, s)) {
+ return false;
+ }
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ switch (sz) {
+ case MO_8:
+ gen_uxtb(t2);
+ break;
+ case MO_16:
+ gen_uxth(t2);
+ break;
+ case MO_32:
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ t3 = tcg_const_i32(1 << sz);
+ if (c) {
+ gen_helper_crc32c(t1, t1, t2, t3);
+ } else {
+ gen_helper_crc32(t1, t1, t2, t3);
+ }
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+#define DO_CRC32(NAME, c, sz) \
+static bool trans_##NAME(DisasContext *s, arg_rrr *a) \
+ { return op_crc32(s, a, c, sz); }
+
+DO_CRC32(CRC32B, false, MO_8)
+DO_CRC32(CRC32H, false, MO_16)
+DO_CRC32(CRC32W, false, MO_32)
+DO_CRC32(CRC32CB, true, MO_8)
+DO_CRC32(CRC32CH, true, MO_16)
+DO_CRC32(CRC32CW, true, MO_32)
+
+#undef DO_CRC32
+
+/*
+ * Miscellaneous instructions
+ */
+
+static bool trans_MRS_bank(DisasContext *s, arg_MRS_bank *a)
+{
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ gen_mrs_banked(s, a->r, a->sysm, a->rd);
+ return true;
+}
+
+static bool trans_MSR_bank(DisasContext *s, arg_MSR_bank *a)
+{
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ gen_msr_banked(s, a->r, a->sysm, a->rn);
+ return true;
+}
+
+static bool trans_MRS_reg(DisasContext *s, arg_MRS_reg *a)
+{
+ TCGv_i32 tmp;
+
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ if (a->r) {
+ if (IS_USER(s)) {
+ unallocated_encoding(s);
+ return true;
+ }
+ tmp = load_cpu_field(spsr);
+ } else {
+ tmp = tcg_temp_new_i32();
+ gen_helper_cpsr_read(tmp, cpu_env);
+ }
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_MSR_reg(DisasContext *s, arg_MSR_reg *a)
+{
+ TCGv_i32 tmp;
+ uint32_t mask = msr_mask(s, a->mask, a->r);
+
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ tmp = load_reg(s, a->rn);
+ if (gen_set_psr(s, mask, a->r, tmp)) {
+ unallocated_encoding(s);
+ }
+ return true;
+}
+
+static bool trans_MRS_v7m(DisasContext *s, arg_MRS_v7m *a)
+{
+ TCGv_i32 tmp;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ tmp = tcg_const_i32(a->sysm);
+ gen_helper_v7m_mrs(tmp, cpu_env, tmp);
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a)
+{
+ TCGv_i32 addr, reg;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ addr = tcg_const_i32((a->mask << 10) | a->sysm);
+ reg = load_reg(s, a->rn);
+ gen_helper_v7m_msr(cpu_env, addr, reg);
+ tcg_temp_free_i32(addr);
+ tcg_temp_free_i32(reg);
+ gen_lookup_tb(s);
+ return true;
+}
+
+static bool trans_BX(DisasContext *s, arg_BX *a)
+{
+ if (!ENABLE_ARCH_4T) {
+ return false;
+ }
+ gen_bx_excret(s, load_reg(s, a->rm));
+ return true;
+}
+
+static bool trans_BXJ(DisasContext *s, arg_BXJ *a)
+{
+ if (!ENABLE_ARCH_5J || arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ /* Trivial implementation equivalent to bx. */
+ gen_bx(s, load_reg(s, a->rm));
+ return true;
+}
+
+static bool trans_BLX_r(DisasContext *s, arg_BLX_r *a)
+{
+ TCGv_i32 tmp;
+
+ if (!ENABLE_ARCH_5) {
+ return false;
+ }
+ tmp = load_reg(s, a->rm);
+ tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
+ gen_bx(s, tmp);
+ return true;
+}
+
+/*
+ * BXNS/BLXNS: only exist for v8M with the security extensions,
+ * and always UNDEF if NonSecure. We don't implement these in
+ * the user-only mode either (in theory you can use them from
+ * Secure User mode but they are too tied in to system emulation).
+ */
+static bool trans_BXNS(DisasContext *s, arg_BXNS *a)
+{
+ if (!s->v8m_secure || IS_USER_ONLY) {
+ unallocated_encoding(s);
+ } else {
+ gen_bxns(s, a->rm);
+ }
+ return true;
+}
+
+static bool trans_BLXNS(DisasContext *s, arg_BLXNS *a)
+{
+ if (!s->v8m_secure || IS_USER_ONLY) {
+ unallocated_encoding(s);
+ } else {
+ gen_blxns(s, a->rm);
+ }
+ return true;
+}
+
+static bool trans_CLZ(DisasContext *s, arg_CLZ *a)
+{
+ TCGv_i32 tmp;
+
+ if (!ENABLE_ARCH_5) {
+ return false;
+ }
+ tmp = load_reg(s, a->rm);
+ tcg_gen_clzi_i32(tmp, tmp, 32);
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_ERET(DisasContext *s, arg_ERET *a)
+{
+ TCGv_i32 tmp;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_V7VE)) {
+ return false;
+ }
+ if (IS_USER(s)) {
+ unallocated_encoding(s);
+ return true;
+ }
+ if (s->current_el == 2) {
+ /* ERET from Hyp uses ELR_Hyp, not LR */
+ tmp = load_cpu_field(elr_el[2]);
+ } else {
+ tmp = load_reg(s, 14);
+ }
+ gen_exception_return(s, tmp);
+ return true;
+}
+
+static bool trans_HLT(DisasContext *s, arg_HLT *a)
+{
+ gen_hlt(s, a->imm);
+ return true;
+}
+
+static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
+{
+ if (!ENABLE_ARCH_5) {
+ return false;
+ }
+ gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
+ return true;
+}
+
+static bool trans_HVC(DisasContext *s, arg_HVC *a)
+{
+ if (!ENABLE_ARCH_7 || arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ if (IS_USER(s)) {
+ unallocated_encoding(s);
+ } else {
+ gen_hvc(s, a->imm);
+ }
+ return true;
+}
+
+static bool trans_SMC(DisasContext *s, arg_SMC *a)
+{
+ if (!ENABLE_ARCH_6K || arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ if (IS_USER(s)) {
+ unallocated_encoding(s);
+ } else {
+ gen_smc(s);
+ }
+ return true;
+}
+
+static bool trans_SG(DisasContext *s, arg_SG *a)
+{
+ if (!arm_dc_feature(s, ARM_FEATURE_M) ||
+ !arm_dc_feature(s, ARM_FEATURE_V8)) {
+ return false;
+ }
+ /*
+ * SG (v8M only)
+ * The bulk of the behaviour for this instruction is implemented
+ * in v7m_handle_execute_nsc(), which deals with the insn when
+ * it is executed by a CPU in non-secure state from memory
+ * which is Secure & NonSecure-Callable.
+ * Here we only need to handle the remaining cases:
+ * * in NS memory (including the "security extension not
+ * implemented" case) : NOP
+ * * in S memory but CPU already secure (clear IT bits)
+ * We know that the attribute for the memory this insn is
+ * in must match the current CPU state, because otherwise
+ * get_phys_addr_pmsav8 would have generated an exception.
+ */
+ if (s->v8m_secure) {
+ /* Like the IT insn, we don't need to generate any code */
+ s->condexec_cond = 0;
+ s->condexec_mask = 0;
+ }
+ return true;
+}
+
+static bool trans_TT(DisasContext *s, arg_TT *a)
+{
+ TCGv_i32 addr, tmp;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_M) ||
+ !arm_dc_feature(s, ARM_FEATURE_V8)) {
+ return false;
+ }
+ if (a->rd == 13 || a->rd == 15 || a->rn == 15) {
+ /* We UNDEF for these UNPREDICTABLE cases */
+ unallocated_encoding(s);
+ return true;
+ }
+ if (a->A && !s->v8m_secure) {
+ /* This case is UNDEFINED. */
+ unallocated_encoding(s);
+ return true;
+ }
+
+ addr = load_reg(s, a->rn);
+ tmp = tcg_const_i32((a->A << 1) | a->T);
+ gen_helper_v7m_tt(tmp, cpu_env, addr, tmp);
+ tcg_temp_free_i32(addr);
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+/*
+ * Load/store register index
+ */
+
+static ISSInfo make_issinfo(DisasContext *s, int rd, bool p, bool w)
+{
+ ISSInfo ret;
+
+ /* ISS not valid if writeback */
+ if (p && !w) {
+ ret = rd;
+ } else {
+ ret = ISSInvalid;
+ }
+ return ret;
+}
+
+static TCGv_i32 op_addr_rr_pre(DisasContext *s, arg_ldst_rr *a)
+{
+ TCGv_i32 addr = load_reg(s, a->rn);
+
+ if (s->v8m_stackcheck && a->rn == 13 && a->w) {
+ gen_helper_v8m_stackcheck(cpu_env, addr);
+ }
+
+ if (a->p) {
+ TCGv_i32 ofs = load_reg(s, a->rm);
+ gen_arm_shift_im(ofs, a->shtype, a->shimm, 0);
+ if (a->u) {
+ tcg_gen_add_i32(addr, addr, ofs);
+ } else {
+ tcg_gen_sub_i32(addr, addr, ofs);
+ }
+ tcg_temp_free_i32(ofs);
+ }
+ return addr;
+}
+
+static void op_addr_rr_post(DisasContext *s, arg_ldst_rr *a,
+ TCGv_i32 addr, int address_offset)
+{
+ if (!a->p) {
+ TCGv_i32 ofs = load_reg(s, a->rm);
+ gen_arm_shift_im(ofs, a->shtype, a->shimm, 0);
+ if (a->u) {
+ tcg_gen_add_i32(addr, addr, ofs);
+ } else {
+ tcg_gen_sub_i32(addr, addr, ofs);
+ }
+ tcg_temp_free_i32(ofs);
+ } else if (!a->w) {
+ tcg_temp_free_i32(addr);
+ return;
+ }
+ tcg_gen_addi_i32(addr, addr, address_offset);
+ store_reg(s, a->rn, addr);
+}
+
+static bool op_load_rr(DisasContext *s, arg_ldst_rr *a,
+ MemOp mop, int mem_idx)
+{
+ ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w);
+ TCGv_i32 addr, tmp;
+
+ addr = op_addr_rr_pre(s, a);
+
+ tmp = tcg_temp_new_i32();
+ gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop | s->be_data);
+ disas_set_da_iss(s, mop, issinfo);
+
+ /*
+ * Perform base writeback before the loaded value to
+ * ensure correct behavior with overlapping index registers.
+ */
+ op_addr_rr_post(s, a, addr, 0);
+ store_reg_from_load(s, a->rt, tmp);
+ return true;
+}
+
+static bool op_store_rr(DisasContext *s, arg_ldst_rr *a,
+ MemOp mop, int mem_idx)
+{
+ ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w) | ISSIsWrite;
+ TCGv_i32 addr, tmp;
+
+ addr = op_addr_rr_pre(s, a);
+
+ tmp = load_reg(s, a->rt);
+ gen_aa32_st_i32(s, tmp, addr, mem_idx, mop | s->be_data);
+ disas_set_da_iss(s, mop, issinfo);
+ tcg_temp_free_i32(tmp);
+
+ op_addr_rr_post(s, a, addr, 0);
+ return true;
+}
+
+static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
+{
+ int mem_idx = get_mem_index(s);
+ TCGv_i32 addr, tmp;
+
+ if (!ENABLE_ARCH_5TE) {
+ return false;
+ }
+ if (a->rt & 1) {
+ unallocated_encoding(s);
+ return true;
+ }
+ addr = op_addr_rr_pre(s, a);
+
+ tmp = tcg_temp_new_i32();
+ gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data);
+ store_reg(s, a->rt, tmp);
+
+ tcg_gen_addi_i32(addr, addr, 4);
+
+ tmp = tcg_temp_new_i32();
+ gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data);
+ store_reg(s, a->rt + 1, tmp);
+
+ /* LDRD w/ base writeback is undefined if the registers overlap. */
+ op_addr_rr_post(s, a, addr, -4);
+ return true;
+}
+
+static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a)
+{
+ int mem_idx = get_mem_index(s);
+ TCGv_i32 addr, tmp;
+
+ if (!ENABLE_ARCH_5TE) {
+ return false;
+ }
+ if (a->rt & 1) {
+ unallocated_encoding(s);
+ return true;
+ }
+ addr = op_addr_rr_pre(s, a);
+
+ tmp = load_reg(s, a->rt);
+ gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data);
+ tcg_temp_free_i32(tmp);
+
+ tcg_gen_addi_i32(addr, addr, 4);
+
+ tmp = load_reg(s, a->rt + 1);
+ gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data);
+ tcg_temp_free_i32(tmp);
+
+ op_addr_rr_post(s, a, addr, -4);
+ return true;
+}
+
+/*
+ * Load/store immediate index
+ */
+
+static TCGv_i32 op_addr_ri_pre(DisasContext *s, arg_ldst_ri *a)
+{
+ int ofs = a->imm;
+
+ if (!a->u) {
+ ofs = -ofs;
+ }
+
+ if (s->v8m_stackcheck && a->rn == 13 && a->w) {
+ /*
+ * Stackcheck. Here we know 'addr' is the current SP;
+ * U is set if we're moving SP up, else down. It is
+ * UNKNOWN whether the limit check triggers when SP starts
+ * below the limit and ends up above it; we chose to do so.
+ */
+ if (!a->u) {
+ TCGv_i32 newsp = tcg_temp_new_i32();
+ tcg_gen_addi_i32(newsp, cpu_R[13], ofs);
+ gen_helper_v8m_stackcheck(cpu_env, newsp);
+ tcg_temp_free_i32(newsp);
+ } else {
+ gen_helper_v8m_stackcheck(cpu_env, cpu_R[13]);
+ }
+ }
+
+ return add_reg_for_lit(s, a->rn, a->p ? ofs : 0);
+}
+
+static void op_addr_ri_post(DisasContext *s, arg_ldst_ri *a,
+ TCGv_i32 addr, int address_offset)
+{
+ if (!a->p) {
+ if (a->u) {
+ address_offset += a->imm;
+ } else {
+ address_offset -= a->imm;
+ }
+ } else if (!a->w) {
+ tcg_temp_free_i32(addr);
+ return;
+ }
+ tcg_gen_addi_i32(addr, addr, address_offset);
+ store_reg(s, a->rn, addr);
+}
+
+static bool op_load_ri(DisasContext *s, arg_ldst_ri *a,
+ MemOp mop, int mem_idx)
+{
+ ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w);
+ TCGv_i32 addr, tmp;
+
+ addr = op_addr_ri_pre(s, a);
+
+ tmp = tcg_temp_new_i32();
+ gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop | s->be_data);
+ disas_set_da_iss(s, mop, issinfo);
+
+ /*
+ * Perform base writeback before the loaded value to
+ * ensure correct behavior with overlapping index registers.
+ */
+ op_addr_ri_post(s, a, addr, 0);
+ store_reg_from_load(s, a->rt, tmp);
+ return true;
+}
+
+static bool op_store_ri(DisasContext *s, arg_ldst_ri *a,
+ MemOp mop, int mem_idx)
+{
+ ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w) | ISSIsWrite;
+ TCGv_i32 addr, tmp;
+
+ addr = op_addr_ri_pre(s, a);
+
+ tmp = load_reg(s, a->rt);
+ gen_aa32_st_i32(s, tmp, addr, mem_idx, mop | s->be_data);
+ disas_set_da_iss(s, mop, issinfo);
+ tcg_temp_free_i32(tmp);
+
+ op_addr_ri_post(s, a, addr, 0);
+ return true;
+}
+
+static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
+{
+ int mem_idx = get_mem_index(s);
+ TCGv_i32 addr, tmp;
+
+ addr = op_addr_ri_pre(s, a);
+
+ tmp = tcg_temp_new_i32();
+ gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data);
+ store_reg(s, a->rt, tmp);
+
+ tcg_gen_addi_i32(addr, addr, 4);
+
+ tmp = tcg_temp_new_i32();
+ gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data);
+ store_reg(s, rt2, tmp);
+
+ /* LDRD w/ base writeback is undefined if the registers overlap. */
+ op_addr_ri_post(s, a, addr, -4);
+ return true;
+}
+
+static bool trans_LDRD_ri_a32(DisasContext *s, arg_ldst_ri *a)
+{
+ if (!ENABLE_ARCH_5TE || (a->rt & 1)) {
+ return false;
+ }
+ return op_ldrd_ri(s, a, a->rt + 1);
+}
+
+static bool trans_LDRD_ri_t32(DisasContext *s, arg_ldst_ri2 *a)
+{
+ arg_ldst_ri b = {
+ .u = a->u, .w = a->w, .p = a->p,
+ .rn = a->rn, .rt = a->rt, .imm = a->imm
+ };
+ return op_ldrd_ri(s, &b, a->rt2);
+}
+
+static bool op_strd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
+{
+ int mem_idx = get_mem_index(s);
+ TCGv_i32 addr, tmp;
+
+ addr = op_addr_ri_pre(s, a);
+
+ tmp = load_reg(s, a->rt);
+ gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data);
+ tcg_temp_free_i32(tmp);
+
+ tcg_gen_addi_i32(addr, addr, 4);
+
+ tmp = load_reg(s, rt2);
+ gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data);
+ tcg_temp_free_i32(tmp);
+
+ op_addr_ri_post(s, a, addr, -4);
+ return true;
+}
+
+static bool trans_STRD_ri_a32(DisasContext *s, arg_ldst_ri *a)
+{
+ if (!ENABLE_ARCH_5TE || (a->rt & 1)) {
+ return false;
+ }
+ return op_strd_ri(s, a, a->rt + 1);
+}
+
+static bool trans_STRD_ri_t32(DisasContext *s, arg_ldst_ri2 *a)
+{
+ arg_ldst_ri b = {
+ .u = a->u, .w = a->w, .p = a->p,
+ .rn = a->rn, .rt = a->rt, .imm = a->imm
+ };
+ return op_strd_ri(s, &b, a->rt2);
+}
+
+#define DO_LDST(NAME, WHICH, MEMOP) \
+static bool trans_##NAME##_ri(DisasContext *s, arg_ldst_ri *a) \
+{ \
+ return op_##WHICH##_ri(s, a, MEMOP, get_mem_index(s)); \
+} \
+static bool trans_##NAME##T_ri(DisasContext *s, arg_ldst_ri *a) \
+{ \
+ return op_##WHICH##_ri(s, a, MEMOP, get_a32_user_mem_index(s)); \
+} \
+static bool trans_##NAME##_rr(DisasContext *s, arg_ldst_rr *a) \
+{ \
+ return op_##WHICH##_rr(s, a, MEMOP, get_mem_index(s)); \
+} \
+static bool trans_##NAME##T_rr(DisasContext *s, arg_ldst_rr *a) \
+{ \
+ return op_##WHICH##_rr(s, a, MEMOP, get_a32_user_mem_index(s)); \
+}
+
+DO_LDST(LDR, load, MO_UL)
+DO_LDST(LDRB, load, MO_UB)
+DO_LDST(LDRH, load, MO_UW)
+DO_LDST(LDRSB, load, MO_SB)
+DO_LDST(LDRSH, load, MO_SW)
+
+DO_LDST(STR, store, MO_UL)
+DO_LDST(STRB, store, MO_UB)
+DO_LDST(STRH, store, MO_UW)
+
+#undef DO_LDST
+
+/*
+ * Synchronization primitives
+ */
+
+static bool op_swp(DisasContext *s, arg_SWP *a, MemOp opc)
+{
+ TCGv_i32 addr, tmp;
+ TCGv taddr;
+
+ opc |= s->be_data;
+ addr = load_reg(s, a->rn);
+ taddr = gen_aa32_addr(s, addr, opc);
+ tcg_temp_free_i32(addr);
+
+ tmp = load_reg(s, a->rt2);
+ tcg_gen_atomic_xchg_i32(tmp, taddr, tmp, get_mem_index(s), opc);
+ tcg_temp_free(taddr);
+
+ store_reg(s, a->rt, tmp);
+ return true;
+}
+
+static bool trans_SWP(DisasContext *s, arg_SWP *a)
+{
+ return op_swp(s, a, MO_UL | MO_ALIGN);
+}
+
+static bool trans_SWPB(DisasContext *s, arg_SWP *a)
+{
+ return op_swp(s, a, MO_UB);
+}
+
+/*
+ * Load/Store Exclusive and Load-Acquire/Store-Release
+ */
+
+static bool op_strex(DisasContext *s, arg_STREX *a, MemOp mop, bool rel)
+{
TCGv_i32 addr;
- TCGv_i64 tmp64;
+
+ /* We UNDEF for these UNPREDICTABLE cases. */
+ if (a->rd == 15 || a->rn == 15 || a->rt == 15
+ || a->rd == a->rn || a->rd == a->rt
+ || (s->thumb && (a->rd == 13 || a->rt == 13))
+ || (mop == MO_64
+ && (a->rt2 == 15
+ || a->rd == a->rt2 || a->rt == a->rt2
+ || (s->thumb && a->rt2 == 13)))) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ if (rel) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ }
+
+ addr = tcg_temp_local_new_i32();
+ load_reg_var(s, addr, a->rn);
+ tcg_gen_addi_i32(addr, addr, a->imm);
+
+ gen_store_exclusive(s, a->rd, a->rt, a->rt2, addr, mop);
+ tcg_temp_free_i32(addr);
+ return true;
+}
+
+static bool trans_STREX(DisasContext *s, arg_STREX *a)
+{
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+ return op_strex(s, a, MO_32, false);
+}
+
+static bool trans_STREXD_a32(DisasContext *s, arg_STREX *a)
+{
+ if (!ENABLE_ARCH_6K) {
+ return false;
+ }
+ /* We UNDEF for these UNPREDICTABLE cases. */
+ if (a->rt & 1) {
+ unallocated_encoding(s);
+ return true;
+ }
+ a->rt2 = a->rt + 1;
+ return op_strex(s, a, MO_64, false);
+}
+
+static bool trans_STREXD_t32(DisasContext *s, arg_STREX *a)
+{
+ return op_strex(s, a, MO_64, false);
+}
+
+static bool trans_STREXB(DisasContext *s, arg_STREX *a)
+{
+ if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) {
+ return false;
+ }
+ return op_strex(s, a, MO_8, false);
+}
+
+static bool trans_STREXH(DisasContext *s, arg_STREX *a)
+{
+ if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) {
+ return false;
+ }
+ return op_strex(s, a, MO_16, false);
+}
+
+static bool trans_STLEX(DisasContext *s, arg_STREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ return op_strex(s, a, MO_32, true);
+}
+
+static bool trans_STLEXD_a32(DisasContext *s, arg_STREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ /* We UNDEF for these UNPREDICTABLE cases. */
+ if (a->rt & 1) {
+ unallocated_encoding(s);
+ return true;
+ }
+ a->rt2 = a->rt + 1;
+ return op_strex(s, a, MO_64, true);
+}
+
+static bool trans_STLEXD_t32(DisasContext *s, arg_STREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ return op_strex(s, a, MO_64, true);
+}
+
+static bool trans_STLEXB(DisasContext *s, arg_STREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ return op_strex(s, a, MO_8, true);
+}
+
+static bool trans_STLEXH(DisasContext *s, arg_STREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ return op_strex(s, a, MO_16, true);
+}
+
+static bool op_stl(DisasContext *s, arg_STL *a, MemOp mop)
+{
+ TCGv_i32 addr, tmp;
+
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ /* We UNDEF for these UNPREDICTABLE cases. */
+ if (a->rn == 15 || a->rt == 15) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ addr = load_reg(s, a->rn);
+ tmp = load_reg(s, a->rt);
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), mop | s->be_data);
+ disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel | ISSIsWrite);
+
+ tcg_temp_free_i32(tmp);
+ tcg_temp_free_i32(addr);
+ return true;
+}
+
+static bool trans_STL(DisasContext *s, arg_STL *a)
+{
+ return op_stl(s, a, MO_UL);
+}
+
+static bool trans_STLB(DisasContext *s, arg_STL *a)
+{
+ return op_stl(s, a, MO_UB);
+}
+
+static bool trans_STLH(DisasContext *s, arg_STL *a)
+{
+ return op_stl(s, a, MO_UW);
+}
+
+static bool op_ldrex(DisasContext *s, arg_LDREX *a, MemOp mop, bool acq)
+{
+ TCGv_i32 addr;
+
+ /* We UNDEF for these UNPREDICTABLE cases. */
+ if (a->rn == 15 || a->rt == 15
+ || (s->thumb && a->rt == 13)
+ || (mop == MO_64
+ && (a->rt2 == 15 || a->rt == a->rt2
+ || (s->thumb && a->rt2 == 13)))) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ addr = tcg_temp_local_new_i32();
+ load_reg_var(s, addr, a->rn);
+ tcg_gen_addi_i32(addr, addr, a->imm);
+
+ gen_load_exclusive(s, a->rt, a->rt2, addr, mop);
+ tcg_temp_free_i32(addr);
+
+ if (acq) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
+ return true;
+}
+
+static bool trans_LDREX(DisasContext *s, arg_LDREX *a)
+{
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+ return op_ldrex(s, a, MO_32, false);
+}
+
+static bool trans_LDREXD_a32(DisasContext *s, arg_LDREX *a)
+{
+ if (!ENABLE_ARCH_6K) {
+ return false;
+ }
+ /* We UNDEF for these UNPREDICTABLE cases. */
+ if (a->rt & 1) {
+ unallocated_encoding(s);
+ return true;
+ }
+ a->rt2 = a->rt + 1;
+ return op_ldrex(s, a, MO_64, false);
+}
+
+static bool trans_LDREXD_t32(DisasContext *s, arg_LDREX *a)
+{
+ return op_ldrex(s, a, MO_64, false);
+}
+
+static bool trans_LDREXB(DisasContext *s, arg_LDREX *a)
+{
+ if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) {
+ return false;
+ }
+ return op_ldrex(s, a, MO_8, false);
+}
+
+static bool trans_LDREXH(DisasContext *s, arg_LDREX *a)
+{
+ if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) {
+ return false;
+ }
+ return op_ldrex(s, a, MO_16, false);
+}
+
+static bool trans_LDAEX(DisasContext *s, arg_LDREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ return op_ldrex(s, a, MO_32, true);
+}
+
+static bool trans_LDAEXD_a32(DisasContext *s, arg_LDREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ /* We UNDEF for these UNPREDICTABLE cases. */
+ if (a->rt & 1) {
+ unallocated_encoding(s);
+ return true;
+ }
+ a->rt2 = a->rt + 1;
+ return op_ldrex(s, a, MO_64, true);
+}
+
+static bool trans_LDAEXD_t32(DisasContext *s, arg_LDREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ return op_ldrex(s, a, MO_64, true);
+}
+
+static bool trans_LDAEXB(DisasContext *s, arg_LDREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ return op_ldrex(s, a, MO_8, true);
+}
+
+static bool trans_LDAEXH(DisasContext *s, arg_LDREX *a)
+{
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ return op_ldrex(s, a, MO_16, true);
+}
+
+static bool op_lda(DisasContext *s, arg_LDA *a, MemOp mop)
+{
+ TCGv_i32 addr, tmp;
+
+ if (!ENABLE_ARCH_8) {
+ return false;
+ }
+ /* We UNDEF for these UNPREDICTABLE cases. */
+ if (a->rn == 15 || a->rt == 15) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ addr = load_reg(s, a->rn);
+ tmp = tcg_temp_new_i32();
+ gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop | s->be_data);
+ disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel);
+ tcg_temp_free_i32(addr);
+
+ store_reg(s, a->rt, tmp);
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ return true;
+}
+
+static bool trans_LDA(DisasContext *s, arg_LDA *a)
+{
+ return op_lda(s, a, MO_UL);
+}
+
+static bool trans_LDAB(DisasContext *s, arg_LDA *a)
+{
+ return op_lda(s, a, MO_UB);
+}
+
+static bool trans_LDAH(DisasContext *s, arg_LDA *a)
+{
+ return op_lda(s, a, MO_UW);
+}
+
+/*
+ * Media instructions
+ */
+
+static bool trans_USADA8(DisasContext *s, arg_USADA8 *a)
+{
+ TCGv_i32 t1, t2;
+
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ gen_helper_usad8(t1, t1, t2);
+ tcg_temp_free_i32(t2);
+ if (a->ra != 15) {
+ t2 = load_reg(s, a->ra);
+ tcg_gen_add_i32(t1, t1, t2);
+ tcg_temp_free_i32(t2);
+ }
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool op_bfx(DisasContext *s, arg_UBFX *a, bool u)
+{
+ TCGv_i32 tmp;
+ int width = a->widthm1 + 1;
+ int shift = a->lsb;
+
+ if (!ENABLE_ARCH_6T2) {
+ return false;
+ }
+ if (shift + width > 32) {
+ /* UNPREDICTABLE; we choose to UNDEF */
+ unallocated_encoding(s);
+ return true;
+ }
+
+ tmp = load_reg(s, a->rn);
+ if (u) {
+ tcg_gen_extract_i32(tmp, tmp, shift, width);
+ } else {
+ tcg_gen_sextract_i32(tmp, tmp, shift, width);
+ }
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_SBFX(DisasContext *s, arg_SBFX *a)
+{
+ return op_bfx(s, a, false);
+}
+
+static bool trans_UBFX(DisasContext *s, arg_UBFX *a)
+{
+ return op_bfx(s, a, true);
+}
+
+static bool trans_BFCI(DisasContext *s, arg_BFCI *a)
+{
+ TCGv_i32 tmp;
+ int msb = a->msb, lsb = a->lsb;
+ int width;
+
+ if (!ENABLE_ARCH_6T2) {
+ return false;
+ }
+ if (msb < lsb) {
+ /* UNPREDICTABLE; we choose to UNDEF */
+ unallocated_encoding(s);
+ return true;
+ }
+
+ width = msb + 1 - lsb;
+ if (a->rn == 15) {
+ /* BFC */
+ tmp = tcg_const_i32(0);
+ } else {
+ /* BFI */
+ tmp = load_reg(s, a->rn);
+ }
+ if (width != 32) {
+ TCGv_i32 tmp2 = load_reg(s, a->rd);
+ tcg_gen_deposit_i32(tmp, tmp2, tmp, lsb, width);
+ tcg_temp_free_i32(tmp2);
+ }
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_UDF(DisasContext *s, arg_UDF *a)
+{
+ unallocated_encoding(s);
+ return true;
+}
+
+/*
+ * Parallel addition and subtraction
+ */
+
+static bool op_par_addsub(DisasContext *s, arg_rrr *a,
+ void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
+{
+ TCGv_i32 t0, t1;
+
+ if (s->thumb
+ ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
+ : !ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t0 = load_reg(s, a->rn);
+ t1 = load_reg(s, a->rm);
+
+ gen(t0, t0, t1);
+
+ tcg_temp_free_i32(t1);
+ store_reg(s, a->rd, t0);
+ return true;
+}
+
+static bool op_par_addsub_ge(DisasContext *s, arg_rrr *a,
+ void (*gen)(TCGv_i32, TCGv_i32,
+ TCGv_i32, TCGv_ptr))
+{
+ TCGv_i32 t0, t1;
+ TCGv_ptr ge;
+
+ if (s->thumb
+ ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
+ : !ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t0 = load_reg(s, a->rn);
+ t1 = load_reg(s, a->rm);
+
+ ge = tcg_temp_new_ptr();
+ tcg_gen_addi_ptr(ge, cpu_env, offsetof(CPUARMState, GE));
+ gen(t0, t0, t1, ge);
+
+ tcg_temp_free_ptr(ge);
+ tcg_temp_free_i32(t1);
+ store_reg(s, a->rd, t0);
+ return true;
+}
+
+#define DO_PAR_ADDSUB(NAME, helper) \
+static bool trans_##NAME(DisasContext *s, arg_rrr *a) \
+{ \
+ return op_par_addsub(s, a, helper); \
+}
+
+#define DO_PAR_ADDSUB_GE(NAME, helper) \
+static bool trans_##NAME(DisasContext *s, arg_rrr *a) \
+{ \
+ return op_par_addsub_ge(s, a, helper); \
+}
+
+DO_PAR_ADDSUB_GE(SADD16, gen_helper_sadd16)
+DO_PAR_ADDSUB_GE(SASX, gen_helper_saddsubx)
+DO_PAR_ADDSUB_GE(SSAX, gen_helper_ssubaddx)
+DO_PAR_ADDSUB_GE(SSUB16, gen_helper_ssub16)
+DO_PAR_ADDSUB_GE(SADD8, gen_helper_sadd8)
+DO_PAR_ADDSUB_GE(SSUB8, gen_helper_ssub8)
+
+DO_PAR_ADDSUB_GE(UADD16, gen_helper_uadd16)
+DO_PAR_ADDSUB_GE(UASX, gen_helper_uaddsubx)
+DO_PAR_ADDSUB_GE(USAX, gen_helper_usubaddx)
+DO_PAR_ADDSUB_GE(USUB16, gen_helper_usub16)
+DO_PAR_ADDSUB_GE(UADD8, gen_helper_uadd8)
+DO_PAR_ADDSUB_GE(USUB8, gen_helper_usub8)
+
+DO_PAR_ADDSUB(QADD16, gen_helper_qadd16)
+DO_PAR_ADDSUB(QASX, gen_helper_qaddsubx)
+DO_PAR_ADDSUB(QSAX, gen_helper_qsubaddx)
+DO_PAR_ADDSUB(QSUB16, gen_helper_qsub16)
+DO_PAR_ADDSUB(QADD8, gen_helper_qadd8)
+DO_PAR_ADDSUB(QSUB8, gen_helper_qsub8)
+
+DO_PAR_ADDSUB(UQADD16, gen_helper_uqadd16)
+DO_PAR_ADDSUB(UQASX, gen_helper_uqaddsubx)
+DO_PAR_ADDSUB(UQSAX, gen_helper_uqsubaddx)
+DO_PAR_ADDSUB(UQSUB16, gen_helper_uqsub16)
+DO_PAR_ADDSUB(UQADD8, gen_helper_uqadd8)
+DO_PAR_ADDSUB(UQSUB8, gen_helper_uqsub8)
+
+DO_PAR_ADDSUB(SHADD16, gen_helper_shadd16)
+DO_PAR_ADDSUB(SHASX, gen_helper_shaddsubx)
+DO_PAR_ADDSUB(SHSAX, gen_helper_shsubaddx)
+DO_PAR_ADDSUB(SHSUB16, gen_helper_shsub16)
+DO_PAR_ADDSUB(SHADD8, gen_helper_shadd8)
+DO_PAR_ADDSUB(SHSUB8, gen_helper_shsub8)
+
+DO_PAR_ADDSUB(UHADD16, gen_helper_uhadd16)
+DO_PAR_ADDSUB(UHASX, gen_helper_uhaddsubx)
+DO_PAR_ADDSUB(UHSAX, gen_helper_uhsubaddx)
+DO_PAR_ADDSUB(UHSUB16, gen_helper_uhsub16)
+DO_PAR_ADDSUB(UHADD8, gen_helper_uhadd8)
+DO_PAR_ADDSUB(UHSUB8, gen_helper_uhsub8)
+
+#undef DO_PAR_ADDSUB
+#undef DO_PAR_ADDSUB_GE
+
+/*
+ * Packing, unpacking, saturation, and reversal
+ */
+
+static bool trans_PKH(DisasContext *s, arg_PKH *a)
+{
+ TCGv_i32 tn, tm;
+ int shift = a->imm;
+
+ if (s->thumb
+ ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
+ : !ENABLE_ARCH_6) {
+ return false;
+ }
+
+ tn = load_reg(s, a->rn);
+ tm = load_reg(s, a->rm);
+ if (a->tb) {
+ /* PKHTB */
+ if (shift == 0) {
+ shift = 31;
+ }
+ tcg_gen_sari_i32(tm, tm, shift);
+ tcg_gen_deposit_i32(tn, tn, tm, 0, 16);
+ } else {
+ /* PKHBT */
+ tcg_gen_shli_i32(tm, tm, shift);
+ tcg_gen_deposit_i32(tn, tm, tn, 0, 16);
+ }
+ tcg_temp_free_i32(tm);
+ store_reg(s, a->rd, tn);
+ return true;
+}
+
+static bool op_sat(DisasContext *s, arg_sat *a,
+ void (*gen)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
+{
+ TCGv_i32 tmp, satimm;
+ int shift = a->imm;
+
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+
+ tmp = load_reg(s, a->rn);
+ if (a->sh) {
+ tcg_gen_sari_i32(tmp, tmp, shift ? shift : 31);
+ } else {
+ tcg_gen_shli_i32(tmp, tmp, shift);
+ }
+
+ satimm = tcg_const_i32(a->satimm);
+ gen(tmp, cpu_env, tmp, satimm);
+ tcg_temp_free_i32(satimm);
+
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_SSAT(DisasContext *s, arg_sat *a)
+{
+ return op_sat(s, a, gen_helper_ssat);
+}
+
+static bool trans_USAT(DisasContext *s, arg_sat *a)
+{
+ return op_sat(s, a, gen_helper_usat);
+}
+
+static bool trans_SSAT16(DisasContext *s, arg_sat *a)
+{
+ if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+ return false;
+ }
+ return op_sat(s, a, gen_helper_ssat16);
+}
+
+static bool trans_USAT16(DisasContext *s, arg_sat *a)
+{
+ if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+ return false;
+ }
+ return op_sat(s, a, gen_helper_usat16);
+}
+
+static bool op_xta(DisasContext *s, arg_rrr_rot *a,
+ void (*gen_extract)(TCGv_i32, TCGv_i32),
+ void (*gen_add)(TCGv_i32, TCGv_i32, TCGv_i32))
+{
+ TCGv_i32 tmp;
+
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+
+ tmp = load_reg(s, a->rm);
+ /*
+ * TODO: In many cases we could do a shift instead of a rotate.
+ * Combined with a simple extend, that becomes an extract.
+ */
+ tcg_gen_rotri_i32(tmp, tmp, a->rot * 8);
+ gen_extract(tmp, tmp);
+
+ if (a->rn != 15) {
+ TCGv_i32 tmp2 = load_reg(s, a->rn);
+ gen_add(tmp, tmp, tmp2);
+ tcg_temp_free_i32(tmp2);
+ }
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_SXTAB(DisasContext *s, arg_rrr_rot *a)
+{
+ return op_xta(s, a, tcg_gen_ext8s_i32, tcg_gen_add_i32);
+}
+
+static bool trans_SXTAH(DisasContext *s, arg_rrr_rot *a)
+{
+ return op_xta(s, a, tcg_gen_ext16s_i32, tcg_gen_add_i32);
+}
+
+static bool trans_SXTAB16(DisasContext *s, arg_rrr_rot *a)
+{
+ if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+ return false;
+ }
+ return op_xta(s, a, gen_helper_sxtb16, gen_add16);
+}
+
+static bool trans_UXTAB(DisasContext *s, arg_rrr_rot *a)
+{
+ return op_xta(s, a, tcg_gen_ext8u_i32, tcg_gen_add_i32);
+}
+
+static bool trans_UXTAH(DisasContext *s, arg_rrr_rot *a)
+{
+ return op_xta(s, a, tcg_gen_ext16u_i32, tcg_gen_add_i32);
+}
+
+static bool trans_UXTAB16(DisasContext *s, arg_rrr_rot *a)
+{
+ if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+ return false;
+ }
+ return op_xta(s, a, gen_helper_uxtb16, gen_add16);
+}
+
+static bool trans_SEL(DisasContext *s, arg_rrr *a)
+{
+ TCGv_i32 t1, t2, t3;
+
+ if (s->thumb
+ ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
+ : !ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ t3 = tcg_temp_new_i32();
+ tcg_gen_ld_i32(t3, cpu_env, offsetof(CPUARMState, GE));
+ gen_helper_sel_flags(t1, t3, t1, t2);
+ tcg_temp_free_i32(t3);
+ tcg_temp_free_i32(t2);
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool op_rr(DisasContext *s, arg_rr *a,
+ void (*gen)(TCGv_i32, TCGv_i32))
+{
+ TCGv_i32 tmp;
+
+ tmp = load_reg(s, a->rm);
+ gen(tmp, tmp);
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_REV(DisasContext *s, arg_rr *a)
+{
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+ return op_rr(s, a, tcg_gen_bswap32_i32);
+}
+
+static bool trans_REV16(DisasContext *s, arg_rr *a)
+{
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+ return op_rr(s, a, gen_rev16);
+}
+
+static bool trans_REVSH(DisasContext *s, arg_rr *a)
+{
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+ return op_rr(s, a, gen_revsh);
+}
+
+static bool trans_RBIT(DisasContext *s, arg_rr *a)
+{
+ if (!ENABLE_ARCH_6T2) {
+ return false;
+ }
+ return op_rr(s, a, gen_helper_rbit);
+}
+
+/*
+ * Signed multiply, signed and unsigned divide
+ */
+
+static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub)
+{
+ TCGv_i32 t1, t2;
+
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ if (m_swap) {
+ gen_swap_half(t2);
+ }
+ gen_smul_dual(t1, t2);
+
+ if (sub) {
+ /* This subtraction cannot overflow. */
+ tcg_gen_sub_i32(t1, t1, t2);
+ } else {
+ /*
+ * This addition cannot overflow 32 bits; however it may
+ * overflow considered as a signed operation, in which case
+ * we must set the Q flag.
+ */
+ gen_helper_add_setq(t1, cpu_env, t1, t2);
+ }
+ tcg_temp_free_i32(t2);
+
+ if (a->ra != 15) {
+ t2 = load_reg(s, a->ra);
+ gen_helper_add_setq(t1, cpu_env, t1, t2);
+ tcg_temp_free_i32(t2);
+ }
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool trans_SMLAD(DisasContext *s, arg_rrrr *a)
+{
+ return op_smlad(s, a, false, false);
+}
+
+static bool trans_SMLADX(DisasContext *s, arg_rrrr *a)
+{
+ return op_smlad(s, a, true, false);
+}
+
+static bool trans_SMLSD(DisasContext *s, arg_rrrr *a)
+{
+ return op_smlad(s, a, false, true);
+}
+
+static bool trans_SMLSDX(DisasContext *s, arg_rrrr *a)
+{
+ return op_smlad(s, a, true, true);
+}
+
+static bool op_smlald(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub)
+{
+ TCGv_i32 t1, t2;
+ TCGv_i64 l1, l2;
+
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ if (m_swap) {
+ gen_swap_half(t2);
+ }
+ gen_smul_dual(t1, t2);
+
+ l1 = tcg_temp_new_i64();
+ l2 = tcg_temp_new_i64();
+ tcg_gen_ext_i32_i64(l1, t1);
+ tcg_gen_ext_i32_i64(l2, t2);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+
+ if (sub) {
+ tcg_gen_sub_i64(l1, l1, l2);
+ } else {
+ tcg_gen_add_i64(l1, l1, l2);
+ }
+ tcg_temp_free_i64(l2);
+
+ gen_addq(s, l1, a->ra, a->rd);
+ gen_storeq_reg(s, a->ra, a->rd, l1);
+ tcg_temp_free_i64(l1);
+ return true;
+}
+
+static bool trans_SMLALD(DisasContext *s, arg_rrrr *a)
+{
+ return op_smlald(s, a, false, false);
+}
+
+static bool trans_SMLALDX(DisasContext *s, arg_rrrr *a)
+{
+ return op_smlald(s, a, true, false);
+}
+
+static bool trans_SMLSLD(DisasContext *s, arg_rrrr *a)
+{
+ return op_smlald(s, a, false, true);
+}
+
+static bool trans_SMLSLDX(DisasContext *s, arg_rrrr *a)
+{
+ return op_smlald(s, a, true, true);
+}
+
+static bool op_smmla(DisasContext *s, arg_rrrr *a, bool round, bool sub)
+{
+ TCGv_i32 t1, t2;
+
+ if (s->thumb
+ ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
+ : !ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ tcg_gen_muls2_i32(t2, t1, t1, t2);
+
+ if (a->ra != 15) {
+ TCGv_i32 t3 = load_reg(s, a->ra);
+ if (sub) {
+ /*
+ * For SMMLS, we need a 64-bit subtract. Borrow caused by
+ * a non-zero multiplicand lowpart, and the correct result
+ * lowpart for rounding.
+ */
+ TCGv_i32 zero = tcg_const_i32(0);
+ tcg_gen_sub2_i32(t2, t1, zero, t3, t2, t1);
+ tcg_temp_free_i32(zero);
+ } else {
+ tcg_gen_add_i32(t1, t1, t3);
+ }
+ tcg_temp_free_i32(t3);
+ }
+ if (round) {
+ /*
+ * Adding 0x80000000 to the 64-bit quantity means that we have
+ * carry in to the high word when the low word has the msb set.
+ */
+ tcg_gen_shri_i32(t2, t2, 31);
+ tcg_gen_add_i32(t1, t1, t2);
+ }
+ tcg_temp_free_i32(t2);
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool trans_SMMLA(DisasContext *s, arg_rrrr *a)
+{
+ return op_smmla(s, a, false, false);
+}
+
+static bool trans_SMMLAR(DisasContext *s, arg_rrrr *a)
+{
+ return op_smmla(s, a, true, false);
+}
+
+static bool trans_SMMLS(DisasContext *s, arg_rrrr *a)
+{
+ return op_smmla(s, a, false, true);
+}
+
+static bool trans_SMMLSR(DisasContext *s, arg_rrrr *a)
+{
+ return op_smmla(s, a, true, true);
+}
+
+static bool op_div(DisasContext *s, arg_rrr *a, bool u)
+{
+ TCGv_i32 t1, t2;
+
+ if (s->thumb
+ ? !dc_isar_feature(thumb_div, s)
+ : !dc_isar_feature(arm_div, s)) {
+ return false;
+ }
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ if (u) {
+ gen_helper_udiv(t1, t1, t2);
+ } else {
+ gen_helper_sdiv(t1, t1, t2);
+ }
+ tcg_temp_free_i32(t2);
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool trans_SDIV(DisasContext *s, arg_rrr *a)
+{
+ return op_div(s, a, false);
+}
+
+static bool trans_UDIV(DisasContext *s, arg_rrr *a)
+{
+ return op_div(s, a, true);
+}
+
+/*
+ * Block data transfer
+ */
+
+static TCGv_i32 op_addr_block_pre(DisasContext *s, arg_ldst_block *a, int n)
+{
+ TCGv_i32 addr = load_reg(s, a->rn);
+
+ if (a->b) {
+ if (a->i) {
+ /* pre increment */
+ tcg_gen_addi_i32(addr, addr, 4);
+ } else {
+ /* pre decrement */
+ tcg_gen_addi_i32(addr, addr, -(n * 4));
+ }
+ } else if (!a->i && n != 1) {
+ /* post decrement */
+ tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+ }
+
+ if (s->v8m_stackcheck && a->rn == 13 && a->w) {
+ /*
+ * If the writeback is incrementing SP rather than
+ * decrementing it, and the initial SP is below the
+ * stack limit but the final written-back SP would
+ * be above, then then we must not perform any memory
+ * accesses, but it is IMPDEF whether we generate
+ * an exception. We choose to do so in this case.
+ * At this point 'addr' is the lowest address, so
+ * either the original SP (if incrementing) or our
+ * final SP (if decrementing), so that's what we check.
+ */
+ gen_helper_v8m_stackcheck(cpu_env, addr);
+ }
+
+ return addr;
+}
+
+static void op_addr_block_post(DisasContext *s, arg_ldst_block *a,
+ TCGv_i32 addr, int n)
+{
+ if (a->w) {
+ /* write back */
+ if (!a->b) {
+ if (a->i) {
+ /* post increment */
+ tcg_gen_addi_i32(addr, addr, 4);
+ } else {
+ /* post decrement */
+ tcg_gen_addi_i32(addr, addr, -(n * 4));
+ }
+ } else if (!a->i && n != 1) {
+ /* pre decrement */
+ tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
+ }
+ store_reg(s, a->rn, addr);
+ } else {
+ tcg_temp_free_i32(addr);
+ }
+}
+
+static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n)
+{
+ int i, j, n, list, mem_idx;
+ bool user = a->u;
+ TCGv_i32 addr, tmp, tmp2;
+
+ if (user) {
+ /* STM (user) */
+ if (IS_USER(s)) {
+ /* Only usable in supervisor mode. */
+ unallocated_encoding(s);
+ return true;
+ }
+ }
+
+ list = a->list;
+ n = ctpop16(list);
+ if (n < min_n || a->rn == 15) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ addr = op_addr_block_pre(s, a, n);
+ mem_idx = get_mem_index(s);
+
+ for (i = j = 0; i < 16; i++) {
+ if (!(list & (1 << i))) {
+ continue;
+ }
+
+ if (user && i != 15) {
+ tmp = tcg_temp_new_i32();
+ tmp2 = tcg_const_i32(i);
+ gen_helper_get_user_reg(tmp, cpu_env, tmp2);
+ tcg_temp_free_i32(tmp2);
+ } else {
+ tmp = load_reg(s, i);
+ }
+ gen_aa32_st32(s, tmp, addr, mem_idx);
+ tcg_temp_free_i32(tmp);
+
+ /* No need to add after the last transfer. */
+ if (++j != n) {
+ tcg_gen_addi_i32(addr, addr, 4);
+ }
+ }
+
+ op_addr_block_post(s, a, addr, n);
+ return true;
+}
+
+static bool trans_STM(DisasContext *s, arg_ldst_block *a)
+{
+ /* BitCount(list) < 1 is UNPREDICTABLE */
+ return op_stm(s, a, 1);
+}
+
+static bool trans_STM_t32(DisasContext *s, arg_ldst_block *a)
+{
+ /* Writeback register in register list is UNPREDICTABLE for T32. */
+ if (a->w && (a->list & (1 << a->rn))) {
+ unallocated_encoding(s);
+ return true;
+ }
+ /* BitCount(list) < 2 is UNPREDICTABLE */
+ return op_stm(s, a, 2);
+}
+
+static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n)
+{
+ int i, j, n, list, mem_idx;
+ bool loaded_base;
+ bool user = a->u;
+ bool exc_return = false;
+ TCGv_i32 addr, tmp, tmp2, loaded_var;
+
+ if (user) {
+ /* LDM (user), LDM (exception return) */
+ if (IS_USER(s)) {
+ /* Only usable in supervisor mode. */
+ unallocated_encoding(s);
+ return true;
+ }
+ if (extract32(a->list, 15, 1)) {
+ exc_return = true;
+ user = false;
+ } else {
+ /* LDM (user) does not allow writeback. */
+ if (a->w) {
+ unallocated_encoding(s);
+ return true;
+ }
+ }
+ }
+
+ list = a->list;
+ n = ctpop16(list);
+ if (n < min_n || a->rn == 15) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ addr = op_addr_block_pre(s, a, n);
+ mem_idx = get_mem_index(s);
+ loaded_base = false;
+ loaded_var = NULL;
+
+ for (i = j = 0; i < 16; i++) {
+ if (!(list & (1 << i))) {
+ continue;
+ }
+
+ tmp = tcg_temp_new_i32();
+ gen_aa32_ld32u(s, tmp, addr, mem_idx);
+ if (user) {
+ tmp2 = tcg_const_i32(i);
+ gen_helper_set_user_reg(cpu_env, tmp2, tmp);
+ tcg_temp_free_i32(tmp2);
+ tcg_temp_free_i32(tmp);
+ } else if (i == a->rn) {
+ loaded_var = tmp;
+ loaded_base = true;
+ } else if (i == 15 && exc_return) {
+ store_pc_exc_ret(s, tmp);
+ } else {
+ store_reg_from_load(s, i, tmp);
+ }
+
+ /* No need to add after the last transfer. */
+ if (++j != n) {
+ tcg_gen_addi_i32(addr, addr, 4);
+ }
+ }
+
+ op_addr_block_post(s, a, addr, n);
+
+ if (loaded_base) {
+ /* Note that we reject base == pc above. */
+ store_reg(s, a->rn, loaded_var);
+ }
+
+ if (exc_return) {
+ /* Restore CPSR from SPSR. */
+ tmp = load_cpu_field(spsr);
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_cpsr_write_eret(cpu_env, tmp);
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_io_end();
+ }
+ tcg_temp_free_i32(tmp);
+ /* Must exit loop to check un-masked IRQs */
+ s->base.is_jmp = DISAS_EXIT;
+ }
+ return true;
+}
+
+static bool trans_LDM_a32(DisasContext *s, arg_ldst_block *a)
+{
+ /*
+ * Writeback register in register list is UNPREDICTABLE
+ * for ArchVersion() >= 7. Prior to v7, A32 would write
+ * an UNKNOWN value to the base register.
+ */
+ if (ENABLE_ARCH_7 && a->w && (a->list & (1 << a->rn))) {
+ unallocated_encoding(s);
+ return true;
+ }
+ /* BitCount(list) < 1 is UNPREDICTABLE */
+ return do_ldm(s, a, 1);
+}
+
+static bool trans_LDM_t32(DisasContext *s, arg_ldst_block *a)
+{
+ /* Writeback register in register list is UNPREDICTABLE for T32. */
+ if (a->w && (a->list & (1 << a->rn))) {
+ unallocated_encoding(s);
+ return true;
+ }
+ /* BitCount(list) < 2 is UNPREDICTABLE */
+ return do_ldm(s, a, 2);
+}
+
+static bool trans_LDM_t16(DisasContext *s, arg_ldst_block *a)
+{
+ /* Writeback is conditional on the base register not being loaded. */
+ a->w = !(a->list & (1 << a->rn));
+ /* BitCount(list) < 1 is UNPREDICTABLE */
+ return do_ldm(s, a, 1);
+}
+
+/*
+ * Branch, branch with link
+ */
+
+static bool trans_B(DisasContext *s, arg_i *a)
+{
+ gen_jmp(s, read_pc(s) + a->imm);
+ return true;
+}
+
+static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a)
+{
+ /* This has cond from encoding, required to be outside IT block. */
+ if (a->cond >= 0xe) {
+ return false;
+ }
+ if (s->condexec_mask) {
+ unallocated_encoding(s);
+ return true;
+ }
+ arm_skip_unless(s, a->cond);
+ gen_jmp(s, read_pc(s) + a->imm);
+ return true;
+}
+
+static bool trans_BL(DisasContext *s, arg_i *a)
+{
+ tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
+ gen_jmp(s, read_pc(s) + a->imm);
+ return true;
+}
+
+static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
+{
+ TCGv_i32 tmp;
+
+ /* For A32, ARCH(5) is checked near the start of the uncond block. */
+ if (s->thumb && (a->imm & 2)) {
+ return false;
+ }
+ tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
+ tmp = tcg_const_i32(!s->thumb);
+ store_cpu_field(tmp, thumb);
+ gen_jmp(s, (read_pc(s) & ~3) + a->imm);
+ return true;
+}
+
+static bool trans_BL_BLX_prefix(DisasContext *s, arg_BL_BLX_prefix *a)
+{
+ assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
+ tcg_gen_movi_i32(cpu_R[14], read_pc(s) + (a->imm << 12));
+ return true;
+}
+
+static bool trans_BL_suffix(DisasContext *s, arg_BL_suffix *a)
+{
+ TCGv_i32 tmp = tcg_temp_new_i32();
+
+ assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
+ tcg_gen_addi_i32(tmp, cpu_R[14], (a->imm << 1) | 1);
+ tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
+ gen_bx(s, tmp);
+ return true;
+}
+
+static bool trans_BLX_suffix(DisasContext *s, arg_BLX_suffix *a)
+{
+ TCGv_i32 tmp;
+
+ assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
+ if (!ENABLE_ARCH_5) {
+ return false;
+ }
+ tmp = tcg_temp_new_i32();
+ tcg_gen_addi_i32(tmp, cpu_R[14], a->imm << 1);
+ tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
+ tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
+ gen_bx(s, tmp);
+ return true;
+}
+
+static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half)
+{
+ TCGv_i32 addr, tmp;
+
+ tmp = load_reg(s, a->rm);
+ if (half) {
+ tcg_gen_add_i32(tmp, tmp, tmp);
+ }
+ addr = load_reg(s, a->rn);
+ tcg_gen_add_i32(addr, addr, tmp);
+
+ gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
+ half ? MO_UW | s->be_data : MO_UB);
+ tcg_temp_free_i32(addr);
+
+ tcg_gen_add_i32(tmp, tmp, tmp);
+ tcg_gen_addi_i32(tmp, tmp, read_pc(s));
+ store_reg(s, 15, tmp);
+ return true;
+}
+
+static bool trans_TBB(DisasContext *s, arg_tbranch *a)
+{
+ return op_tbranch(s, a, false);
+}
+
+static bool trans_TBH(DisasContext *s, arg_tbranch *a)
+{
+ return op_tbranch(s, a, true);
+}
+
+static bool trans_CBZ(DisasContext *s, arg_CBZ *a)
+{
+ TCGv_i32 tmp = load_reg(s, a->rn);
+
+ arm_gen_condlabel(s);
+ tcg_gen_brcondi_i32(a->nz ? TCG_COND_EQ : TCG_COND_NE,
+ tmp, 0, s->condlabel);
+ tcg_temp_free_i32(tmp);
+ gen_jmp(s, read_pc(s) + a->imm);
+ return true;
+}
+
+/*
+ * Supervisor call
+ */
+
+static bool trans_SVC(DisasContext *s, arg_SVC *a)
+{
+ gen_set_pc_im(s, s->base.pc_next);
+ s->svc_imm = a->imm;
+ s->base.is_jmp = DISAS_SWI;
+ return true;
+}
+
+/*
+ * Unconditional system instructions
+ */
+
+static bool trans_RFE(DisasContext *s, arg_RFE *a)
+{
+ static const int8_t pre_offset[4] = {
+ /* DA */ -4, /* IA */ 0, /* DB */ -8, /* IB */ 4
+ };
+ static const int8_t post_offset[4] = {
+ /* DA */ -8, /* IA */ 4, /* DB */ -4, /* IB */ 0
+ };
+ TCGv_i32 addr, t1, t2;
+
+ if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ if (IS_USER(s)) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ addr = load_reg(s, a->rn);
+ tcg_gen_addi_i32(addr, addr, pre_offset[a->pu]);
+
+ /* Load PC into tmp and CPSR into tmp2. */
+ t1 = tcg_temp_new_i32();
+ gen_aa32_ld32u(s, t1, addr, get_mem_index(s));
+ tcg_gen_addi_i32(addr, addr, 4);
+ t2 = tcg_temp_new_i32();
+ gen_aa32_ld32u(s, t2, addr, get_mem_index(s));
+
+ if (a->w) {
+ /* Base writeback. */
+ tcg_gen_addi_i32(addr, addr, post_offset[a->pu]);
+ store_reg(s, a->rn, addr);
+ } else {
+ tcg_temp_free_i32(addr);
+ }
+ gen_rfe(s, t1, t2);
+ return true;
+}
+
+static bool trans_SRS(DisasContext *s, arg_SRS *a)
+{
+ if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ gen_srs(s, a->mode, a->pu, a->w);
+ return true;
+}
+
+static bool trans_CPS(DisasContext *s, arg_CPS *a)
+{
+ uint32_t mask, val;
+
+ if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ if (IS_USER(s)) {
+ /* Implemented as NOP in user mode. */
+ return true;
+ }
+ /* TODO: There are quite a lot of UNPREDICTABLE argument combinations. */
+
+ mask = val = 0;
+ if (a->imod & 2) {
+ if (a->A) {
+ mask |= CPSR_A;
+ }
+ if (a->I) {
+ mask |= CPSR_I;
+ }
+ if (a->F) {
+ mask |= CPSR_F;
+ }
+ if (a->imod & 1) {
+ val |= mask;
+ }
+ }
+ if (a->M) {
+ mask |= CPSR_M;
+ val |= a->mode;
+ }
+ if (mask) {
+ gen_set_psr_im(s, mask, 0, val);
+ }
+ return true;
+}
+
+static bool trans_CPS_v7m(DisasContext *s, arg_CPS_v7m *a)
+{
+ TCGv_i32 tmp, addr;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ if (IS_USER(s)) {
+ /* Implemented as NOP in user mode. */
+ return true;
+ }
+
+ tmp = tcg_const_i32(a->im);
+ /* FAULTMASK */
+ if (a->F) {
+ addr = tcg_const_i32(19);
+ gen_helper_v7m_msr(cpu_env, addr, tmp);
+ tcg_temp_free_i32(addr);
+ }
+ /* PRIMASK */
+ if (a->I) {
+ addr = tcg_const_i32(16);
+ gen_helper_v7m_msr(cpu_env, addr, tmp);
+ tcg_temp_free_i32(addr);
+ }
+ tcg_temp_free_i32(tmp);
+ gen_lookup_tb(s);
+ return true;
+}
+
+/*
+ * Clear-Exclusive, Barriers
+ */
+
+static bool trans_CLREX(DisasContext *s, arg_CLREX *a)
+{
+ if (s->thumb
+ ? !ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M)
+ : !ENABLE_ARCH_6K) {
+ return false;
+ }
+ gen_clrex(s);
+ return true;
+}
+
+static bool trans_DSB(DisasContext *s, arg_DSB *a)
+{
+ if (!ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
+ return true;
+}
+
+static bool trans_DMB(DisasContext *s, arg_DMB *a)
+{
+ return trans_DSB(s, NULL);
+}
+
+static bool trans_ISB(DisasContext *s, arg_ISB *a)
+{
+ if (!ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ /*
+ * We need to break the TB after this insn to execute
+ * self-modifying code correctly and also to take
+ * any pending interrupts immediately.
+ */
+ gen_goto_tb(s, 0, s->base.pc_next);
+ return true;
+}
+
+static bool trans_SB(DisasContext *s, arg_SB *a)
+{
+ if (!dc_isar_feature(aa32_sb, s)) {
+ return false;
+ }
+ /*
+ * TODO: There is no speculation barrier opcode
+ * for TCG; MB and end the TB instead.
+ */
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
+ gen_goto_tb(s, 0, s->base.pc_next);
+ return true;
+}
+
+static bool trans_SETEND(DisasContext *s, arg_SETEND *a)
+{
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+ if (a->E != (s->be_data == MO_BE)) {
+ gen_helper_setend(cpu_env);
+ s->base.is_jmp = DISAS_UPDATE;
+ }
+ return true;
+}
+
+/*
+ * Preload instructions
+ * All are nops, contingent on the appropriate arch level.
+ */
+
+static bool trans_PLD(DisasContext *s, arg_PLD *a)
+{
+ return ENABLE_ARCH_5TE;
+}
+
+static bool trans_PLDW(DisasContext *s, arg_PLD *a)
+{
+ return arm_dc_feature(s, ARM_FEATURE_V7MP);
+}
+
+static bool trans_PLI(DisasContext *s, arg_PLD *a)
+{
+ return ENABLE_ARCH_7;
+}
+
+/*
+ * If-then
+ */
+
+static bool trans_IT(DisasContext *s, arg_IT *a)
+{
+ int cond_mask = a->cond_mask;
+
+ /*
+ * No actual code generated for this insn, just setup state.
+ *
+ * Combinations of firstcond and mask which set up an 0b1111
+ * condition are UNPREDICTABLE; we take the CONSTRAINED
+ * UNPREDICTABLE choice to treat 0b1111 the same as 0b1110,
+ * i.e. both meaning "execute always".
+ */
+ s->condexec_cond = (cond_mask >> 4) & 0xe;
+ s->condexec_mask = cond_mask & 0x1f;
+ return true;
+}
+
+/*
+ * Legacy decoder.
+ */
+
+static void disas_arm_insn(DisasContext *s, unsigned int insn)
+{
+ unsigned int cond = insn >> 28;
/* M variants do not implement ARM mode; this must raise the INVSTATE
* UsageFault exception.
@@ -7674,8 +10470,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
default_exception_el(s));
return;
}
- cond = insn >> 28;
- if (cond == 0xf){
+
+ if (cond == 0xf) {
/* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
* choose to UNDEF. In ARMv5 and above the space is used
* for miscellaneous unconditional instructions.
@@ -7683,6 +10479,11 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
ARCH(5);
/* Unconditional instructions. */
+ if (disas_a32_uncond(s, insn)) {
+ return;
+ }
+ /* fall back to legacy decoder */
+
if (((insn >> 25) & 7) == 1) {
/* NEON Data processing. */
if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
@@ -7712,133 +10513,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
return;
}
- if (((insn & 0x0f30f000) == 0x0510f000) ||
- ((insn & 0x0f30f010) == 0x0710f000)) {
- if ((insn & (1 << 22)) == 0) {
- /* PLDW; v7MP */
- if (!arm_dc_feature(s, ARM_FEATURE_V7MP)) {
- goto illegal_op;
- }
- }
- /* Otherwise PLD; v5TE+ */
- ARCH(5TE);
- return;
- }
- if (((insn & 0x0f70f000) == 0x0450f000) ||
- ((insn & 0x0f70f010) == 0x0650f000)) {
- ARCH(7);
- return; /* PLI; V7 */
- }
- if (((insn & 0x0f700000) == 0x04100000) ||
- ((insn & 0x0f700010) == 0x06100000)) {
- if (!arm_dc_feature(s, ARM_FEATURE_V7MP)) {
- goto illegal_op;
- }
- return; /* v7MP: Unallocated memory hint: must NOP */
- }
-
- if ((insn & 0x0ffffdff) == 0x01010000) {
- ARCH(6);
- /* setend */
- if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
- gen_helper_setend(cpu_env);
- s->base.is_jmp = DISAS_UPDATE;
- }
- return;
- } else if ((insn & 0x0fffff00) == 0x057ff000) {
- switch ((insn >> 4) & 0xf) {
- case 1: /* clrex */
- ARCH(6K);
- gen_clrex(s);
- return;
- case 4: /* dsb */
- case 5: /* dmb */
- ARCH(7);
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
- return;
- case 6: /* isb */
- /* We need to break the TB after this insn to execute
- * self-modifying code correctly and also to take
- * any pending interrupts immediately.
- */
- gen_goto_tb(s, 0, s->base.pc_next);
- return;
- case 7: /* sb */
- if ((insn & 0xf) || !dc_isar_feature(aa32_sb, s)) {
- goto illegal_op;
- }
- /*
- * TODO: There is no speculation barrier opcode
- * for TCG; MB and end the TB instead.
- */
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
- gen_goto_tb(s, 0, s->base.pc_next);
- return;
- default:
- goto illegal_op;
- }
- } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
- /* srs */
- ARCH(6);
- gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));
- return;
- } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
- /* rfe */
- int32_t offset;
- if (IS_USER(s))
- goto illegal_op;
- ARCH(6);
- rn = (insn >> 16) & 0xf;
- addr = load_reg(s, rn);
- i = (insn >> 23) & 3;
- switch (i) {
- case 0: offset = -4; break; /* DA */
- case 1: offset = 0; break; /* IA */
- case 2: offset = -8; break; /* DB */
- case 3: offset = 4; break; /* IB */
- default: abort();
- }
- if (offset)
- tcg_gen_addi_i32(addr, addr, offset);
- /* Load PC into tmp and CPSR into tmp2. */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- tcg_gen_addi_i32(addr, addr, 4);
- tmp2 = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
- if (insn & (1 << 21)) {
- /* Base writeback. */
- switch (i) {
- case 0: offset = -8; break;
- case 1: offset = 4; break;
- case 2: offset = -4; break;
- case 3: offset = 0; break;
- default: abort();
- }
- if (offset)
- tcg_gen_addi_i32(addr, addr, offset);
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- gen_rfe(s, tmp, tmp2);
- return;
- } else if ((insn & 0x0e000000) == 0x0a000000) {
- /* branch link and change to thumb (blx <offset>) */
- int32_t offset;
-
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, s->base.pc_next);
- store_reg(s, 14, tmp);
- /* Sign-extend the 24-bit offset */
- offset = (((int32_t)insn) << 8) >> 8;
- val = read_pc(s);
- /* offset * 4 + bit24 * 2 + (thumb bit) */
- val += (offset << 2) | ((insn >> 23) & 2) | 1;
- /* protected by ARCH(5); above, near the start of uncond block */
- gen_bx_im(s, val);
- return;
- } else if ((insn & 0x0e000f00) == 0x0c000100) {
+ if ((insn & 0x0e000f00) == 0x0c000100) {
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
/* iWMMXt register transfer. */
if (extract32(s->c15_cpar, 1, 1)) {
@@ -7859,36 +10534,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
goto illegal_op;
}
return;
- } else if ((insn & 0x0fe00000) == 0x0c400000) {
- /* Coprocessor double register transfer. */
- ARCH(5TE);
- } else if ((insn & 0x0f000010) == 0x0e000010) {
- /* Additional coprocessor register transfer. */
- } else if ((insn & 0x0ff10020) == 0x01000000) {
- uint32_t mask;
- uint32_t val;
- /* cps (privileged) */
- if (IS_USER(s))
- return;
- mask = val = 0;
- if (insn & (1 << 19)) {
- if (insn & (1 << 8))
- mask |= CPSR_A;
- if (insn & (1 << 7))
- mask |= CPSR_I;
- if (insn & (1 << 6))
- mask |= CPSR_F;
- if (insn & (1 << 18))
- val |= mask;
- }
- if (insn & (1 << 17)) {
- mask |= CPSR_M;
- val |= (insn & 0x1f);
- }
- if (mask) {
- gen_set_psr_im(s, mask, 0, val);
- }
- return;
}
goto illegal_op;
}
@@ -7897,1313 +10542,30 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
next instruction */
arm_skip_unless(s, cond);
}
- if ((insn & 0x0f900000) == 0x03000000) {
- if ((insn & (1 << 21)) == 0) {
- ARCH(6T2);
- rd = (insn >> 12) & 0xf;
- val = ((insn >> 4) & 0xf000) | (insn & 0xfff);
- if ((insn & (1 << 22)) == 0) {
- /* MOVW */
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, val);
- } else {
- /* MOVT */
- tmp = load_reg(s, rd);
- tcg_gen_ext16u_i32(tmp, tmp);
- tcg_gen_ori_i32(tmp, tmp, val << 16);
- }
- store_reg(s, rd, tmp);
- } else {
- if (((insn >> 12) & 0xf) != 0xf)
- goto illegal_op;
- if (((insn >> 16) & 0xf) == 0) {
- gen_nop_hint(s, insn & 0xff);
- } else {
- /* CPSR = immediate */
- val = insn & 0xff;
- shift = ((insn >> 8) & 0xf) * 2;
- val = ror32(val, shift);
- i = ((insn & (1 << 22)) != 0);
- if (gen_set_psr_im(s, msr_mask(s, (insn >> 16) & 0xf, i),
- i, val)) {
- goto illegal_op;
- }
- }
- }
- } else if ((insn & 0x0f900000) == 0x01000000
- && (insn & 0x00000090) != 0x00000090) {
- /* miscellaneous instructions */
- op1 = (insn >> 21) & 3;
- sh = (insn >> 4) & 0xf;
- rm = insn & 0xf;
- switch (sh) {
- case 0x0: /* MSR, MRS */
- if (insn & (1 << 9)) {
- /* MSR (banked) and MRS (banked) */
- int sysm = extract32(insn, 16, 4) |
- (extract32(insn, 8, 1) << 4);
- int r = extract32(insn, 22, 1);
-
- if (op1 & 1) {
- /* MSR (banked) */
- gen_msr_banked(s, r, sysm, rm);
- } else {
- /* MRS (banked) */
- int rd = extract32(insn, 12, 4);
-
- gen_mrs_banked(s, r, sysm, rd);
- }
- break;
- }
-
- /* MSR, MRS (for PSRs) */
- if (op1 & 1) {
- /* PSR = reg */
- tmp = load_reg(s, rm);
- i = ((op1 & 2) != 0);
- if (gen_set_psr(s, msr_mask(s, (insn >> 16) & 0xf, i), i, tmp))
- goto illegal_op;
- } else {
- /* reg = PSR */
- rd = (insn >> 12) & 0xf;
- if (op1 & 2) {
- if (IS_USER(s))
- goto illegal_op;
- tmp = load_cpu_field(spsr);
- } else {
- tmp = tcg_temp_new_i32();
- gen_helper_cpsr_read(tmp, cpu_env);
- }
- store_reg(s, rd, tmp);
- }
- break;
- case 0x1:
- if (op1 == 1) {
- /* branch/exchange thumb (bx). */
- ARCH(4T);
- tmp = load_reg(s, rm);
- gen_bx(s, tmp);
- } else if (op1 == 3) {
- /* clz */
- ARCH(5);
- rd = (insn >> 12) & 0xf;
- tmp = load_reg(s, rm);
- tcg_gen_clzi_i32(tmp, tmp, 32);
- store_reg(s, rd, tmp);
- } else {
- goto illegal_op;
- }
- break;
- case 0x2:
- if (op1 == 1) {
- ARCH(5J); /* bxj */
- /* Trivial implementation equivalent to bx. */
- tmp = load_reg(s, rm);
- gen_bx(s, tmp);
- } else {
- goto illegal_op;
- }
- break;
- case 0x3:
- if (op1 != 1)
- goto illegal_op;
-
- ARCH(5);
- /* branch link/exchange thumb (blx) */
- tmp = load_reg(s, rm);
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, s->base.pc_next);
- store_reg(s, 14, tmp2);
- gen_bx(s, tmp);
- break;
- case 0x4:
- {
- /* crc32/crc32c */
- uint32_t c = extract32(insn, 8, 4);
- /* Check this CPU supports ARMv8 CRC instructions.
- * op1 == 3 is UNPREDICTABLE but handle as UNDEFINED.
- * Bits 8, 10 and 11 should be zero.
- */
- if (!dc_isar_feature(aa32_crc32, s) || op1 == 0x3 || (c & 0xd) != 0) {
- goto illegal_op;
- }
-
- rn = extract32(insn, 16, 4);
- rd = extract32(insn, 12, 4);
+ if (disas_a32(s, insn)) {
+ return;
+ }
+ /* fall back to legacy decoder */
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- if (op1 == 0) {
- tcg_gen_andi_i32(tmp2, tmp2, 0xff);
- } else if (op1 == 1) {
- tcg_gen_andi_i32(tmp2, tmp2, 0xffff);
- }
- tmp3 = tcg_const_i32(1 << op1);
- if (c & 0x2) {
- gen_helper_crc32c(tmp, tmp, tmp2, tmp3);
- } else {
- gen_helper_crc32(tmp, tmp, tmp2, tmp3);
- }
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i32(tmp3);
- store_reg(s, rd, tmp);
- break;
- }
- case 0x5: /* saturating add/subtract */
- ARCH(5TE);
- rd = (insn >> 12) & 0xf;
- rn = (insn >> 16) & 0xf;
- tmp = load_reg(s, rm);
- tmp2 = load_reg(s, rn);
- if (op1 & 2)
- gen_helper_add_saturate(tmp2, cpu_env, tmp2, tmp2);
- if (op1 & 1)
- gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2);
- else
- gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- break;
- case 0x6: /* ERET */
- if (op1 != 3) {
- goto illegal_op;
- }
- if (!arm_dc_feature(s, ARM_FEATURE_V7VE)) {
- goto illegal_op;
- }
- if ((insn & 0x000fff0f) != 0x0000000e) {
- /* UNPREDICTABLE; we choose to UNDEF */
+ switch ((insn >> 24) & 0xf) {
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ if (((insn >> 8) & 0xe) == 10) {
+ /* VFP. */
+ if (disas_vfp_insn(s, insn)) {
goto illegal_op;
}
-
- if (s->current_el == 2) {
- tmp = load_cpu_field(elr_el[2]);
- } else {
- tmp = load_reg(s, 14);
- }
- gen_exception_return(s, tmp);
- break;
- case 7:
- {
- int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
- switch (op1) {
- case 0:
- /* HLT */
- gen_hlt(s, imm16);
- break;
- case 1:
- /* bkpt */
- ARCH(5);
- gen_exception_bkpt_insn(s, syn_aa32_bkpt(imm16, false));
- break;
- case 2:
- /* Hypervisor call (v7) */
- ARCH(7);
- if (IS_USER(s)) {
- goto illegal_op;
- }
- gen_hvc(s, imm16);
- break;
- case 3:
- /* Secure monitor call (v6+) */
- ARCH(6K);
- if (IS_USER(s)) {
- goto illegal_op;
- }
- gen_smc(s);
- break;
- default:
- g_assert_not_reached();
- }
- break;
- }
- case 0x8: /* signed multiply */
- case 0xa:
- case 0xc:
- case 0xe:
- ARCH(5TE);
- rs = (insn >> 8) & 0xf;
- rn = (insn >> 12) & 0xf;
- rd = (insn >> 16) & 0xf;
- if (op1 == 1) {
- /* (32 * 16) >> 16 */
- tmp = load_reg(s, rm);
- tmp2 = load_reg(s, rs);
- if (sh & 4)
- tcg_gen_sari_i32(tmp2, tmp2, 16);
- else
- gen_sxth(tmp2);
- tmp64 = gen_muls_i64_i32(tmp, tmp2);
- tcg_gen_shri_i64(tmp64, tmp64, 16);
- tmp = tcg_temp_new_i32();
- tcg_gen_extrl_i64_i32(tmp, tmp64);
- tcg_temp_free_i64(tmp64);
- if ((sh & 2) == 0) {
- tmp2 = load_reg(s, rn);
- gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- store_reg(s, rd, tmp);
- } else {
- /* 16 * 16 */
- tmp = load_reg(s, rm);
- tmp2 = load_reg(s, rs);
- gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
- tcg_temp_free_i32(tmp2);
- if (op1 == 2) {
- tmp64 = tcg_temp_new_i64();
- tcg_gen_ext_i32_i64(tmp64, tmp);
- tcg_temp_free_i32(tmp);
- gen_addq(s, tmp64, rn, rd);
- gen_storeq_reg(s, rn, rd, tmp64);
- tcg_temp_free_i64(tmp64);
- } else {
- if (op1 == 0) {
- tmp2 = load_reg(s, rn);
- gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- store_reg(s, rd, tmp);
- }
- }
- break;
- default:
+ } else if (disas_coproc_insn(s, insn)) {
+ /* Coprocessor. */
goto illegal_op;
}
- } else if (((insn & 0x0e000000) == 0 &&
- (insn & 0x00000090) != 0x90) ||
- ((insn & 0x0e000000) == (1 << 25))) {
- int set_cc, logic_cc, shiftop;
-
- op1 = (insn >> 21) & 0xf;
- set_cc = (insn >> 20) & 1;
- logic_cc = table_logic_cc[op1] & set_cc;
-
- /* data processing instruction */
- if (insn & (1 << 25)) {
- /* immediate operand */
- val = insn & 0xff;
- shift = ((insn >> 8) & 0xf) * 2;
- val = ror32(val, shift);
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, val);
- if (logic_cc && shift) {
- gen_set_CF_bit31(tmp2);
- }
- } else {
- /* register */
- rm = (insn) & 0xf;
- tmp2 = load_reg(s, rm);
- shiftop = (insn >> 5) & 3;
- if (!(insn & (1 << 4))) {
- shift = (insn >> 7) & 0x1f;
- gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
- } else {
- rs = (insn >> 8) & 0xf;
- tmp = load_reg(s, rs);
- gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
- }
- }
- if (op1 != 0x0f && op1 != 0x0d) {
- rn = (insn >> 16) & 0xf;
- tmp = load_reg(s, rn);
- } else {
- tmp = NULL;
- }
- rd = (insn >> 12) & 0xf;
- switch(op1) {
- case 0x00:
- tcg_gen_and_i32(tmp, tmp, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp);
- }
- store_reg_bx(s, rd, tmp);
- break;
- case 0x01:
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp);
- }
- store_reg_bx(s, rd, tmp);
- break;
- case 0x02:
- if (set_cc && rd == 15) {
- /* SUBS r15, ... is used for exception return. */
- if (IS_USER(s)) {
- goto illegal_op;
- }
- gen_sub_CC(tmp, tmp, tmp2);
- gen_exception_return(s, tmp);
- } else {
- if (set_cc) {
- gen_sub_CC(tmp, tmp, tmp2);
- } else {
- tcg_gen_sub_i32(tmp, tmp, tmp2);
- }
- store_reg_bx(s, rd, tmp);
- }
- break;
- case 0x03:
- if (set_cc) {
- gen_sub_CC(tmp, tmp2, tmp);
- } else {
- tcg_gen_sub_i32(tmp, tmp2, tmp);
- }
- store_reg_bx(s, rd, tmp);
- break;
- case 0x04:
- if (set_cc) {
- gen_add_CC(tmp, tmp, tmp2);
- } else {
- tcg_gen_add_i32(tmp, tmp, tmp2);
- }
- store_reg_bx(s, rd, tmp);
- break;
- case 0x05:
- if (set_cc) {
- gen_adc_CC(tmp, tmp, tmp2);
- } else {
- gen_add_carry(tmp, tmp, tmp2);
- }
- store_reg_bx(s, rd, tmp);
- break;
- case 0x06:
- if (set_cc) {
- gen_sbc_CC(tmp, tmp, tmp2);
- } else {
- gen_sub_carry(tmp, tmp, tmp2);
- }
- store_reg_bx(s, rd, tmp);
- break;
- case 0x07:
- if (set_cc) {
- gen_sbc_CC(tmp, tmp2, tmp);
- } else {
- gen_sub_carry(tmp, tmp2, tmp);
- }
- store_reg_bx(s, rd, tmp);
- break;
- case 0x08:
- if (set_cc) {
- tcg_gen_and_i32(tmp, tmp, tmp2);
- gen_logic_CC(tmp);
- }
- tcg_temp_free_i32(tmp);
- break;
- case 0x09:
- if (set_cc) {
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- gen_logic_CC(tmp);
- }
- tcg_temp_free_i32(tmp);
- break;
- case 0x0a:
- if (set_cc) {
- gen_sub_CC(tmp, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp);
- break;
- case 0x0b:
- if (set_cc) {
- gen_add_CC(tmp, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp);
- break;
- case 0x0c:
- tcg_gen_or_i32(tmp, tmp, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp);
- }
- store_reg_bx(s, rd, tmp);
- break;
- case 0x0d:
- if (logic_cc && rd == 15) {
- /* MOVS r15, ... is used for exception return. */
- if (IS_USER(s)) {
- goto illegal_op;
- }
- gen_exception_return(s, tmp2);
- } else {
- if (logic_cc) {
- gen_logic_CC(tmp2);
- }
- store_reg_bx(s, rd, tmp2);
- }
- break;
- case 0x0e:
- tcg_gen_andc_i32(tmp, tmp, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp);
- }
- store_reg_bx(s, rd, tmp);
- break;
- default:
- case 0x0f:
- tcg_gen_not_i32(tmp2, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp2);
- }
- store_reg_bx(s, rd, tmp2);
- break;
- }
- if (op1 != 0x0f && op1 != 0x0d) {
- tcg_temp_free_i32(tmp2);
- }
- } else {
- /* other instructions */
- op1 = (insn >> 24) & 0xf;
- switch(op1) {
- case 0x0:
- case 0x1:
- /* multiplies, extra load/stores */
- sh = (insn >> 5) & 3;
- if (sh == 0) {
- if (op1 == 0x0) {
- rd = (insn >> 16) & 0xf;
- rn = (insn >> 12) & 0xf;
- rs = (insn >> 8) & 0xf;
- rm = (insn) & 0xf;
- op1 = (insn >> 20) & 0xf;
- switch (op1) {
- case 0: case 1: case 2: case 3: case 6:
- /* 32 bit mul */
- tmp = load_reg(s, rs);
- tmp2 = load_reg(s, rm);
- tcg_gen_mul_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- if (insn & (1 << 22)) {
- /* Subtract (mls) */
- ARCH(6T2);
- tmp2 = load_reg(s, rn);
- tcg_gen_sub_i32(tmp, tmp2, tmp);
- tcg_temp_free_i32(tmp2);
- } else if (insn & (1 << 21)) {
- /* Add */
- tmp2 = load_reg(s, rn);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- if (insn & (1 << 20))
- gen_logic_CC(tmp);
- store_reg(s, rd, tmp);
- break;
- case 4:
- /* 64 bit mul double accumulate (UMAAL) */
- ARCH(6);
- tmp = load_reg(s, rs);
- tmp2 = load_reg(s, rm);
- tmp64 = gen_mulu_i64_i32(tmp, tmp2);
- gen_addq_lo(s, tmp64, rn);
- gen_addq_lo(s, tmp64, rd);
- gen_storeq_reg(s, rn, rd, tmp64);
- tcg_temp_free_i64(tmp64);
- break;
- case 8: case 9: case 10: case 11:
- case 12: case 13: case 14: case 15:
- /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */
- tmp = load_reg(s, rs);
- tmp2 = load_reg(s, rm);
- if (insn & (1 << 22)) {
- tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);
- } else {
- tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);
- }
- if (insn & (1 << 21)) { /* mult accumulate */
- TCGv_i32 al = load_reg(s, rn);
- TCGv_i32 ah = load_reg(s, rd);
- tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, al, ah);
- tcg_temp_free_i32(al);
- tcg_temp_free_i32(ah);
- }
- if (insn & (1 << 20)) {
- gen_logicq_cc(tmp, tmp2);
- }
- store_reg(s, rn, tmp);
- store_reg(s, rd, tmp2);
- break;
- default:
- goto illegal_op;
- }
- } else {
- rn = (insn >> 16) & 0xf;
- rd = (insn >> 12) & 0xf;
- if (insn & (1 << 23)) {
- /* load/store exclusive */
- bool is_ld = extract32(insn, 20, 1);
- bool is_lasr = !extract32(insn, 8, 1);
- int op2 = (insn >> 8) & 3;
- op1 = (insn >> 21) & 0x3;
-
- switch (op2) {
- case 0: /* lda/stl */
- if (op1 == 1) {
- goto illegal_op;
- }
- ARCH(8);
- break;
- case 1: /* reserved */
- goto illegal_op;
- case 2: /* ldaex/stlex */
- ARCH(8);
- break;
- case 3: /* ldrex/strex */
- if (op1) {
- ARCH(6K);
- } else {
- ARCH(6);
- }
- break;
- }
-
- addr = tcg_temp_local_new_i32();
- load_reg_var(s, addr, rn);
-
- if (is_lasr && !is_ld) {
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
- }
-
- if (op2 == 0) {
- if (is_ld) {
- tmp = tcg_temp_new_i32();
- switch (op1) {
- case 0: /* lda */
- gen_aa32_ld32u_iss(s, tmp, addr,
- get_mem_index(s),
- rd | ISSIsAcqRel);
- break;
- case 2: /* ldab */
- gen_aa32_ld8u_iss(s, tmp, addr,
- get_mem_index(s),
- rd | ISSIsAcqRel);
- break;
- case 3: /* ldah */
- gen_aa32_ld16u_iss(s, tmp, addr,
- get_mem_index(s),
- rd | ISSIsAcqRel);
- break;
- default:
- abort();
- }
- store_reg(s, rd, tmp);
- } else {
- rm = insn & 0xf;
- tmp = load_reg(s, rm);
- switch (op1) {
- case 0: /* stl */
- gen_aa32_st32_iss(s, tmp, addr,
- get_mem_index(s),
- rm | ISSIsAcqRel);
- break;
- case 2: /* stlb */
- gen_aa32_st8_iss(s, tmp, addr,
- get_mem_index(s),
- rm | ISSIsAcqRel);
- break;
- case 3: /* stlh */
- gen_aa32_st16_iss(s, tmp, addr,
- get_mem_index(s),
- rm | ISSIsAcqRel);
- break;
- default:
- abort();
- }
- tcg_temp_free_i32(tmp);
- }
- } else if (is_ld) {
- switch (op1) {
- case 0: /* ldrex */
- gen_load_exclusive(s, rd, 15, addr, 2);
- break;
- case 1: /* ldrexd */
- gen_load_exclusive(s, rd, rd + 1, addr, 3);
- break;
- case 2: /* ldrexb */
- gen_load_exclusive(s, rd, 15, addr, 0);
- break;
- case 3: /* ldrexh */
- gen_load_exclusive(s, rd, 15, addr, 1);
- break;
- default:
- abort();
- }
- } else {
- rm = insn & 0xf;
- switch (op1) {
- case 0: /* strex */
- gen_store_exclusive(s, rd, rm, 15, addr, 2);
- break;
- case 1: /* strexd */
- gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);
- break;
- case 2: /* strexb */
- gen_store_exclusive(s, rd, rm, 15, addr, 0);
- break;
- case 3: /* strexh */
- gen_store_exclusive(s, rd, rm, 15, addr, 1);
- break;
- default:
- abort();
- }
- }
- tcg_temp_free_i32(addr);
-
- if (is_lasr && is_ld) {
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
- }
- } else if ((insn & 0x00300f00) == 0) {
- /* 0bcccc_0001_0x00_xxxx_xxxx_0000_1001_xxxx
- * - SWP, SWPB
- */
-
- TCGv taddr;
- TCGMemOp opc = s->be_data;
-
- rm = (insn) & 0xf;
-
- if (insn & (1 << 22)) {
- opc |= MO_UB;
- } else {
- opc |= MO_UL | MO_ALIGN;
- }
-
- addr = load_reg(s, rn);
- taddr = gen_aa32_addr(s, addr, opc);
- tcg_temp_free_i32(addr);
-
- tmp = load_reg(s, rm);
- tcg_gen_atomic_xchg_i32(tmp, taddr, tmp,
- get_mem_index(s), opc);
- tcg_temp_free(taddr);
- store_reg(s, rd, tmp);
- } else {
- goto illegal_op;
- }
- }
- } else {
- int address_offset;
- bool load = insn & (1 << 20);
- bool wbit = insn & (1 << 21);
- bool pbit = insn & (1 << 24);
- bool doubleword = false;
- ISSInfo issinfo;
-
- /* Misc load/store */
- rn = (insn >> 16) & 0xf;
- rd = (insn >> 12) & 0xf;
-
- /* ISS not valid if writeback */
- issinfo = (pbit & !wbit) ? rd : ISSInvalid;
-
- if (!load && (sh & 2)) {
- /* doubleword */
- ARCH(5TE);
- if (rd & 1) {
- /* UNPREDICTABLE; we choose to UNDEF */
- goto illegal_op;
- }
- load = (sh & 1) == 0;
- doubleword = true;
- }
-
- addr = load_reg(s, rn);
- if (pbit) {
- gen_add_datah_offset(s, insn, 0, addr);
- }
- address_offset = 0;
-
- if (doubleword) {
- if (!load) {
- /* store */
- tmp = load_reg(s, rd);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- tcg_gen_addi_i32(addr, addr, 4);
- tmp = load_reg(s, rd + 1);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- } else {
- /* load */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- store_reg(s, rd, tmp);
- tcg_gen_addi_i32(addr, addr, 4);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- rd++;
- }
- address_offset = -4;
- } else if (load) {
- /* load */
- tmp = tcg_temp_new_i32();
- switch (sh) {
- case 1:
- gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),
- issinfo);
- break;
- case 2:
- gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s),
- issinfo);
- break;
- default:
- case 3:
- gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s),
- issinfo);
- break;
- }
- } else {
- /* store */
- tmp = load_reg(s, rd);
- gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), issinfo);
- tcg_temp_free_i32(tmp);
- }
- /* Perform base writeback before the loaded value to
- ensure correct behavior with overlapping index registers.
- ldrd with base writeback is undefined if the
- destination and index registers overlap. */
- if (!pbit) {
- gen_add_datah_offset(s, insn, address_offset, addr);
- store_reg(s, rn, addr);
- } else if (wbit) {
- if (address_offset)
- tcg_gen_addi_i32(addr, addr, address_offset);
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- if (load) {
- /* Complete the load. */
- store_reg(s, rd, tmp);
- }
- }
- break;
- case 0x4:
- case 0x5:
- goto do_ldst;
- case 0x6:
- case 0x7:
- if (insn & (1 << 4)) {
- ARCH(6);
- /* Armv6 Media instructions. */
- rm = insn & 0xf;
- rn = (insn >> 16) & 0xf;
- rd = (insn >> 12) & 0xf;
- rs = (insn >> 8) & 0xf;
- switch ((insn >> 23) & 3) {
- case 0: /* Parallel add/subtract. */
- op1 = (insn >> 20) & 7;
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- sh = (insn >> 5) & 7;
- if ((op1 & 3) == 0 || sh == 5 || sh == 6)
- goto illegal_op;
- gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- break;
- case 1:
- if ((insn & 0x00700020) == 0) {
- /* Halfword pack. */
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- shift = (insn >> 7) & 0x1f;
- if (insn & (1 << 6)) {
- /* pkhtb */
- if (shift == 0) {
- shift = 31;
- }
- tcg_gen_sari_i32(tmp2, tmp2, shift);
- tcg_gen_deposit_i32(tmp, tmp, tmp2, 0, 16);
- } else {
- /* pkhbt */
- tcg_gen_shli_i32(tmp2, tmp2, shift);
- tcg_gen_deposit_i32(tmp, tmp2, tmp, 0, 16);
- }
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- } else if ((insn & 0x00200020) == 0x00200000) {
- /* [us]sat */
- tmp = load_reg(s, rm);
- shift = (insn >> 7) & 0x1f;
- if (insn & (1 << 6)) {
- if (shift == 0)
- shift = 31;
- tcg_gen_sari_i32(tmp, tmp, shift);
- } else {
- tcg_gen_shli_i32(tmp, tmp, shift);
- }
- sh = (insn >> 16) & 0x1f;
- tmp2 = tcg_const_i32(sh);
- if (insn & (1 << 22))
- gen_helper_usat(tmp, cpu_env, tmp, tmp2);
- else
- gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- } else if ((insn & 0x00300fe0) == 0x00200f20) {
- /* [us]sat16 */
- tmp = load_reg(s, rm);
- sh = (insn >> 16) & 0x1f;
- tmp2 = tcg_const_i32(sh);
- if (insn & (1 << 22))
- gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
- else
- gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- } else if ((insn & 0x00700fe0) == 0x00000fa0) {
- /* Select bytes. */
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- tmp3 = tcg_temp_new_i32();
- tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
- gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
- tcg_temp_free_i32(tmp3);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- } else if ((insn & 0x000003e0) == 0x00000060) {
- tmp = load_reg(s, rm);
- shift = (insn >> 10) & 3;
- /* ??? In many cases it's not necessary to do a
- rotate, a shift is sufficient. */
- tcg_gen_rotri_i32(tmp, tmp, shift * 8);
- op1 = (insn >> 20) & 7;
- switch (op1) {
- case 0: gen_sxtb16(tmp); break;
- case 2: gen_sxtb(tmp); break;
- case 3: gen_sxth(tmp); break;
- case 4: gen_uxtb16(tmp); break;
- case 6: gen_uxtb(tmp); break;
- case 7: gen_uxth(tmp); break;
- default: goto illegal_op;
- }
- if (rn != 15) {
- tmp2 = load_reg(s, rn);
- if ((op1 & 3) == 0) {
- gen_add16(tmp, tmp2);
- } else {
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- }
- store_reg(s, rd, tmp);
- } else if ((insn & 0x003f0f60) == 0x003f0f20) {
- /* rev */
- tmp = load_reg(s, rm);
- if (insn & (1 << 22)) {
- if (insn & (1 << 7)) {
- gen_revsh(tmp);
- } else {
- ARCH(6T2);
- gen_helper_rbit(tmp, tmp);
- }
- } else {
- if (insn & (1 << 7))
- gen_rev16(tmp);
- else
- tcg_gen_bswap32_i32(tmp, tmp);
- }
- store_reg(s, rd, tmp);
- } else {
- goto illegal_op;
- }
- break;
- case 2: /* Multiplies (Type 3). */
- switch ((insn >> 20) & 0x7) {
- case 5:
- if (((insn >> 6) ^ (insn >> 7)) & 1) {
- /* op2 not 00x or 11x : UNDEF */
- goto illegal_op;
- }
- /* Signed multiply most significant [accumulate].
- (SMMUL, SMMLA, SMMLS) */
- tmp = load_reg(s, rm);
- tmp2 = load_reg(s, rs);
- tcg_gen_muls2_i32(tmp2, tmp, tmp, tmp2);
-
- if (rd != 15) {
- tmp3 = load_reg(s, rd);
- if (insn & (1 << 6)) {
- tcg_gen_sub_i32(tmp, tmp, tmp3);
- } else {
- tcg_gen_add_i32(tmp, tmp, tmp3);
- }
- tcg_temp_free_i32(tmp3);
- }
- if (insn & (1 << 5)) {
- /*
- * Adding 0x80000000 to the 64-bit quantity
- * means that we have carry in to the high
- * word when the low word has the high bit set.
- */
- tcg_gen_shri_i32(tmp2, tmp2, 31);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp2);
- store_reg(s, rn, tmp);
- break;
- case 0:
- case 4:
- /* SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD */
- if (insn & (1 << 7)) {
- goto illegal_op;
- }
- tmp = load_reg(s, rm);
- tmp2 = load_reg(s, rs);
- if (insn & (1 << 5))
- gen_swap_half(tmp2);
- gen_smul_dual(tmp, tmp2);
- if (insn & (1 << 22)) {
- /* smlald, smlsld */
- TCGv_i64 tmp64_2;
-
- tmp64 = tcg_temp_new_i64();
- tmp64_2 = tcg_temp_new_i64();
- tcg_gen_ext_i32_i64(tmp64, tmp);
- tcg_gen_ext_i32_i64(tmp64_2, tmp2);
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(tmp2);
- if (insn & (1 << 6)) {
- tcg_gen_sub_i64(tmp64, tmp64, tmp64_2);
- } else {
- tcg_gen_add_i64(tmp64, tmp64, tmp64_2);
- }
- tcg_temp_free_i64(tmp64_2);
- gen_addq(s, tmp64, rd, rn);
- gen_storeq_reg(s, rd, rn, tmp64);
- tcg_temp_free_i64(tmp64);
- } else {
- /* smuad, smusd, smlad, smlsd */
- if (insn & (1 << 6)) {
- /* This subtraction cannot overflow. */
- tcg_gen_sub_i32(tmp, tmp, tmp2);
- } else {
- /* This addition cannot overflow 32 bits;
- * however it may overflow considered as a
- * signed operation, in which case we must set
- * the Q flag.
- */
- gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp2);
- if (rd != 15)
- {
- tmp2 = load_reg(s, rd);
- gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- store_reg(s, rn, tmp);
- }
- break;
- case 1:
- case 3:
- /* SDIV, UDIV */
- if (!dc_isar_feature(arm_div, s)) {
- goto illegal_op;
- }
- if (((insn >> 5) & 7) || (rd != 15)) {
- goto illegal_op;
- }
- tmp = load_reg(s, rm);
- tmp2 = load_reg(s, rs);
- if (insn & (1 << 21)) {
- gen_helper_udiv(tmp, tmp, tmp2);
- } else {
- gen_helper_sdiv(tmp, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp2);
- store_reg(s, rn, tmp);
- break;
- default:
- goto illegal_op;
- }
- break;
- case 3:
- op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
- switch (op1) {
- case 0: /* Unsigned sum of absolute differences. */
- ARCH(6);
- tmp = load_reg(s, rm);
- tmp2 = load_reg(s, rs);
- gen_helper_usad8(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- if (rd != 15) {
- tmp2 = load_reg(s, rd);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- store_reg(s, rn, tmp);
- break;
- case 0x20: case 0x24: case 0x28: case 0x2c:
- /* Bitfield insert/clear. */
- ARCH(6T2);
- shift = (insn >> 7) & 0x1f;
- i = (insn >> 16) & 0x1f;
- if (i < shift) {
- /* UNPREDICTABLE; we choose to UNDEF */
- goto illegal_op;
- }
- i = i + 1 - shift;
- if (rm == 15) {
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, 0);
- } else {
- tmp = load_reg(s, rm);
- }
- if (i != 32) {
- tmp2 = load_reg(s, rd);
- tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i);
- tcg_temp_free_i32(tmp2);
- }
- store_reg(s, rd, tmp);
- break;
- case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
- case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
- ARCH(6T2);
- tmp = load_reg(s, rm);
- shift = (insn >> 7) & 0x1f;
- i = ((insn >> 16) & 0x1f) + 1;
- if (shift + i > 32)
- goto illegal_op;
- if (i < 32) {
- if (op1 & 0x20) {
- tcg_gen_extract_i32(tmp, tmp, shift, i);
- } else {
- tcg_gen_sextract_i32(tmp, tmp, shift, i);
- }
- }
- store_reg(s, rd, tmp);
- break;
- default:
- goto illegal_op;
- }
- break;
- }
- break;
- }
- do_ldst:
- /* Check for undefined extension instructions
- * per the ARM Bible IE:
- * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
- */
- sh = (0xf << 20) | (0xf << 4);
- if (op1 == 0x7 && ((insn & sh) == sh))
- {
- goto illegal_op;
- }
- /* load/store byte/word */
- rn = (insn >> 16) & 0xf;
- rd = (insn >> 12) & 0xf;
- tmp2 = load_reg(s, rn);
- if ((insn & 0x01200000) == 0x00200000) {
- /* ldrt/strt */
- i = get_a32_user_mem_index(s);
- } else {
- i = get_mem_index(s);
- }
- if (insn & (1 << 24))
- gen_add_data_offset(s, insn, tmp2);
- if (insn & (1 << 20)) {
- /* load */
- tmp = tcg_temp_new_i32();
- if (insn & (1 << 22)) {
- gen_aa32_ld8u_iss(s, tmp, tmp2, i, rd);
- } else {
- gen_aa32_ld32u_iss(s, tmp, tmp2, i, rd);
- }
- } else {
- /* store */
- tmp = load_reg(s, rd);
- if (insn & (1 << 22)) {
- gen_aa32_st8_iss(s, tmp, tmp2, i, rd);
- } else {
- gen_aa32_st32_iss(s, tmp, tmp2, i, rd);
- }
- tcg_temp_free_i32(tmp);
- }
- if (!(insn & (1 << 24))) {
- gen_add_data_offset(s, insn, tmp2);
- store_reg(s, rn, tmp2);
- } else if (insn & (1 << 21)) {
- store_reg(s, rn, tmp2);
- } else {
- tcg_temp_free_i32(tmp2);
- }
- if (insn & (1 << 20)) {
- /* Complete the load. */
- store_reg_from_load(s, rd, tmp);
- }
- break;
- case 0x08:
- case 0x09:
- {
- int j, n, loaded_base;
- bool exc_return = false;
- bool is_load = extract32(insn, 20, 1);
- bool user = false;
- TCGv_i32 loaded_var;
- /* load/store multiple words */
- /* XXX: store correct base if write back */
- if (insn & (1 << 22)) {
- /* LDM (user), LDM (exception return) and STM (user) */
- if (IS_USER(s))
- goto illegal_op; /* only usable in supervisor mode */
-
- if (is_load && extract32(insn, 15, 1)) {
- exc_return = true;
- } else {
- user = true;
- }
- }
- rn = (insn >> 16) & 0xf;
- addr = load_reg(s, rn);
-
- /* compute total size */
- loaded_base = 0;
- loaded_var = NULL;
- n = 0;
- for (i = 0; i < 16; i++) {
- if (insn & (1 << i))
- n++;
- }
- /* XXX: test invalid n == 0 case ? */
- if (insn & (1 << 23)) {
- if (insn & (1 << 24)) {
- /* pre increment */
- tcg_gen_addi_i32(addr, addr, 4);
- } else {
- /* post increment */
- }
- } else {
- if (insn & (1 << 24)) {
- /* pre decrement */
- tcg_gen_addi_i32(addr, addr, -(n * 4));
- } else {
- /* post decrement */
- if (n != 1)
- tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
- }
- }
- j = 0;
- for (i = 0; i < 16; i++) {
- if (insn & (1 << i)) {
- if (is_load) {
- /* load */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- if (user) {
- tmp2 = tcg_const_i32(i);
- gen_helper_set_user_reg(cpu_env, tmp2, tmp);
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i32(tmp);
- } else if (i == rn) {
- loaded_var = tmp;
- loaded_base = 1;
- } else if (i == 15 && exc_return) {
- store_pc_exc_ret(s, tmp);
- } else {
- store_reg_from_load(s, i, tmp);
- }
- } else {
- /* store */
- if (i == 15) {
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, read_pc(s));
- } else if (user) {
- tmp = tcg_temp_new_i32();
- tmp2 = tcg_const_i32(i);
- gen_helper_get_user_reg(tmp, cpu_env, tmp2);
- tcg_temp_free_i32(tmp2);
- } else {
- tmp = load_reg(s, i);
- }
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- }
- j++;
- /* no need to add after the last transfer */
- if (j != n)
- tcg_gen_addi_i32(addr, addr, 4);
- }
- }
- if (insn & (1 << 21)) {
- /* write back */
- if (insn & (1 << 23)) {
- if (insn & (1 << 24)) {
- /* pre increment */
- } else {
- /* post increment */
- tcg_gen_addi_i32(addr, addr, 4);
- }
- } else {
- if (insn & (1 << 24)) {
- /* pre decrement */
- if (n != 1)
- tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
- } else {
- /* post decrement */
- tcg_gen_addi_i32(addr, addr, -(n * 4));
- }
- }
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- if (loaded_base) {
- store_reg(s, rn, loaded_var);
- }
- if (exc_return) {
- /* Restore CPSR from SPSR. */
- tmp = load_cpu_field(spsr);
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_cpsr_write_eret(cpu_env, tmp);
- tcg_temp_free_i32(tmp);
- /* Must exit loop to check un-masked IRQs */
- s->base.is_jmp = DISAS_EXIT;
- }
- }
- break;
- case 0xa:
- case 0xb:
- {
- int32_t offset;
-
- /* branch (and link) */
- if (insn & (1 << 24)) {
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, s->base.pc_next);
- store_reg(s, 14, tmp);
- }
- offset = sextract32(insn << 2, 0, 26);
- gen_jmp(s, read_pc(s) + offset);
- }
- break;
- case 0xc:
- case 0xd:
- case 0xe:
- if (((insn >> 8) & 0xe) == 10) {
- /* VFP. */
- if (disas_vfp_insn(s, insn)) {
- goto illegal_op;
- }
- } else if (disas_coproc_insn(s, insn)) {
- /* Coprocessor. */
- goto illegal_op;
- }
- break;
- case 0xf:
- /* swi */
- gen_set_pc_im(s, s->base.pc_next);
- s->svc_imm = extract32(insn, 0, 24);
- s->base.is_jmp = DISAS_SWI;
- break;
- default:
- illegal_op:
- unallocated_encoding(s);
- break;
- }
+ break;
+ default:
+ illegal_op:
+ unallocated_encoding(s);
+ break;
}
}
@@ -9246,104 +10608,9 @@ static bool thumb_insn_is_16bit(DisasContext *s, uint32_t pc, uint32_t insn)
return true;
}
-/* Return true if this is a Thumb-2 logical op. */
-static int
-thumb2_logic_op(int op)
-{
- return (op < 8);
-}
-
-/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero
- then set condition code flags based on the result of the operation.
- If SHIFTER_OUT is nonzero then set the carry flag for logical operations
- to the high bit of T1.
- Returns zero if the opcode is valid. */
-
-static int
-gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out,
- TCGv_i32 t0, TCGv_i32 t1)
-{
- int logic_cc;
-
- logic_cc = 0;
- switch (op) {
- case 0: /* and */
- tcg_gen_and_i32(t0, t0, t1);
- logic_cc = conds;
- break;
- case 1: /* bic */
- tcg_gen_andc_i32(t0, t0, t1);
- logic_cc = conds;
- break;
- case 2: /* orr */
- tcg_gen_or_i32(t0, t0, t1);
- logic_cc = conds;
- break;
- case 3: /* orn */
- tcg_gen_orc_i32(t0, t0, t1);
- logic_cc = conds;
- break;
- case 4: /* eor */
- tcg_gen_xor_i32(t0, t0, t1);
- logic_cc = conds;
- break;
- case 8: /* add */
- if (conds)
- gen_add_CC(t0, t0, t1);
- else
- tcg_gen_add_i32(t0, t0, t1);
- break;
- case 10: /* adc */
- if (conds)
- gen_adc_CC(t0, t0, t1);
- else
- gen_adc(t0, t1);
- break;
- case 11: /* sbc */
- if (conds) {
- gen_sbc_CC(t0, t0, t1);
- } else {
- gen_sub_carry(t0, t0, t1);
- }
- break;
- case 13: /* sub */
- if (conds)
- gen_sub_CC(t0, t0, t1);
- else
- tcg_gen_sub_i32(t0, t0, t1);
- break;
- case 14: /* rsb */
- if (conds)
- gen_sub_CC(t0, t1, t0);
- else
- tcg_gen_sub_i32(t0, t1, t0);
- break;
- default: /* 5, 6, 7, 9, 12, 15. */
- return 1;
- }
- if (logic_cc) {
- gen_logic_CC(t0);
- if (shifter_out)
- gen_set_CF_bit31(t1);
- }
- return 0;
-}
-
/* Translate a 32-bit thumb instruction. */
static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
{
- uint32_t imm, shift, offset;
- uint32_t rd, rn, rm, rs;
- TCGv_i32 tmp;
- TCGv_i32 tmp2;
- TCGv_i32 tmp3;
- TCGv_i32 addr;
- TCGv_i64 tmp64;
- int op;
- int shiftop;
- int conds;
- int logic_cc;
-
/*
* ARMv6-M supports a limited subset of Thumb2 instructions.
* Other Thumb1 architectures allow only 32-bit
@@ -9379,800 +10646,15 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
ARCH(6T2);
}
- rn = (insn >> 16) & 0xf;
- rs = (insn >> 12) & 0xf;
- rd = (insn >> 8) & 0xf;
- rm = insn & 0xf;
+ if (disas_t32(s, insn)) {
+ return;
+ }
+ /* fall back to legacy decoder */
+
switch ((insn >> 25) & 0xf) {
case 0: case 1: case 2: case 3:
/* 16-bit instructions. Should never happen. */
abort();
- case 4:
- if (insn & (1 << 22)) {
- /* 0b1110_100x_x1xx_xxxx_xxxx_xxxx_xxxx_xxxx
- * - load/store doubleword, load/store exclusive, ldacq/strel,
- * table branch, TT.
- */
- if (insn == 0xe97fe97f && arm_dc_feature(s, ARM_FEATURE_M) &&
- arm_dc_feature(s, ARM_FEATURE_V8)) {
- /* 0b1110_1001_0111_1111_1110_1001_0111_111
- * - SG (v8M only)
- * The bulk of the behaviour for this instruction is implemented
- * in v7m_handle_execute_nsc(), which deals with the insn when
- * it is executed by a CPU in non-secure state from memory
- * which is Secure & NonSecure-Callable.
- * Here we only need to handle the remaining cases:
- * * in NS memory (including the "security extension not
- * implemented" case) : NOP
- * * in S memory but CPU already secure (clear IT bits)
- * We know that the attribute for the memory this insn is
- * in must match the current CPU state, because otherwise
- * get_phys_addr_pmsav8 would have generated an exception.
- */
- if (s->v8m_secure) {
- /* Like the IT insn, we don't need to generate any code */
- s->condexec_cond = 0;
- s->condexec_mask = 0;
- }
- } else if (insn & 0x01200000) {
- /* 0b1110_1000_x11x_xxxx_xxxx_xxxx_xxxx_xxxx
- * - load/store dual (post-indexed)
- * 0b1111_1001_x10x_xxxx_xxxx_xxxx_xxxx_xxxx
- * - load/store dual (literal and immediate)
- * 0b1111_1001_x11x_xxxx_xxxx_xxxx_xxxx_xxxx
- * - load/store dual (pre-indexed)
- */
- bool wback = extract32(insn, 21, 1);
-
- if (rn == 15 && (insn & (1 << 21))) {
- /* UNPREDICTABLE */
- goto illegal_op;
- }
-
- addr = add_reg_for_lit(s, rn, 0);
- offset = (insn & 0xff) * 4;
- if ((insn & (1 << 23)) == 0) {
- offset = -offset;
- }
-
- if (s->v8m_stackcheck && rn == 13 && wback) {
- /*
- * Here 'addr' is the current SP; if offset is +ve we're
- * moving SP up, else down. It is UNKNOWN whether the limit
- * check triggers when SP starts below the limit and ends
- * up above it; check whichever of the current and final
- * SP is lower, so QEMU will trigger in that situation.
- */
- if ((int32_t)offset < 0) {
- TCGv_i32 newsp = tcg_temp_new_i32();
-
- tcg_gen_addi_i32(newsp, addr, offset);
- gen_helper_v8m_stackcheck(cpu_env, newsp);
- tcg_temp_free_i32(newsp);
- } else {
- gen_helper_v8m_stackcheck(cpu_env, addr);
- }
- }
-
- if (insn & (1 << 24)) {
- tcg_gen_addi_i32(addr, addr, offset);
- offset = 0;
- }
- if (insn & (1 << 20)) {
- /* ldrd */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- store_reg(s, rs, tmp);
- tcg_gen_addi_i32(addr, addr, 4);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- store_reg(s, rd, tmp);
- } else {
- /* strd */
- tmp = load_reg(s, rs);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- tcg_gen_addi_i32(addr, addr, 4);
- tmp = load_reg(s, rd);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- }
- if (wback) {
- /* Base writeback. */
- tcg_gen_addi_i32(addr, addr, offset - 4);
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- } else if ((insn & (1 << 23)) == 0) {
- /* 0b1110_1000_010x_xxxx_xxxx_xxxx_xxxx_xxxx
- * - load/store exclusive word
- * - TT (v8M only)
- */
- if (rs == 15) {
- if (!(insn & (1 << 20)) &&
- arm_dc_feature(s, ARM_FEATURE_M) &&
- arm_dc_feature(s, ARM_FEATURE_V8)) {
- /* 0b1110_1000_0100_xxxx_1111_xxxx_xxxx_xxxx
- * - TT (v8M only)
- */
- bool alt = insn & (1 << 7);
- TCGv_i32 addr, op, ttresp;
-
- if ((insn & 0x3f) || rd == 13 || rd == 15 || rn == 15) {
- /* we UNDEF for these UNPREDICTABLE cases */
- goto illegal_op;
- }
-
- if (alt && !s->v8m_secure) {
- goto illegal_op;
- }
-
- addr = load_reg(s, rn);
- op = tcg_const_i32(extract32(insn, 6, 2));
- ttresp = tcg_temp_new_i32();
- gen_helper_v7m_tt(ttresp, cpu_env, addr, op);
- tcg_temp_free_i32(addr);
- tcg_temp_free_i32(op);
- store_reg(s, rd, ttresp);
- break;
- }
- goto illegal_op;
- }
- addr = tcg_temp_local_new_i32();
- load_reg_var(s, addr, rn);
- tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);
- if (insn & (1 << 20)) {
- gen_load_exclusive(s, rs, 15, addr, 2);
- } else {
- gen_store_exclusive(s, rd, rs, 15, addr, 2);
- }
- tcg_temp_free_i32(addr);
- } else if ((insn & (7 << 5)) == 0) {
- /* Table Branch. */
- addr = load_reg(s, rn);
- tmp = load_reg(s, rm);
- tcg_gen_add_i32(addr, addr, tmp);
- if (insn & (1 << 4)) {
- /* tbh */
- tcg_gen_add_i32(addr, addr, tmp);
- tcg_temp_free_i32(tmp);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
- } else { /* tbb */
- tcg_temp_free_i32(tmp);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
- }
- tcg_temp_free_i32(addr);
- tcg_gen_shli_i32(tmp, tmp, 1);
- tcg_gen_addi_i32(tmp, tmp, read_pc(s));
- store_reg(s, 15, tmp);
- } else {
- bool is_lasr = false;
- bool is_ld = extract32(insn, 20, 1);
- int op2 = (insn >> 6) & 0x3;
- op = (insn >> 4) & 0x3;
- switch (op2) {
- case 0:
- goto illegal_op;
- case 1:
- /* Load/store exclusive byte/halfword/doubleword */
- if (op == 2) {
- goto illegal_op;
- }
- ARCH(7);
- break;
- case 2:
- /* Load-acquire/store-release */
- if (op == 3) {
- goto illegal_op;
- }
- /* Fall through */
- case 3:
- /* Load-acquire/store-release exclusive */
- ARCH(8);
- is_lasr = true;
- break;
- }
-
- if (is_lasr && !is_ld) {
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
- }
-
- addr = tcg_temp_local_new_i32();
- load_reg_var(s, addr, rn);
- if (!(op2 & 1)) {
- if (is_ld) {
- tmp = tcg_temp_new_i32();
- switch (op) {
- case 0: /* ldab */
- gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s),
- rs | ISSIsAcqRel);
- break;
- case 1: /* ldah */
- gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),
- rs | ISSIsAcqRel);
- break;
- case 2: /* lda */
- gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
- rs | ISSIsAcqRel);
- break;
- default:
- abort();
- }
- store_reg(s, rs, tmp);
- } else {
- tmp = load_reg(s, rs);
- switch (op) {
- case 0: /* stlb */
- gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s),
- rs | ISSIsAcqRel);
- break;
- case 1: /* stlh */
- gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s),
- rs | ISSIsAcqRel);
- break;
- case 2: /* stl */
- gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s),
- rs | ISSIsAcqRel);
- break;
- default:
- abort();
- }
- tcg_temp_free_i32(tmp);
- }
- } else if (is_ld) {
- gen_load_exclusive(s, rs, rd, addr, op);
- } else {
- gen_store_exclusive(s, rm, rs, rd, addr, op);
- }
- tcg_temp_free_i32(addr);
-
- if (is_lasr && is_ld) {
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
- }
- }
- } else {
- /* Load/store multiple, RFE, SRS. */
- if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
- /* RFE, SRS: not available in user mode or on M profile */
- if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
- goto illegal_op;
- }
- if (insn & (1 << 20)) {
- /* rfe */
- addr = load_reg(s, rn);
- if ((insn & (1 << 24)) == 0)
- tcg_gen_addi_i32(addr, addr, -8);
- /* Load PC into tmp and CPSR into tmp2. */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- tcg_gen_addi_i32(addr, addr, 4);
- tmp2 = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
- if (insn & (1 << 21)) {
- /* Base writeback. */
- if (insn & (1 << 24)) {
- tcg_gen_addi_i32(addr, addr, 4);
- } else {
- tcg_gen_addi_i32(addr, addr, -4);
- }
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- gen_rfe(s, tmp, tmp2);
- } else {
- /* srs */
- gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2,
- insn & (1 << 21));
- }
- } else {
- int i, loaded_base = 0;
- TCGv_i32 loaded_var;
- bool wback = extract32(insn, 21, 1);
- /* Load/store multiple. */
- addr = load_reg(s, rn);
- offset = 0;
- for (i = 0; i < 16; i++) {
- if (insn & (1 << i))
- offset += 4;
- }
-
- if (insn & (1 << 24)) {
- tcg_gen_addi_i32(addr, addr, -offset);
- }
-
- if (s->v8m_stackcheck && rn == 13 && wback) {
- /*
- * If the writeback is incrementing SP rather than
- * decrementing it, and the initial SP is below the
- * stack limit but the final written-back SP would
- * be above, then then we must not perform any memory
- * accesses, but it is IMPDEF whether we generate
- * an exception. We choose to do so in this case.
- * At this point 'addr' is the lowest address, so
- * either the original SP (if incrementing) or our
- * final SP (if decrementing), so that's what we check.
- */
- gen_helper_v8m_stackcheck(cpu_env, addr);
- }
-
- loaded_var = NULL;
- for (i = 0; i < 16; i++) {
- if ((insn & (1 << i)) == 0)
- continue;
- if (insn & (1 << 20)) {
- /* Load. */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- if (i == 15) {
- gen_bx_excret(s, tmp);
- } else if (i == rn) {
- loaded_var = tmp;
- loaded_base = 1;
- } else {
- store_reg(s, i, tmp);
- }
- } else {
- /* Store. */
- tmp = load_reg(s, i);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- }
- tcg_gen_addi_i32(addr, addr, 4);
- }
- if (loaded_base) {
- store_reg(s, rn, loaded_var);
- }
- if (wback) {
- /* Base register writeback. */
- if (insn & (1 << 24)) {
- tcg_gen_addi_i32(addr, addr, -offset);
- }
- /* Fault if writeback register is in register list. */
- if (insn & (1 << rn))
- goto illegal_op;
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- }
- }
- break;
- case 5:
-
- op = (insn >> 21) & 0xf;
- if (op == 6) {
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- goto illegal_op;
- }
- /* Halfword pack. */
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
- if (insn & (1 << 5)) {
- /* pkhtb */
- if (shift == 0) {
- shift = 31;
- }
- tcg_gen_sari_i32(tmp2, tmp2, shift);
- tcg_gen_deposit_i32(tmp, tmp, tmp2, 0, 16);
- } else {
- /* pkhbt */
- tcg_gen_shli_i32(tmp2, tmp2, shift);
- tcg_gen_deposit_i32(tmp, tmp2, tmp, 0, 16);
- }
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- } else {
- /* Data processing register constant shift. */
- if (rn == 15) {
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, 0);
- } else {
- tmp = load_reg(s, rn);
- }
- tmp2 = load_reg(s, rm);
-
- shiftop = (insn >> 4) & 3;
- shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
- conds = (insn & (1 << 20)) != 0;
- logic_cc = (conds && thumb2_logic_op(op));
- gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
- if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
- goto illegal_op;
- tcg_temp_free_i32(tmp2);
- if (rd == 13 &&
- ((op == 2 && rn == 15) ||
- (op == 8 && rn == 13) ||
- (op == 13 && rn == 13))) {
- /* MOV SP, ... or ADD SP, SP, ... or SUB SP, SP, ... */
- store_sp_checked(s, tmp);
- } else if (rd != 15) {
- store_reg(s, rd, tmp);
- } else {
- tcg_temp_free_i32(tmp);
- }
- }
- break;
- case 13: /* Misc data processing. */
- op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
- if (op < 4 && (insn & 0xf000) != 0xf000)
- goto illegal_op;
- switch (op) {
- case 0: /* Register controlled shift. */
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- if ((insn & 0x70) != 0)
- goto illegal_op;
- /*
- * 0b1111_1010_0xxx_xxxx_1111_xxxx_0000_xxxx:
- * - MOV, MOVS (register-shifted register), flagsetting
- */
- op = (insn >> 21) & 3;
- logic_cc = (insn & (1 << 20)) != 0;
- gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
- if (logic_cc)
- gen_logic_CC(tmp);
- store_reg(s, rd, tmp);
- break;
- case 1: /* Sign/zero extend. */
- op = (insn >> 20) & 7;
- switch (op) {
- case 0: /* SXTAH, SXTH */
- case 1: /* UXTAH, UXTH */
- case 4: /* SXTAB, SXTB */
- case 5: /* UXTAB, UXTB */
- break;
- case 2: /* SXTAB16, SXTB16 */
- case 3: /* UXTAB16, UXTB16 */
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- goto illegal_op;
- }
- break;
- default:
- goto illegal_op;
- }
- if (rn != 15) {
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- goto illegal_op;
- }
- }
- tmp = load_reg(s, rm);
- shift = (insn >> 4) & 3;
- /* ??? In many cases it's not necessary to do a
- rotate, a shift is sufficient. */
- tcg_gen_rotri_i32(tmp, tmp, shift * 8);
- op = (insn >> 20) & 7;
- switch (op) {
- case 0: gen_sxth(tmp); break;
- case 1: gen_uxth(tmp); break;
- case 2: gen_sxtb16(tmp); break;
- case 3: gen_uxtb16(tmp); break;
- case 4: gen_sxtb(tmp); break;
- case 5: gen_uxtb(tmp); break;
- default:
- g_assert_not_reached();
- }
- if (rn != 15) {
- tmp2 = load_reg(s, rn);
- if ((op >> 1) == 1) {
- gen_add16(tmp, tmp2);
- } else {
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- }
- store_reg(s, rd, tmp);
- break;
- case 2: /* SIMD add/subtract. */
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- goto illegal_op;
- }
- op = (insn >> 20) & 7;
- shift = (insn >> 4) & 7;
- if ((op & 3) == 3 || (shift & 3) == 3)
- goto illegal_op;
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- break;
- case 3: /* Other data processing. */
- op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
- if (op < 4) {
- /* Saturating add/subtract. */
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- goto illegal_op;
- }
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- if (op & 1)
- gen_helper_add_saturate(tmp, cpu_env, tmp, tmp);
- if (op & 2)
- gen_helper_sub_saturate(tmp, cpu_env, tmp2, tmp);
- else
- gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- } else {
- switch (op) {
- case 0x0a: /* rbit */
- case 0x08: /* rev */
- case 0x09: /* rev16 */
- case 0x0b: /* revsh */
- case 0x18: /* clz */
- break;
- case 0x10: /* sel */
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- goto illegal_op;
- }
- break;
- case 0x20: /* crc32/crc32c */
- case 0x21:
- case 0x22:
- case 0x28:
- case 0x29:
- case 0x2a:
- if (!dc_isar_feature(aa32_crc32, s)) {
- goto illegal_op;
- }
- break;
- default:
- goto illegal_op;
- }
- tmp = load_reg(s, rn);
- switch (op) {
- case 0x0a: /* rbit */
- gen_helper_rbit(tmp, tmp);
- break;
- case 0x08: /* rev */
- tcg_gen_bswap32_i32(tmp, tmp);
- break;
- case 0x09: /* rev16 */
- gen_rev16(tmp);
- break;
- case 0x0b: /* revsh */
- gen_revsh(tmp);
- break;
- case 0x10: /* sel */
- tmp2 = load_reg(s, rm);
- tmp3 = tcg_temp_new_i32();
- tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
- gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
- tcg_temp_free_i32(tmp3);
- tcg_temp_free_i32(tmp2);
- break;
- case 0x18: /* clz */
- tcg_gen_clzi_i32(tmp, tmp, 32);
- break;
- case 0x20:
- case 0x21:
- case 0x22:
- case 0x28:
- case 0x29:
- case 0x2a:
- {
- /* crc32/crc32c */
- uint32_t sz = op & 0x3;
- uint32_t c = op & 0x8;
-
- tmp2 = load_reg(s, rm);
- if (sz == 0) {
- tcg_gen_andi_i32(tmp2, tmp2, 0xff);
- } else if (sz == 1) {
- tcg_gen_andi_i32(tmp2, tmp2, 0xffff);
- }
- tmp3 = tcg_const_i32(1 << sz);
- if (c) {
- gen_helper_crc32c(tmp, tmp, tmp2, tmp3);
- } else {
- gen_helper_crc32(tmp, tmp, tmp2, tmp3);
- }
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i32(tmp3);
- break;
- }
- default:
- g_assert_not_reached();
- }
- }
- store_reg(s, rd, tmp);
- break;
- case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */
- switch ((insn >> 20) & 7) {
- case 0: /* 32 x 32 -> 32 */
- case 7: /* Unsigned sum of absolute differences. */
- break;
- case 1: /* 16 x 16 -> 32 */
- case 2: /* Dual multiply add. */
- case 3: /* 32 * 16 -> 32msb */
- case 4: /* Dual multiply subtract. */
- case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- goto illegal_op;
- }
- break;
- }
- op = (insn >> 4) & 0xf;
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- switch ((insn >> 20) & 7) {
- case 0: /* 32 x 32 -> 32 */
- tcg_gen_mul_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- if (rs != 15) {
- tmp2 = load_reg(s, rs);
- if (op)
- tcg_gen_sub_i32(tmp, tmp2, tmp);
- else
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- break;
- case 1: /* 16 x 16 -> 32 */
- gen_mulxy(tmp, tmp2, op & 2, op & 1);
- tcg_temp_free_i32(tmp2);
- if (rs != 15) {
- tmp2 = load_reg(s, rs);
- gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- break;
- case 2: /* Dual multiply add. */
- case 4: /* Dual multiply subtract. */
- if (op)
- gen_swap_half(tmp2);
- gen_smul_dual(tmp, tmp2);
- if (insn & (1 << 22)) {
- /* This subtraction cannot overflow. */
- tcg_gen_sub_i32(tmp, tmp, tmp2);
- } else {
- /* This addition cannot overflow 32 bits;
- * however it may overflow considered as a signed
- * operation, in which case we must set the Q flag.
- */
- gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp2);
- if (rs != 15)
- {
- tmp2 = load_reg(s, rs);
- gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- break;
- case 3: /* 32 * 16 -> 32msb */
- if (op)
- tcg_gen_sari_i32(tmp2, tmp2, 16);
- else
- gen_sxth(tmp2);
- tmp64 = gen_muls_i64_i32(tmp, tmp2);
- tcg_gen_shri_i64(tmp64, tmp64, 16);
- tmp = tcg_temp_new_i32();
- tcg_gen_extrl_i64_i32(tmp, tmp64);
- tcg_temp_free_i64(tmp64);
- if (rs != 15)
- {
- tmp2 = load_reg(s, rs);
- gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- break;
- case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
- tcg_gen_muls2_i32(tmp2, tmp, tmp, tmp2);
- if (rs != 15) {
- tmp3 = load_reg(s, rs);
- if (insn & (1 << 20)) {
- tcg_gen_add_i32(tmp, tmp, tmp3);
- } else {
- tcg_gen_sub_i32(tmp, tmp, tmp3);
- }
- tcg_temp_free_i32(tmp3);
- }
- if (insn & (1 << 4)) {
- /*
- * Adding 0x80000000 to the 64-bit quantity
- * means that we have carry in to the high
- * word when the low word has the high bit set.
- */
- tcg_gen_shri_i32(tmp2, tmp2, 31);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp2);
- break;
- case 7: /* Unsigned sum of absolute differences. */
- gen_helper_usad8(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- if (rs != 15) {
- tmp2 = load_reg(s, rs);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- break;
- }
- store_reg(s, rd, tmp);
- break;
- case 6: case 7: /* 64-bit multiply, Divide. */
- op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
- tmp = load_reg(s, rn);
- tmp2 = load_reg(s, rm);
- if ((op & 0x50) == 0x10) {
- /* sdiv, udiv */
- if (!dc_isar_feature(thumb_div, s)) {
- goto illegal_op;
- }
- if (op & 0x20)
- gen_helper_udiv(tmp, tmp, tmp2);
- else
- gen_helper_sdiv(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- } else if ((op & 0xe) == 0xc) {
- /* Dual multiply accumulate long. */
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(tmp2);
- goto illegal_op;
- }
- if (op & 1)
- gen_swap_half(tmp2);
- gen_smul_dual(tmp, tmp2);
- if (op & 0x10) {
- tcg_gen_sub_i32(tmp, tmp, tmp2);
- } else {
- tcg_gen_add_i32(tmp, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp2);
- /* BUGFIX */
- tmp64 = tcg_temp_new_i64();
- tcg_gen_ext_i32_i64(tmp64, tmp);
- tcg_temp_free_i32(tmp);
- gen_addq(s, tmp64, rs, rd);
- gen_storeq_reg(s, rs, rd, tmp64);
- tcg_temp_free_i64(tmp64);
- } else {
- if (op & 0x20) {
- /* Unsigned 64-bit multiply */
- tmp64 = gen_mulu_i64_i32(tmp, tmp2);
- } else {
- if (op & 8) {
- /* smlalxy */
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i32(tmp);
- goto illegal_op;
- }
- gen_mulxy(tmp, tmp2, op & 2, op & 1);
- tcg_temp_free_i32(tmp2);
- tmp64 = tcg_temp_new_i64();
- tcg_gen_ext_i32_i64(tmp64, tmp);
- tcg_temp_free_i32(tmp);
- } else {
- /* Signed 64-bit multiply */
- tmp64 = gen_muls_i64_i32(tmp, tmp2);
- }
- }
- if (op & 4) {
- /* umaal */
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- tcg_temp_free_i64(tmp64);
- goto illegal_op;
- }
- gen_addq_lo(s, tmp64, rs);
- gen_addq_lo(s, tmp64, rd);
- } else if (op & 0x40) {
- /* 64-bit accumulate. */
- gen_addq(s, tmp64, rs, rd);
- }
- gen_storeq_reg(s, rs, rd, tmp64);
- tcg_temp_free_i64(tmp64);
- }
- break;
- }
- break;
case 6: case 7: case 14: case 15:
/* Coprocessor. */
if (arm_dc_feature(s, ARM_FEATURE_M)) {
@@ -10201,6 +10683,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
if (arm_dc_feature(s, ARM_FEATURE_VFP)) {
+ uint32_t rn = (insn >> 16) & 0xf;
TCGv_i32 fptr = load_reg(s, rn);
if (extract32(insn, 20, 1)) {
@@ -10259,1457 +10742,25 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
}
break;
- case 8: case 9: case 10: case 11:
- if (insn & (1 << 15)) {
- /* Branches, misc control. */
- if (insn & 0x5000) {
- /* Unconditional branch. */
- /* signextend(hw1[10:0]) -> offset[:12]. */
- offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
- /* hw1[10:0] -> offset[11:1]. */
- offset |= (insn & 0x7ff) << 1;
- /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
- offset[24:22] already have the same value because of the
- sign extension above. */
- offset ^= ((~insn) & (1 << 13)) << 10;
- offset ^= ((~insn) & (1 << 11)) << 11;
-
- if (insn & (1 << 14)) {
- /* Branch and link. */
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
- }
-
- offset += read_pc(s);
- if (insn & (1 << 12)) {
- /* b/bl */
- gen_jmp(s, offset);
- } else {
- /* blx */
- offset &= ~(uint32_t)2;
- /* thumb2 bx, no need to check */
- gen_bx_im(s, offset);
- }
- } else if (((insn >> 23) & 7) == 7) {
- /* Misc control */
- if (insn & (1 << 13))
- goto illegal_op;
-
- if (insn & (1 << 26)) {
- if (arm_dc_feature(s, ARM_FEATURE_M)) {
- goto illegal_op;
- }
- if (!(insn & (1 << 20))) {
- /* Hypervisor call (v7) */
- int imm16 = extract32(insn, 16, 4) << 12
- | extract32(insn, 0, 12);
- ARCH(7);
- if (IS_USER(s)) {
- goto illegal_op;
- }
- gen_hvc(s, imm16);
- } else {
- /* Secure monitor call (v6+) */
- ARCH(6K);
- if (IS_USER(s)) {
- goto illegal_op;
- }
- gen_smc(s);
- }
- } else {
- op = (insn >> 20) & 7;
- switch (op) {
- case 0: /* msr cpsr. */
- if (arm_dc_feature(s, ARM_FEATURE_M)) {
- tmp = load_reg(s, rn);
- /* the constant is the mask and SYSm fields */
- addr = tcg_const_i32(insn & 0xfff);
- gen_helper_v7m_msr(cpu_env, addr, tmp);
- tcg_temp_free_i32(addr);
- tcg_temp_free_i32(tmp);
- gen_lookup_tb(s);
- break;
- }
- /* fall through */
- case 1: /* msr spsr. */
- if (arm_dc_feature(s, ARM_FEATURE_M)) {
- goto illegal_op;
- }
-
- if (extract32(insn, 5, 1)) {
- /* MSR (banked) */
- int sysm = extract32(insn, 8, 4) |
- (extract32(insn, 4, 1) << 4);
- int r = op & 1;
-
- gen_msr_banked(s, r, sysm, rm);
- break;
- }
-
- /* MSR (for PSRs) */
- tmp = load_reg(s, rn);
- if (gen_set_psr(s,
- msr_mask(s, (insn >> 8) & 0xf, op == 1),
- op == 1, tmp))
- goto illegal_op;
- break;
- case 2: /* cps, nop-hint. */
- if (((insn >> 8) & 7) == 0) {
- gen_nop_hint(s, insn & 0xff);
- }
- /* Implemented as NOP in user mode. */
- if (IS_USER(s))
- break;
- offset = 0;
- imm = 0;
- if (insn & (1 << 10)) {
- if (insn & (1 << 7))
- offset |= CPSR_A;
- if (insn & (1 << 6))
- offset |= CPSR_I;
- if (insn & (1 << 5))
- offset |= CPSR_F;
- if (insn & (1 << 9))
- imm = CPSR_A | CPSR_I | CPSR_F;
- }
- if (insn & (1 << 8)) {
- offset |= 0x1f;
- imm |= (insn & 0x1f);
- }
- if (offset) {
- gen_set_psr_im(s, offset, 0, imm);
- }
- break;
- case 3: /* Special control operations. */
- if (!arm_dc_feature(s, ARM_FEATURE_V7) &&
- !arm_dc_feature(s, ARM_FEATURE_M)) {
- goto illegal_op;
- }
- op = (insn >> 4) & 0xf;
- switch (op) {
- case 2: /* clrex */
- gen_clrex(s);
- break;
- case 4: /* dsb */
- case 5: /* dmb */
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
- break;
- case 6: /* isb */
- /* We need to break the TB after this insn
- * to execute self-modifying code correctly
- * and also to take any pending interrupts
- * immediately.
- */
- gen_goto_tb(s, 0, s->base.pc_next);
- break;
- case 7: /* sb */
- if ((insn & 0xf) || !dc_isar_feature(aa32_sb, s)) {
- goto illegal_op;
- }
- /*
- * TODO: There is no speculation barrier opcode
- * for TCG; MB and end the TB instead.
- */
- tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
- gen_goto_tb(s, 0, s->base.pc_next);
- break;
- default:
- goto illegal_op;
- }
- break;
- case 4: /* bxj */
- /* Trivial implementation equivalent to bx.
- * This instruction doesn't exist at all for M-profile.
- */
- if (arm_dc_feature(s, ARM_FEATURE_M)) {
- goto illegal_op;
- }
- tmp = load_reg(s, rn);
- gen_bx(s, tmp);
- break;
- case 5: /* Exception return. */
- if (IS_USER(s)) {
- goto illegal_op;
- }
- if (rn != 14 || rd != 15) {
- goto illegal_op;
- }
- if (s->current_el == 2) {
- /* ERET from Hyp uses ELR_Hyp, not LR */
- if (insn & 0xff) {
- goto illegal_op;
- }
- tmp = load_cpu_field(elr_el[2]);
- } else {
- tmp = load_reg(s, rn);
- tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
- }
- gen_exception_return(s, tmp);
- break;
- case 6: /* MRS */
- if (extract32(insn, 5, 1) &&
- !arm_dc_feature(s, ARM_FEATURE_M)) {
- /* MRS (banked) */
- int sysm = extract32(insn, 16, 4) |
- (extract32(insn, 4, 1) << 4);
-
- gen_mrs_banked(s, 0, sysm, rd);
- break;
- }
-
- if (extract32(insn, 16, 4) != 0xf) {
- goto illegal_op;
- }
- if (!arm_dc_feature(s, ARM_FEATURE_M) &&
- extract32(insn, 0, 8) != 0) {
- goto illegal_op;
- }
-
- /* mrs cpsr */
- tmp = tcg_temp_new_i32();
- if (arm_dc_feature(s, ARM_FEATURE_M)) {
- addr = tcg_const_i32(insn & 0xff);
- gen_helper_v7m_mrs(tmp, cpu_env, addr);
- tcg_temp_free_i32(addr);
- } else {
- gen_helper_cpsr_read(tmp, cpu_env);
- }
- store_reg(s, rd, tmp);
- break;
- case 7: /* MRS */
- if (extract32(insn, 5, 1) &&
- !arm_dc_feature(s, ARM_FEATURE_M)) {
- /* MRS (banked) */
- int sysm = extract32(insn, 16, 4) |
- (extract32(insn, 4, 1) << 4);
-
- gen_mrs_banked(s, 1, sysm, rd);
- break;
- }
-
- /* mrs spsr. */
- /* Not accessible in user mode. */
- if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
- goto illegal_op;
- }
-
- if (extract32(insn, 16, 4) != 0xf ||
- extract32(insn, 0, 8) != 0) {
- goto illegal_op;
- }
-
- tmp = load_cpu_field(spsr);
- store_reg(s, rd, tmp);
- break;
- }
- }
- } else {
- /* Conditional branch. */
- op = (insn >> 22) & 0xf;
- /* Generate a conditional jump to next instruction. */
- arm_skip_unless(s, op);
-
- /* offset[11:1] = insn[10:0] */
- offset = (insn & 0x7ff) << 1;
- /* offset[17:12] = insn[21:16]. */
- offset |= (insn & 0x003f0000) >> 4;
- /* offset[31:20] = insn[26]. */
- offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;
- /* offset[18] = insn[13]. */
- offset |= (insn & (1 << 13)) << 5;
- /* offset[19] = insn[11]. */
- offset |= (insn & (1 << 11)) << 8;
-
- /* jump to the offset */
- gen_jmp(s, read_pc(s) + offset);
- }
- } else {
- /*
- * 0b1111_0xxx_xxxx_0xxx_xxxx_xxxx
- * - Data-processing (modified immediate, plain binary immediate)
- */
- if (insn & (1 << 25)) {
- /*
- * 0b1111_0x1x_xxxx_0xxx_xxxx_xxxx
- * - Data-processing (plain binary immediate)
- */
- if (insn & (1 << 24)) {
- if (insn & (1 << 20))
- goto illegal_op;
- /* Bitfield/Saturate. */
- op = (insn >> 21) & 7;
- imm = insn & 0x1f;
- shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
- if (rn == 15) {
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, 0);
- } else {
- tmp = load_reg(s, rn);
- }
- switch (op) {
- case 2: /* Signed bitfield extract. */
- imm++;
- if (shift + imm > 32)
- goto illegal_op;
- if (imm < 32) {
- tcg_gen_sextract_i32(tmp, tmp, shift, imm);
- }
- break;
- case 6: /* Unsigned bitfield extract. */
- imm++;
- if (shift + imm > 32)
- goto illegal_op;
- if (imm < 32) {
- tcg_gen_extract_i32(tmp, tmp, shift, imm);
- }
- break;
- case 3: /* Bitfield insert/clear. */
- if (imm < shift)
- goto illegal_op;
- imm = imm + 1 - shift;
- if (imm != 32) {
- tmp2 = load_reg(s, rd);
- tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, imm);
- tcg_temp_free_i32(tmp2);
- }
- break;
- case 7:
- goto illegal_op;
- default: /* Saturate. */
- if (op & 1) {
- tcg_gen_sari_i32(tmp, tmp, shift);
- } else {
- tcg_gen_shli_i32(tmp, tmp, shift);
- }
- tmp2 = tcg_const_i32(imm);
- if (op & 4) {
- /* Unsigned. */
- if ((op & 1) && shift == 0) {
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(tmp2);
- goto illegal_op;
- }
- gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
- } else {
- gen_helper_usat(tmp, cpu_env, tmp, tmp2);
- }
- } else {
- /* Signed. */
- if ((op & 1) && shift == 0) {
- if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(tmp2);
- goto illegal_op;
- }
- gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
- } else {
- gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
- }
- }
- tcg_temp_free_i32(tmp2);
- break;
- }
- store_reg(s, rd, tmp);
- } else {
- imm = ((insn & 0x04000000) >> 15)
- | ((insn & 0x7000) >> 4) | (insn & 0xff);
- if (insn & (1 << 22)) {
- /* 16-bit immediate. */
- imm |= (insn >> 4) & 0xf000;
- if (insn & (1 << 23)) {
- /* movt */
- tmp = load_reg(s, rd);
- tcg_gen_ext16u_i32(tmp, tmp);
- tcg_gen_ori_i32(tmp, tmp, imm << 16);
- } else {
- /* movw */
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, imm);
- }
- store_reg(s, rd, tmp);
- } else {
- /* Add/sub 12-bit immediate. */
- if (insn & (1 << 23)) {
- imm = -imm;
- }
- tmp = add_reg_for_lit(s, rn, imm);
- if (rn == 13 && rd == 13) {
- /* ADD SP, SP, imm or SUB SP, SP, imm */
- store_sp_checked(s, tmp);
- } else {
- store_reg(s, rd, tmp);
- }
- }
- }
- } else {
- /*
- * 0b1111_0x0x_xxxx_0xxx_xxxx_xxxx
- * - Data-processing (modified immediate)
- */
- int shifter_out = 0;
- /* modified 12-bit immediate. */
- shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);
- imm = (insn & 0xff);
- switch (shift) {
- case 0: /* XY */
- /* Nothing to do. */
- break;
- case 1: /* 00XY00XY */
- imm |= imm << 16;
- break;
- case 2: /* XY00XY00 */
- imm |= imm << 16;
- imm <<= 8;
- break;
- case 3: /* XYXYXYXY */
- imm |= imm << 16;
- imm |= imm << 8;
- break;
- default: /* Rotated constant. */
- shift = (shift << 1) | (imm >> 7);
- imm |= 0x80;
- imm = imm << (32 - shift);
- shifter_out = 1;
- break;
- }
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, imm);
- rn = (insn >> 16) & 0xf;
- if (rn == 15) {
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, 0);
- } else {
- tmp = load_reg(s, rn);
- }
- op = (insn >> 21) & 0xf;
- if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
- shifter_out, tmp, tmp2))
- goto illegal_op;
- tcg_temp_free_i32(tmp2);
- rd = (insn >> 8) & 0xf;
- if (rd == 13 && rn == 13
- && (op == 8 || op == 13)) {
- /* ADD(S) SP, SP, imm or SUB(S) SP, SP, imm */
- store_sp_checked(s, tmp);
- } else if (rd != 15) {
- store_reg(s, rd, tmp);
- } else {
- tcg_temp_free_i32(tmp);
- }
- }
- }
- break;
- case 12: /* Load/store single data item. */
- {
- int postinc = 0;
- int writeback = 0;
- int memidx;
- ISSInfo issinfo;
-
+ case 12:
if ((insn & 0x01100000) == 0x01000000) {
if (disas_neon_ls_insn(s, insn)) {
goto illegal_op;
}
break;
}
- op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
- if (rs == 15) {
- if (!(insn & (1 << 20))) {
- goto illegal_op;
- }
- if (op != 2) {
- /* Byte or halfword load space with dest == r15 : memory hints.
- * Catch them early so we don't emit pointless addressing code.
- * This space is a mix of:
- * PLD/PLDW/PLI, which we implement as NOPs (note that unlike
- * the ARM encodings, PLDW space doesn't UNDEF for non-v7MP
- * cores)
- * unallocated hints, which must be treated as NOPs
- * UNPREDICTABLE space, which we NOP or UNDEF depending on
- * which is easiest for the decoding logic
- * Some space which must UNDEF
- */
- int op1 = (insn >> 23) & 3;
- int op2 = (insn >> 6) & 0x3f;
- if (op & 2) {
- goto illegal_op;
- }
- if (rn == 15) {
- /* UNPREDICTABLE, unallocated hint or
- * PLD/PLDW/PLI (literal)
- */
- return;
- }
- if (op1 & 1) {
- return; /* PLD/PLDW/PLI or unallocated hint */
- }
- if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {
- return; /* PLD/PLDW/PLI or unallocated hint */
- }
- /* UNDEF space, or an UNPREDICTABLE */
- goto illegal_op;
- }
- }
- memidx = get_mem_index(s);
- imm = insn & 0xfff;
- if (insn & (1 << 23)) {
- /* PC relative or Positive offset. */
- addr = add_reg_for_lit(s, rn, imm);
- } else if (rn == 15) {
- /* PC relative with negative offset. */
- addr = add_reg_for_lit(s, rn, -imm);
- } else {
- addr = load_reg(s, rn);
- imm = insn & 0xff;
- switch ((insn >> 8) & 0xf) {
- case 0x0: /* Shifted Register. */
- shift = (insn >> 4) & 0xf;
- if (shift > 3) {
- tcg_temp_free_i32(addr);
- goto illegal_op;
- }
- tmp = load_reg(s, rm);
- tcg_gen_shli_i32(tmp, tmp, shift);
- tcg_gen_add_i32(addr, addr, tmp);
- tcg_temp_free_i32(tmp);
- break;
- case 0xc: /* Negative offset. */
- tcg_gen_addi_i32(addr, addr, -imm);
- break;
- case 0xe: /* User privilege. */
- tcg_gen_addi_i32(addr, addr, imm);
- memidx = get_a32_user_mem_index(s);
- break;
- case 0x9: /* Post-decrement. */
- imm = -imm;
- /* Fall through. */
- case 0xb: /* Post-increment. */
- postinc = 1;
- writeback = 1;
- break;
- case 0xd: /* Pre-decrement. */
- imm = -imm;
- /* Fall through. */
- case 0xf: /* Pre-increment. */
- writeback = 1;
- break;
- default:
- tcg_temp_free_i32(addr);
- goto illegal_op;
- }
- }
-
- issinfo = writeback ? ISSInvalid : rs;
-
- if (s->v8m_stackcheck && rn == 13 && writeback) {
- /*
- * Stackcheck. Here we know 'addr' is the current SP;
- * if imm is +ve we're moving SP up, else down. It is
- * UNKNOWN whether the limit check triggers when SP starts
- * below the limit and ends up above it; we chose to do so.
- */
- if ((int32_t)imm < 0) {
- TCGv_i32 newsp = tcg_temp_new_i32();
-
- tcg_gen_addi_i32(newsp, addr, imm);
- gen_helper_v8m_stackcheck(cpu_env, newsp);
- tcg_temp_free_i32(newsp);
- } else {
- gen_helper_v8m_stackcheck(cpu_env, addr);
- }
- }
-
- if (writeback && !postinc) {
- tcg_gen_addi_i32(addr, addr, imm);
- }
-
- if (insn & (1 << 20)) {
- /* Load. */
- tmp = tcg_temp_new_i32();
- switch (op) {
- case 0:
- gen_aa32_ld8u_iss(s, tmp, addr, memidx, issinfo);
- break;
- case 4:
- gen_aa32_ld8s_iss(s, tmp, addr, memidx, issinfo);
- break;
- case 1:
- gen_aa32_ld16u_iss(s, tmp, addr, memidx, issinfo);
- break;
- case 5:
- gen_aa32_ld16s_iss(s, tmp, addr, memidx, issinfo);
- break;
- case 2:
- gen_aa32_ld32u_iss(s, tmp, addr, memidx, issinfo);
- break;
- default:
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(addr);
- goto illegal_op;
- }
- if (rs == 15) {
- gen_bx_excret(s, tmp);
- } else {
- store_reg(s, rs, tmp);
- }
- } else {
- /* Store. */
- tmp = load_reg(s, rs);
- switch (op) {
- case 0:
- gen_aa32_st8_iss(s, tmp, addr, memidx, issinfo);
- break;
- case 1:
- gen_aa32_st16_iss(s, tmp, addr, memidx, issinfo);
- break;
- case 2:
- gen_aa32_st32_iss(s, tmp, addr, memidx, issinfo);
- break;
- default:
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(addr);
- goto illegal_op;
- }
- tcg_temp_free_i32(tmp);
- }
- if (postinc)
- tcg_gen_addi_i32(addr, addr, imm);
- if (writeback) {
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- }
- break;
- default:
goto illegal_op;
+ default:
+ illegal_op:
+ unallocated_encoding(s);
}
- return;
-illegal_op:
- unallocated_encoding(s);
}
static void disas_thumb_insn(DisasContext *s, uint32_t insn)
{
- uint32_t val, op, rm, rn, rd, shift, cond;
- int32_t offset;
- int i;
- TCGv_i32 tmp;
- TCGv_i32 tmp2;
- TCGv_i32 addr;
-
- switch (insn >> 12) {
- case 0: case 1:
-
- rd = insn & 7;
- op = (insn >> 11) & 3;
- if (op == 3) {
- /*
- * 0b0001_1xxx_xxxx_xxxx
- * - Add, subtract (three low registers)
- * - Add, subtract (two low registers and immediate)
- */
- rn = (insn >> 3) & 7;
- tmp = load_reg(s, rn);
- if (insn & (1 << 10)) {
- /* immediate */
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
- } else {
- /* reg */
- rm = (insn >> 6) & 7;
- tmp2 = load_reg(s, rm);
- }
- if (insn & (1 << 9)) {
- if (s->condexec_mask)
- tcg_gen_sub_i32(tmp, tmp, tmp2);
- else
- gen_sub_CC(tmp, tmp, tmp2);
- } else {
- if (s->condexec_mask)
- tcg_gen_add_i32(tmp, tmp, tmp2);
- else
- gen_add_CC(tmp, tmp, tmp2);
- }
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- } else {
- /* shift immediate */
- rm = (insn >> 3) & 7;
- shift = (insn >> 6) & 0x1f;
- tmp = load_reg(s, rm);
- gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0);
- if (!s->condexec_mask)
- gen_logic_CC(tmp);
- store_reg(s, rd, tmp);
- }
- break;
- case 2: case 3:
- /*
- * 0b001x_xxxx_xxxx_xxxx
- * - Add, subtract, compare, move (one low register and immediate)
- */
- op = (insn >> 11) & 3;
- rd = (insn >> 8) & 0x7;
- if (op == 0) { /* mov */
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, insn & 0xff);
- if (!s->condexec_mask)
- gen_logic_CC(tmp);
- store_reg(s, rd, tmp);
- } else {
- tmp = load_reg(s, rd);
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, insn & 0xff);
- switch (op) {
- case 1: /* cmp */
- gen_sub_CC(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(tmp2);
- break;
- case 2: /* add */
- if (s->condexec_mask)
- tcg_gen_add_i32(tmp, tmp, tmp2);
- else
- gen_add_CC(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- break;
- case 3: /* sub */
- if (s->condexec_mask)
- tcg_gen_sub_i32(tmp, tmp, tmp2);
- else
- gen_sub_CC(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- store_reg(s, rd, tmp);
- break;
- }
- }
- break;
- case 4:
- if (insn & (1 << 11)) {
- rd = (insn >> 8) & 7;
- /* load pc-relative. Bit 1 of PC is ignored. */
- addr = add_reg_for_lit(s, 15, (insn & 0xff) * 4);
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
- rd | ISSIs16Bit);
- tcg_temp_free_i32(addr);
- store_reg(s, rd, tmp);
- break;
- }
- if (insn & (1 << 10)) {
- /* 0b0100_01xx_xxxx_xxxx
- * - data processing extended, branch and exchange
- */
- rd = (insn & 7) | ((insn >> 4) & 8);
- rm = (insn >> 3) & 0xf;
- op = (insn >> 8) & 3;
- switch (op) {
- case 0: /* add */
- tmp = load_reg(s, rd);
- tmp2 = load_reg(s, rm);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- if (rd == 13) {
- /* ADD SP, SP, reg */
- store_sp_checked(s, tmp);
- } else {
- store_reg(s, rd, tmp);
- }
- break;
- case 1: /* cmp */
- tmp = load_reg(s, rd);
- tmp2 = load_reg(s, rm);
- gen_sub_CC(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i32(tmp);
- break;
- case 2: /* mov/cpy */
- tmp = load_reg(s, rm);
- if (rd == 13) {
- /* MOV SP, reg */
- store_sp_checked(s, tmp);
- } else {
- store_reg(s, rd, tmp);
- }
- break;
- case 3:
- {
- /* 0b0100_0111_xxxx_xxxx
- * - branch [and link] exchange thumb register
- */
- bool link = insn & (1 << 7);
-
- if (insn & 3) {
- goto undef;
- }
- if (link) {
- ARCH(5);
- }
- if ((insn & 4)) {
- /* BXNS/BLXNS: only exists for v8M with the
- * security extensions, and always UNDEF if NonSecure.
- * We don't implement these in the user-only mode
- * either (in theory you can use them from Secure User
- * mode but they are too tied in to system emulation.)
- */
- if (!s->v8m_secure || IS_USER_ONLY) {
- goto undef;
- }
- if (link) {
- gen_blxns(s, rm);
- } else {
- gen_bxns(s, rm);
- }
- break;
- }
- /* BLX/BX */
- tmp = load_reg(s, rm);
- if (link) {
- val = (uint32_t)s->base.pc_next | 1;
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, val);
- store_reg(s, 14, tmp2);
- gen_bx(s, tmp);
- } else {
- /* Only BX works as exception-return, not BLX */
- gen_bx_excret(s, tmp);
- }
- break;
- }
- }
- break;
- }
-
- /*
- * 0b0100_00xx_xxxx_xxxx
- * - Data-processing (two low registers)
- */
- rd = insn & 7;
- rm = (insn >> 3) & 7;
- op = (insn >> 6) & 0xf;
- if (op == 2 || op == 3 || op == 4 || op == 7) {
- /* the shift/rotate ops want the operands backwards */
- val = rm;
- rm = rd;
- rd = val;
- val = 1;
- } else {
- val = 0;
- }
-
- if (op == 9) { /* neg */
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, 0);
- } else if (op != 0xf) { /* mvn doesn't read its first operand */
- tmp = load_reg(s, rd);
- } else {
- tmp = NULL;
- }
-
- tmp2 = load_reg(s, rm);
- switch (op) {
- case 0x0: /* and */
- tcg_gen_and_i32(tmp, tmp, tmp2);
- if (!s->condexec_mask)
- gen_logic_CC(tmp);
- break;
- case 0x1: /* eor */
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- if (!s->condexec_mask)
- gen_logic_CC(tmp);
- break;
- case 0x2: /* lsl */
- if (s->condexec_mask) {
- gen_shl(tmp2, tmp2, tmp);
- } else {
- gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp);
- gen_logic_CC(tmp2);
- }
- break;
- case 0x3: /* lsr */
- if (s->condexec_mask) {
- gen_shr(tmp2, tmp2, tmp);
- } else {
- gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp);
- gen_logic_CC(tmp2);
- }
- break;
- case 0x4: /* asr */
- if (s->condexec_mask) {
- gen_sar(tmp2, tmp2, tmp);
- } else {
- gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp);
- gen_logic_CC(tmp2);
- }
- break;
- case 0x5: /* adc */
- if (s->condexec_mask) {
- gen_adc(tmp, tmp2);
- } else {
- gen_adc_CC(tmp, tmp, tmp2);
- }
- break;
- case 0x6: /* sbc */
- if (s->condexec_mask) {
- gen_sub_carry(tmp, tmp, tmp2);
- } else {
- gen_sbc_CC(tmp, tmp, tmp2);
- }
- break;
- case 0x7: /* ror */
- if (s->condexec_mask) {
- tcg_gen_andi_i32(tmp, tmp, 0x1f);
- tcg_gen_rotr_i32(tmp2, tmp2, tmp);
- } else {
- gen_helper_ror_cc(tmp2, cpu_env, tmp2, tmp);
- gen_logic_CC(tmp2);
- }
- break;
- case 0x8: /* tst */
- tcg_gen_and_i32(tmp, tmp, tmp2);
- gen_logic_CC(tmp);
- rd = 16;
- break;
- case 0x9: /* neg */
- if (s->condexec_mask)
- tcg_gen_neg_i32(tmp, tmp2);
- else
- gen_sub_CC(tmp, tmp, tmp2);
- break;
- case 0xa: /* cmp */
- gen_sub_CC(tmp, tmp, tmp2);
- rd = 16;
- break;
- case 0xb: /* cmn */
- gen_add_CC(tmp, tmp, tmp2);
- rd = 16;
- break;
- case 0xc: /* orr */
- tcg_gen_or_i32(tmp, tmp, tmp2);
- if (!s->condexec_mask)
- gen_logic_CC(tmp);
- break;
- case 0xd: /* mul */
- tcg_gen_mul_i32(tmp, tmp, tmp2);
- if (!s->condexec_mask)
- gen_logic_CC(tmp);
- break;
- case 0xe: /* bic */
- tcg_gen_andc_i32(tmp, tmp, tmp2);
- if (!s->condexec_mask)
- gen_logic_CC(tmp);
- break;
- case 0xf: /* mvn */
- tcg_gen_not_i32(tmp2, tmp2);
- if (!s->condexec_mask)
- gen_logic_CC(tmp2);
- val = 1;
- rm = rd;
- break;
- }
- if (rd != 16) {
- if (val) {
- store_reg(s, rm, tmp2);
- if (op != 0xf)
- tcg_temp_free_i32(tmp);
- } else {
- store_reg(s, rd, tmp);
- tcg_temp_free_i32(tmp2);
- }
- } else {
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(tmp2);
- }
- break;
-
- case 5:
- /* load/store register offset. */
- rd = insn & 7;
- rn = (insn >> 3) & 7;
- rm = (insn >> 6) & 7;
- op = (insn >> 9) & 7;
- addr = load_reg(s, rn);
- tmp = load_reg(s, rm);
- tcg_gen_add_i32(addr, addr, tmp);
- tcg_temp_free_i32(tmp);
-
- if (op < 3) { /* store */
- tmp = load_reg(s, rd);
- } else {
- tmp = tcg_temp_new_i32();
- }
-
- switch (op) {
- case 0: /* str */
- gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- break;
- case 1: /* strh */
- gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- break;
- case 2: /* strb */
- gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- break;
- case 3: /* ldrsb */
- gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- break;
- case 4: /* ldr */
- gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- break;
- case 5: /* ldrh */
- gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- break;
- case 6: /* ldrb */
- gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- break;
- case 7: /* ldrsh */
- gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- break;
- }
- if (op >= 3) { /* load */
- store_reg(s, rd, tmp);
- } else {
- tcg_temp_free_i32(tmp);
- }
- tcg_temp_free_i32(addr);
- break;
-
- case 6:
- /* load/store word immediate offset */
- rd = insn & 7;
- rn = (insn >> 3) & 7;
- addr = load_reg(s, rn);
- val = (insn >> 4) & 0x7c;
- tcg_gen_addi_i32(addr, addr, val);
-
- if (insn & (1 << 11)) {
- /* load */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- store_reg(s, rd, tmp);
- } else {
- /* store */
- tmp = load_reg(s, rd);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- }
- tcg_temp_free_i32(addr);
- break;
-
- case 7:
- /* load/store byte immediate offset */
- rd = insn & 7;
- rn = (insn >> 3) & 7;
- addr = load_reg(s, rn);
- val = (insn >> 6) & 0x1f;
- tcg_gen_addi_i32(addr, addr, val);
-
- if (insn & (1 << 11)) {
- /* load */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- store_reg(s, rd, tmp);
- } else {
- /* store */
- tmp = load_reg(s, rd);
- gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- tcg_temp_free_i32(tmp);
- }
- tcg_temp_free_i32(addr);
- break;
-
- case 8:
- /* load/store halfword immediate offset */
- rd = insn & 7;
- rn = (insn >> 3) & 7;
- addr = load_reg(s, rn);
- val = (insn >> 5) & 0x3e;
- tcg_gen_addi_i32(addr, addr, val);
-
- if (insn & (1 << 11)) {
- /* load */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- store_reg(s, rd, tmp);
- } else {
- /* store */
- tmp = load_reg(s, rd);
- gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- tcg_temp_free_i32(tmp);
- }
- tcg_temp_free_i32(addr);
- break;
-
- case 9:
- /* load/store from stack */
- rd = (insn >> 8) & 7;
- addr = load_reg(s, 13);
- val = (insn & 0xff) * 4;
- tcg_gen_addi_i32(addr, addr, val);
-
- if (insn & (1 << 11)) {
- /* load */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- store_reg(s, rd, tmp);
- } else {
- /* store */
- tmp = load_reg(s, rd);
- gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
- tcg_temp_free_i32(tmp);
- }
- tcg_temp_free_i32(addr);
- break;
-
- case 10:
- /*
- * 0b1010_xxxx_xxxx_xxxx
- * - Add PC/SP (immediate)
- */
- rd = (insn >> 8) & 7;
- val = (insn & 0xff) * 4;
- tmp = add_reg_for_lit(s, insn & (1 << 11) ? 13 : 15, val);
- store_reg(s, rd, tmp);
- break;
-
- case 11:
- /* misc */
- op = (insn >> 8) & 0xf;
- switch (op) {
- case 0:
- /*
- * 0b1011_0000_xxxx_xxxx
- * - ADD (SP plus immediate)
- * - SUB (SP minus immediate)
- */
- tmp = load_reg(s, 13);
- val = (insn & 0x7f) * 4;
- if (insn & (1 << 7))
- val = -(int32_t)val;
- tcg_gen_addi_i32(tmp, tmp, val);
- store_sp_checked(s, tmp);
- break;
-
- case 2: /* sign/zero extend. */
- ARCH(6);
- rd = insn & 7;
- rm = (insn >> 3) & 7;
- tmp = load_reg(s, rm);
- switch ((insn >> 6) & 3) {
- case 0: gen_sxth(tmp); break;
- case 1: gen_sxtb(tmp); break;
- case 2: gen_uxth(tmp); break;
- case 3: gen_uxtb(tmp); break;
- }
- store_reg(s, rd, tmp);
- break;
- case 4: case 5: case 0xc: case 0xd:
- /*
- * 0b1011_x10x_xxxx_xxxx
- * - push/pop
- */
- addr = load_reg(s, 13);
- if (insn & (1 << 8))
- offset = 4;
- else
- offset = 0;
- for (i = 0; i < 8; i++) {
- if (insn & (1 << i))
- offset += 4;
- }
- if ((insn & (1 << 11)) == 0) {
- tcg_gen_addi_i32(addr, addr, -offset);
- }
-
- if (s->v8m_stackcheck) {
- /*
- * Here 'addr' is the lower of "old SP" and "new SP";
- * if this is a pop that starts below the limit and ends
- * above it, it is UNKNOWN whether the limit check triggers;
- * we choose to trigger.
- */
- gen_helper_v8m_stackcheck(cpu_env, addr);
- }
-
- for (i = 0; i < 8; i++) {
- if (insn & (1 << i)) {
- if (insn & (1 << 11)) {
- /* pop */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- store_reg(s, i, tmp);
- } else {
- /* push */
- tmp = load_reg(s, i);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- }
- /* advance to the next address. */
- tcg_gen_addi_i32(addr, addr, 4);
- }
- }
- tmp = NULL;
- if (insn & (1 << 8)) {
- if (insn & (1 << 11)) {
- /* pop pc */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- /* don't set the pc until the rest of the instruction
- has completed */
- } else {
- /* push lr */
- tmp = load_reg(s, 14);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- }
- tcg_gen_addi_i32(addr, addr, 4);
- }
- if ((insn & (1 << 11)) == 0) {
- tcg_gen_addi_i32(addr, addr, -offset);
- }
- /* write back the new stack pointer */
- store_reg(s, 13, addr);
- /* set the new PC value */
- if ((insn & 0x0900) == 0x0900) {
- store_reg_from_load(s, 15, tmp);
- }
- break;
-
- case 1: case 3: case 9: case 11: /* czb */
- rm = insn & 7;
- tmp = load_reg(s, rm);
- arm_gen_condlabel(s);
- if (insn & (1 << 11))
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
- else
- tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
- tcg_temp_free_i32(tmp);
- offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
- gen_jmp(s, read_pc(s) + offset);
- break;
-
- case 15: /* IT, nop-hint. */
- if ((insn & 0xf) == 0) {
- gen_nop_hint(s, (insn >> 4) & 0xf);
- break;
- }
- /*
- * IT (If-Then)
- *
- * Combinations of firstcond and mask which set up an 0b1111
- * condition are UNPREDICTABLE; we take the CONSTRAINED
- * UNPREDICTABLE choice to treat 0b1111 the same as 0b1110,
- * i.e. both meaning "execute always".
- */
- s->condexec_cond = (insn >> 4) & 0xe;
- s->condexec_mask = insn & 0x1f;
- /* No actual code generated for this insn, just setup state. */
- break;
-
- case 0xe: /* bkpt */
- {
- int imm8 = extract32(insn, 0, 8);
- ARCH(5);
- gen_exception_bkpt_insn(s, syn_aa32_bkpt(imm8, true));
- break;
- }
-
- case 0xa: /* rev, and hlt */
- {
- int op1 = extract32(insn, 6, 2);
-
- if (op1 == 2) {
- /* HLT */
- int imm6 = extract32(insn, 0, 6);
-
- gen_hlt(s, imm6);
- break;
- }
-
- /* Otherwise this is rev */
- ARCH(6);
- rn = (insn >> 3) & 0x7;
- rd = insn & 0x7;
- tmp = load_reg(s, rn);
- switch (op1) {
- case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
- case 1: gen_rev16(tmp); break;
- case 3: gen_revsh(tmp); break;
- default:
- g_assert_not_reached();
- }
- store_reg(s, rd, tmp);
- break;
- }
-
- case 6:
- switch ((insn >> 5) & 7) {
- case 2:
- /* setend */
- ARCH(6);
- if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
- gen_helper_setend(cpu_env);
- s->base.is_jmp = DISAS_UPDATE;
- }
- break;
- case 3:
- /* cps */
- ARCH(6);
- if (IS_USER(s)) {
- break;
- }
- if (arm_dc_feature(s, ARM_FEATURE_M)) {
- tmp = tcg_const_i32((insn & (1 << 4)) != 0);
- /* FAULTMASK */
- if (insn & 1) {
- addr = tcg_const_i32(19);
- gen_helper_v7m_msr(cpu_env, addr, tmp);
- tcg_temp_free_i32(addr);
- }
- /* PRIMASK */
- if (insn & 2) {
- addr = tcg_const_i32(16);
- gen_helper_v7m_msr(cpu_env, addr, tmp);
- tcg_temp_free_i32(addr);
- }
- tcg_temp_free_i32(tmp);
- gen_lookup_tb(s);
- } else {
- if (insn & (1 << 4)) {
- shift = CPSR_A | CPSR_I | CPSR_F;
- } else {
- shift = 0;
- }
- gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
- }
- break;
- default:
- goto undef;
- }
- break;
-
- default:
- goto undef;
- }
- break;
-
- case 12:
- {
- /* load/store multiple */
- TCGv_i32 loaded_var = NULL;
- rn = (insn >> 8) & 0x7;
- addr = load_reg(s, rn);
- for (i = 0; i < 8; i++) {
- if (insn & (1 << i)) {
- if (insn & (1 << 11)) {
- /* load */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- if (i == rn) {
- loaded_var = tmp;
- } else {
- store_reg(s, i, tmp);
- }
- } else {
- /* store */
- tmp = load_reg(s, i);
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
- tcg_temp_free_i32(tmp);
- }
- /* advance to the next address */
- tcg_gen_addi_i32(addr, addr, 4);
- }
- }
- if ((insn & (1 << rn)) == 0) {
- /* base reg not in list: base register writeback */
- store_reg(s, rn, addr);
- } else {
- /* base reg in list: if load, complete it now */
- if (insn & (1 << 11)) {
- store_reg(s, rn, loaded_var);
- }
- tcg_temp_free_i32(addr);
- }
- break;
- }
- case 13:
- /* conditional branch or swi */
- cond = (insn >> 8) & 0xf;
- if (cond == 0xe)
- goto undef;
-
- if (cond == 0xf) {
- /* swi */
- gen_set_pc_im(s, s->base.pc_next);
- s->svc_imm = extract32(insn, 0, 8);
- s->base.is_jmp = DISAS_SWI;
- break;
- }
- /* generate a conditional jump to next instruction */
- arm_skip_unless(s, cond);
-
- /* jump to the offset */
- val = read_pc(s);
- offset = ((int32_t)insn << 24) >> 24;
- val += offset << 1;
- gen_jmp(s, val);
- break;
-
- case 14:
- if (insn & (1 << 11)) {
- /* thumb_insn_is_16bit() ensures we can't get here for
- * a Thumb2 CPU, so this must be a thumb1 split BL/BLX:
- * 0b1110_1xxx_xxxx_xxxx : BLX suffix (or UNDEF)
- */
- assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
- ARCH(5);
- offset = ((insn & 0x7ff) << 1);
- tmp = load_reg(s, 14);
- tcg_gen_addi_i32(tmp, tmp, offset);
- tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
-
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, s->base.pc_next | 1);
- store_reg(s, 14, tmp2);
- gen_bx(s, tmp);
- break;
- }
- /* unconditional branch */
- val = read_pc(s);
- offset = ((int32_t)insn << 21) >> 21;
- val += offset << 1;
- gen_jmp(s, val);
- break;
-
- case 15:
- /* thumb_insn_is_16bit() ensures we can't get here for
- * a Thumb2 CPU, so this must be a thumb1 split BL/BLX.
- */
- assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
-
- if (insn & (1 << 11)) {
- /* 0b1111_1xxx_xxxx_xxxx : BL suffix */
- offset = ((insn & 0x7ff) << 1) | 1;
- tmp = load_reg(s, 14);
- tcg_gen_addi_i32(tmp, tmp, offset);
-
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, s->base.pc_next | 1);
- store_reg(s, 14, tmp2);
- gen_bx(s, tmp);
- } else {
- /* 0b1111_0xxx_xxxx_xxxx : BL/BLX prefix */
- uint32_t uoffset = ((int32_t)insn << 21) >> 9;
-
- tcg_gen_movi_i32(cpu_R[14], read_pc(s) + uoffset);
- }
- break;
+ if (!disas_t16(s, insn)) {
+ unallocated_encoding(s);
}
- return;
-illegal_op:
-undef:
- unallocated_encoding(s);
}
static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 92ef790be9..dd24f91f26 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -23,7 +23,7 @@ typedef struct DisasContext {
int condexec_cond;
int thumb;
int sctlr_b;
- TCGMemOp be_data;
+ MemOp be_data;
#if !defined(CONFIG_USER_ONLY)
int user;
#endif
@@ -99,8 +99,6 @@ typedef struct DisasCompare {
bool value_global;
} DisasCompare;
-void unallocated_encoding(DisasContext *s);
-
/* Share the TCG temporaries common between 32 and 64 bit modes. */
extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
extern TCGv_i64 cpu_exclusive_addr;
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index df0f1361ef..f0516e81f1 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -137,9 +137,7 @@ static void do_stby_e(CPUHPPAState *env, target_ulong addr, target_ureg val,
default:
/* Nothing is stored, but protection is checked and the
cacheline is marked dirty. */
-#ifndef CONFIG_USER_ONLY
probe_write(env, addr, 0, cpu_mmu_index(env, 0), ra);
-#endif
break;
}
}
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 8c6189512c..53e17d8963 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -1500,7 +1500,7 @@ static void form_gva(DisasContext *ctx, TCGv_tl *pgva, TCGv_reg *pofs,
*/
static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
unsigned rx, int scale, target_sreg disp,
- unsigned sp, int modify, TCGMemOp mop)
+ unsigned sp, int modify, MemOp mop)
{
TCGv_reg ofs;
TCGv_tl addr;
@@ -1518,7 +1518,7 @@ static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
unsigned rx, int scale, target_sreg disp,
- unsigned sp, int modify, TCGMemOp mop)
+ unsigned sp, int modify, MemOp mop)
{
TCGv_reg ofs;
TCGv_tl addr;
@@ -1536,7 +1536,7 @@ static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
unsigned rx, int scale, target_sreg disp,
- unsigned sp, int modify, TCGMemOp mop)
+ unsigned sp, int modify, MemOp mop)
{
TCGv_reg ofs;
TCGv_tl addr;
@@ -1554,7 +1554,7 @@ static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
unsigned rx, int scale, target_sreg disp,
- unsigned sp, int modify, TCGMemOp mop)
+ unsigned sp, int modify, MemOp mop)
{
TCGv_reg ofs;
TCGv_tl addr;
@@ -1580,7 +1580,7 @@ static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
unsigned rx, int scale, target_sreg disp,
- unsigned sp, int modify, TCGMemOp mop)
+ unsigned sp, int modify, MemOp mop)
{
TCGv_reg dest;
@@ -1653,7 +1653,7 @@ static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
target_sreg disp, unsigned sp,
- int modify, TCGMemOp mop)
+ int modify, MemOp mop)
{
nullify_over(ctx);
do_store_reg(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
@@ -2939,7 +2939,7 @@ static bool trans_st(DisasContext *ctx, arg_ldst *a)
static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
{
- TCGMemOp mop = MO_TEUL | MO_ALIGN_16 | a->size;
+ MemOp mop = MO_TEUL | MO_ALIGN_16 | a->size;
TCGv_reg zero, dest, ofs;
TCGv_tl addr;
diff --git a/target/i386/translate.c b/target/i386/translate.c
index 5cd74ad639..868b0acafe 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -87,8 +87,8 @@ typedef struct DisasContext {
/* current insn context */
int override; /* -1 if no override */
int prefix;
- TCGMemOp aflag;
- TCGMemOp dflag;
+ MemOp aflag;
+ MemOp dflag;
target_ulong pc_start;
target_ulong pc; /* pc = eip + cs_base */
/* current block context */
@@ -149,7 +149,7 @@ static void gen_eob(DisasContext *s);
static void gen_jr(DisasContext *s, TCGv dest);
static void gen_jmp(DisasContext *s, target_ulong eip);
static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
-static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d);
+static void gen_op(DisasContext *s1, int op, MemOp ot, int d);
/* i386 arith/logic operations */
enum {
@@ -320,7 +320,7 @@ static inline bool byte_reg_is_xH(DisasContext *s, int reg)
}
/* Select the size of a push/pop operation. */
-static inline TCGMemOp mo_pushpop(DisasContext *s, TCGMemOp ot)
+static inline MemOp mo_pushpop(DisasContext *s, MemOp ot)
{
if (CODE64(s)) {
return ot == MO_16 ? MO_16 : MO_64;
@@ -330,13 +330,13 @@ static inline TCGMemOp mo_pushpop(DisasContext *s, TCGMemOp ot)
}
/* Select the size of the stack pointer. */
-static inline TCGMemOp mo_stacksize(DisasContext *s)
+static inline MemOp mo_stacksize(DisasContext *s)
{
return CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16;
}
/* Select only size 64 else 32. Used for SSE operand sizes. */
-static inline TCGMemOp mo_64_32(TCGMemOp ot)
+static inline MemOp mo_64_32(MemOp ot)
{
#ifdef TARGET_X86_64
return ot == MO_64 ? MO_64 : MO_32;
@@ -347,19 +347,19 @@ static inline TCGMemOp mo_64_32(TCGMemOp ot)
/* Select size 8 if lsb of B is clear, else OT. Used for decoding
byte vs word opcodes. */
-static inline TCGMemOp mo_b_d(int b, TCGMemOp ot)
+static inline MemOp mo_b_d(int b, MemOp ot)
{
return b & 1 ? ot : MO_8;
}
/* Select size 8 if lsb of B is clear, else OT capped at 32.
Used for decoding operand size of port opcodes. */
-static inline TCGMemOp mo_b_d32(int b, TCGMemOp ot)
+static inline MemOp mo_b_d32(int b, MemOp ot)
{
return b & 1 ? (ot == MO_16 ? MO_16 : MO_32) : MO_8;
}
-static void gen_op_mov_reg_v(DisasContext *s, TCGMemOp ot, int reg, TCGv t0)
+static void gen_op_mov_reg_v(DisasContext *s, MemOp ot, int reg, TCGv t0)
{
switch(ot) {
case MO_8:
@@ -388,7 +388,7 @@ static void gen_op_mov_reg_v(DisasContext *s, TCGMemOp ot, int reg, TCGv t0)
}
static inline
-void gen_op_mov_v_reg(DisasContext *s, TCGMemOp ot, TCGv t0, int reg)
+void gen_op_mov_v_reg(DisasContext *s, MemOp ot, TCGv t0, int reg)
{
if (ot == MO_8 && byte_reg_is_xH(s, reg)) {
tcg_gen_extract_tl(t0, cpu_regs[reg - 4], 8, 8);
@@ -411,13 +411,13 @@ static inline void gen_op_jmp_v(TCGv dest)
}
static inline
-void gen_op_add_reg_im(DisasContext *s, TCGMemOp size, int reg, int32_t val)
+void gen_op_add_reg_im(DisasContext *s, MemOp size, int reg, int32_t val)
{
tcg_gen_addi_tl(s->tmp0, cpu_regs[reg], val);
gen_op_mov_reg_v(s, size, reg, s->tmp0);
}
-static inline void gen_op_add_reg_T0(DisasContext *s, TCGMemOp size, int reg)
+static inline void gen_op_add_reg_T0(DisasContext *s, MemOp size, int reg)
{
tcg_gen_add_tl(s->tmp0, cpu_regs[reg], s->T0);
gen_op_mov_reg_v(s, size, reg, s->tmp0);
@@ -451,7 +451,7 @@ static inline void gen_jmp_im(DisasContext *s, target_ulong pc)
/* Compute SEG:REG into A0. SEG is selected from the override segment
(OVR_SEG) and the default segment (DEF_SEG). OVR_SEG may be -1 to
indicate no override. */
-static void gen_lea_v_seg(DisasContext *s, TCGMemOp aflag, TCGv a0,
+static void gen_lea_v_seg(DisasContext *s, MemOp aflag, TCGv a0,
int def_seg, int ovr_seg)
{
switch (aflag) {
@@ -514,13 +514,13 @@ static inline void gen_string_movl_A0_EDI(DisasContext *s)
gen_lea_v_seg(s, s->aflag, cpu_regs[R_EDI], R_ES, -1);
}
-static inline void gen_op_movl_T0_Dshift(DisasContext *s, TCGMemOp ot)
+static inline void gen_op_movl_T0_Dshift(DisasContext *s, MemOp ot)
{
tcg_gen_ld32s_tl(s->T0, cpu_env, offsetof(CPUX86State, df));
tcg_gen_shli_tl(s->T0, s->T0, ot);
};
-static TCGv gen_ext_tl(TCGv dst, TCGv src, TCGMemOp size, bool sign)
+static TCGv gen_ext_tl(TCGv dst, TCGv src, MemOp size, bool sign)
{
switch (size) {
case MO_8:
@@ -551,18 +551,18 @@ static TCGv gen_ext_tl(TCGv dst, TCGv src, TCGMemOp size, bool sign)
}
}
-static void gen_extu(TCGMemOp ot, TCGv reg)
+static void gen_extu(MemOp ot, TCGv reg)
{
gen_ext_tl(reg, reg, ot, false);
}
-static void gen_exts(TCGMemOp ot, TCGv reg)
+static void gen_exts(MemOp ot, TCGv reg)
{
gen_ext_tl(reg, reg, ot, true);
}
static inline
-void gen_op_jnz_ecx(DisasContext *s, TCGMemOp size, TCGLabel *label1)
+void gen_op_jnz_ecx(DisasContext *s, MemOp size, TCGLabel *label1)
{
tcg_gen_mov_tl(s->tmp0, cpu_regs[R_ECX]);
gen_extu(size, s->tmp0);
@@ -570,14 +570,14 @@ void gen_op_jnz_ecx(DisasContext *s, TCGMemOp size, TCGLabel *label1)
}
static inline
-void gen_op_jz_ecx(DisasContext *s, TCGMemOp size, TCGLabel *label1)
+void gen_op_jz_ecx(DisasContext *s, MemOp size, TCGLabel *label1)
{
tcg_gen_mov_tl(s->tmp0, cpu_regs[R_ECX]);
gen_extu(size, s->tmp0);
tcg_gen_brcondi_tl(TCG_COND_EQ, s->tmp0, 0, label1);
}
-static void gen_helper_in_func(TCGMemOp ot, TCGv v, TCGv_i32 n)
+static void gen_helper_in_func(MemOp ot, TCGv v, TCGv_i32 n)
{
switch (ot) {
case MO_8:
@@ -594,7 +594,7 @@ static void gen_helper_in_func(TCGMemOp ot, TCGv v, TCGv_i32 n)
}
}
-static void gen_helper_out_func(TCGMemOp ot, TCGv_i32 v, TCGv_i32 n)
+static void gen_helper_out_func(MemOp ot, TCGv_i32 v, TCGv_i32 n)
{
switch (ot) {
case MO_8:
@@ -611,7 +611,7 @@ static void gen_helper_out_func(TCGMemOp ot, TCGv_i32 v, TCGv_i32 n)
}
}
-static void gen_check_io(DisasContext *s, TCGMemOp ot, target_ulong cur_eip,
+static void gen_check_io(DisasContext *s, MemOp ot, target_ulong cur_eip,
uint32_t svm_flags)
{
target_ulong next_eip;
@@ -644,7 +644,7 @@ static void gen_check_io(DisasContext *s, TCGMemOp ot, target_ulong cur_eip,
}
}
-static inline void gen_movs(DisasContext *s, TCGMemOp ot)
+static inline void gen_movs(DisasContext *s, MemOp ot)
{
gen_string_movl_A0_ESI(s);
gen_op_ld_v(s, ot, s->T0, s->A0);
@@ -840,7 +840,7 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg)
return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
default:
{
- TCGMemOp size = (s->cc_op - CC_OP_ADDB) & 3;
+ MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true);
return (CCPrepare) { .cond = TCG_COND_LT, .reg = t0, .mask = -1 };
}
@@ -885,7 +885,7 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
.mask = -1 };
default:
{
- TCGMemOp size = (s->cc_op - CC_OP_ADDB) & 3;
+ MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 };
}
@@ -897,7 +897,7 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg)
{
int inv, jcc_op, cond;
- TCGMemOp size;
+ MemOp size;
CCPrepare cc;
TCGv t0;
@@ -1075,7 +1075,7 @@ static TCGLabel *gen_jz_ecx_string(DisasContext *s, target_ulong next_eip)
return l2;
}
-static inline void gen_stos(DisasContext *s, TCGMemOp ot)
+static inline void gen_stos(DisasContext *s, MemOp ot)
{
gen_op_mov_v_reg(s, MO_32, s->T0, R_EAX);
gen_string_movl_A0_EDI(s);
@@ -1084,7 +1084,7 @@ static inline void gen_stos(DisasContext *s, TCGMemOp ot)
gen_op_add_reg_T0(s, s->aflag, R_EDI);
}
-static inline void gen_lods(DisasContext *s, TCGMemOp ot)
+static inline void gen_lods(DisasContext *s, MemOp ot)
{
gen_string_movl_A0_ESI(s);
gen_op_ld_v(s, ot, s->T0, s->A0);
@@ -1093,7 +1093,7 @@ static inline void gen_lods(DisasContext *s, TCGMemOp ot)
gen_op_add_reg_T0(s, s->aflag, R_ESI);
}
-static inline void gen_scas(DisasContext *s, TCGMemOp ot)
+static inline void gen_scas(DisasContext *s, MemOp ot)
{
gen_string_movl_A0_EDI(s);
gen_op_ld_v(s, ot, s->T1, s->A0);
@@ -1102,7 +1102,7 @@ static inline void gen_scas(DisasContext *s, TCGMemOp ot)
gen_op_add_reg_T0(s, s->aflag, R_EDI);
}
-static inline void gen_cmps(DisasContext *s, TCGMemOp ot)
+static inline void gen_cmps(DisasContext *s, MemOp ot)
{
gen_string_movl_A0_EDI(s);
gen_op_ld_v(s, ot, s->T1, s->A0);
@@ -1126,7 +1126,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
}
-static inline void gen_ins(DisasContext *s, TCGMemOp ot)
+static inline void gen_ins(DisasContext *s, MemOp ot)
{
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
@@ -1148,7 +1148,7 @@ static inline void gen_ins(DisasContext *s, TCGMemOp ot)
}
}
-static inline void gen_outs(DisasContext *s, TCGMemOp ot)
+static inline void gen_outs(DisasContext *s, MemOp ot)
{
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
@@ -1171,7 +1171,7 @@ static inline void gen_outs(DisasContext *s, TCGMemOp ot)
/* same method as Valgrind : we generate jumps to current or next
instruction */
#define GEN_REPZ(op) \
-static inline void gen_repz_ ## op(DisasContext *s, TCGMemOp ot, \
+static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, \
target_ulong cur_eip, target_ulong next_eip) \
{ \
TCGLabel *l2; \
@@ -1187,7 +1187,7 @@ static inline void gen_repz_ ## op(DisasContext *s, TCGMemOp ot, \
}
#define GEN_REPZ2(op) \
-static inline void gen_repz_ ## op(DisasContext *s, TCGMemOp ot, \
+static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, \
target_ulong cur_eip, \
target_ulong next_eip, \
int nz) \
@@ -1284,7 +1284,7 @@ static void gen_illegal_opcode(DisasContext *s)
}
/* if d == OR_TMP0, it means memory operand (address in A0) */
-static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d)
+static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
{
if (d != OR_TMP0) {
if (s1->prefix & PREFIX_LOCK) {
@@ -1395,7 +1395,7 @@ static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d)
}
/* if d == OR_TMP0, it means memory operand (address in A0) */
-static void gen_inc(DisasContext *s1, TCGMemOp ot, int d, int c)
+static void gen_inc(DisasContext *s1, MemOp ot, int d, int c)
{
if (s1->prefix & PREFIX_LOCK) {
if (d != OR_TMP0) {
@@ -1421,7 +1421,7 @@ static void gen_inc(DisasContext *s1, TCGMemOp ot, int d, int c)
set_cc_op(s1, (c > 0 ? CC_OP_INCB : CC_OP_DECB) + ot);
}
-static void gen_shift_flags(DisasContext *s, TCGMemOp ot, TCGv result,
+static void gen_shift_flags(DisasContext *s, MemOp ot, TCGv result,
TCGv shm1, TCGv count, bool is_right)
{
TCGv_i32 z32, s32, oldop;
@@ -1466,7 +1466,7 @@ static void gen_shift_flags(DisasContext *s, TCGMemOp ot, TCGv result,
set_cc_op(s, CC_OP_DYNAMIC);
}
-static void gen_shift_rm_T1(DisasContext *s, TCGMemOp ot, int op1,
+static void gen_shift_rm_T1(DisasContext *s, MemOp ot, int op1,
int is_right, int is_arith)
{
target_ulong mask = (ot == MO_64 ? 0x3f : 0x1f);
@@ -1502,7 +1502,7 @@ static void gen_shift_rm_T1(DisasContext *s, TCGMemOp ot, int op1,
gen_shift_flags(s, ot, s->T0, s->tmp0, s->T1, is_right);
}
-static void gen_shift_rm_im(DisasContext *s, TCGMemOp ot, int op1, int op2,
+static void gen_shift_rm_im(DisasContext *s, MemOp ot, int op1, int op2,
int is_right, int is_arith)
{
int mask = (ot == MO_64 ? 0x3f : 0x1f);
@@ -1542,7 +1542,7 @@ static void gen_shift_rm_im(DisasContext *s, TCGMemOp ot, int op1, int op2,
}
}
-static void gen_rot_rm_T1(DisasContext *s, TCGMemOp ot, int op1, int is_right)
+static void gen_rot_rm_T1(DisasContext *s, MemOp ot, int op1, int is_right)
{
target_ulong mask = (ot == MO_64 ? 0x3f : 0x1f);
TCGv_i32 t0, t1;
@@ -1627,7 +1627,7 @@ static void gen_rot_rm_T1(DisasContext *s, TCGMemOp ot, int op1, int is_right)
set_cc_op(s, CC_OP_DYNAMIC);
}
-static void gen_rot_rm_im(DisasContext *s, TCGMemOp ot, int op1, int op2,
+static void gen_rot_rm_im(DisasContext *s, MemOp ot, int op1, int op2,
int is_right)
{
int mask = (ot == MO_64 ? 0x3f : 0x1f);
@@ -1705,7 +1705,7 @@ static void gen_rot_rm_im(DisasContext *s, TCGMemOp ot, int op1, int op2,
}
/* XXX: add faster immediate = 1 case */
-static void gen_rotc_rm_T1(DisasContext *s, TCGMemOp ot, int op1,
+static void gen_rotc_rm_T1(DisasContext *s, MemOp ot, int op1,
int is_right)
{
gen_compute_eflags(s);
@@ -1761,7 +1761,7 @@ static void gen_rotc_rm_T1(DisasContext *s, TCGMemOp ot, int op1,
}
/* XXX: add faster immediate case */
-static void gen_shiftd_rm_T1(DisasContext *s, TCGMemOp ot, int op1,
+static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot, int op1,
bool is_right, TCGv count_in)
{
target_ulong mask = (ot == MO_64 ? 63 : 31);
@@ -1842,7 +1842,7 @@ static void gen_shiftd_rm_T1(DisasContext *s, TCGMemOp ot, int op1,
tcg_temp_free(count);
}
-static void gen_shift(DisasContext *s1, int op, TCGMemOp ot, int d, int s)
+static void gen_shift(DisasContext *s1, int op, MemOp ot, int d, int s)
{
if (s != OR_TMP1)
gen_op_mov_v_reg(s1, ot, s1->T1, s);
@@ -1872,7 +1872,7 @@ static void gen_shift(DisasContext *s1, int op, TCGMemOp ot, int d, int s)
}
}
-static void gen_shifti(DisasContext *s1, int op, TCGMemOp ot, int d, int c)
+static void gen_shifti(DisasContext *s1, int op, MemOp ot, int d, int c)
{
switch(op) {
case OP_ROL:
@@ -2149,7 +2149,7 @@ static void gen_add_A0_ds_seg(DisasContext *s)
/* generate modrm memory load or store of 'reg'. TMP0 is used if reg ==
OR_TMP0 */
static void gen_ldst_modrm(CPUX86State *env, DisasContext *s, int modrm,
- TCGMemOp ot, int reg, int is_store)
+ MemOp ot, int reg, int is_store)
{
int mod, rm;
@@ -2179,7 +2179,7 @@ static void gen_ldst_modrm(CPUX86State *env, DisasContext *s, int modrm,
}
}
-static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, TCGMemOp ot)
+static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, MemOp ot)
{
uint32_t ret;
@@ -2202,7 +2202,7 @@ static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, TCGMemOp ot)
return ret;
}
-static inline int insn_const_size(TCGMemOp ot)
+static inline int insn_const_size(MemOp ot)
{
if (ot <= MO_32) {
return 1 << ot;
@@ -2266,7 +2266,7 @@ static inline void gen_jcc(DisasContext *s, int b,
}
}
-static void gen_cmovcc1(CPUX86State *env, DisasContext *s, TCGMemOp ot, int b,
+static void gen_cmovcc1(CPUX86State *env, DisasContext *s, MemOp ot, int b,
int modrm, int reg)
{
CCPrepare cc;
@@ -2363,8 +2363,8 @@ static inline void gen_stack_update(DisasContext *s, int addend)
/* Generate a push. It depends on ss32, addseg and dflag. */
static void gen_push_v(DisasContext *s, TCGv val)
{
- TCGMemOp d_ot = mo_pushpop(s, s->dflag);
- TCGMemOp a_ot = mo_stacksize(s);
+ MemOp d_ot = mo_pushpop(s, s->dflag);
+ MemOp a_ot = mo_stacksize(s);
int size = 1 << d_ot;
TCGv new_esp = s->A0;
@@ -2383,9 +2383,9 @@ static void gen_push_v(DisasContext *s, TCGv val)
}
/* two step pop is necessary for precise exceptions */
-static TCGMemOp gen_pop_T0(DisasContext *s)
+static MemOp gen_pop_T0(DisasContext *s)
{
- TCGMemOp d_ot = mo_pushpop(s, s->dflag);
+ MemOp d_ot = mo_pushpop(s, s->dflag);
gen_lea_v_seg(s, mo_stacksize(s), cpu_regs[R_ESP], R_SS, -1);
gen_op_ld_v(s, d_ot, s->T0, s->A0);
@@ -2393,7 +2393,7 @@ static TCGMemOp gen_pop_T0(DisasContext *s)
return d_ot;
}
-static inline void gen_pop_update(DisasContext *s, TCGMemOp ot)
+static inline void gen_pop_update(DisasContext *s, MemOp ot)
{
gen_stack_update(s, 1 << ot);
}
@@ -2405,8 +2405,8 @@ static inline void gen_stack_A0(DisasContext *s)
static void gen_pusha(DisasContext *s)
{
- TCGMemOp s_ot = s->ss32 ? MO_32 : MO_16;
- TCGMemOp d_ot = s->dflag;
+ MemOp s_ot = s->ss32 ? MO_32 : MO_16;
+ MemOp d_ot = s->dflag;
int size = 1 << d_ot;
int i;
@@ -2421,8 +2421,8 @@ static void gen_pusha(DisasContext *s)
static void gen_popa(DisasContext *s)
{
- TCGMemOp s_ot = s->ss32 ? MO_32 : MO_16;
- TCGMemOp d_ot = s->dflag;
+ MemOp s_ot = s->ss32 ? MO_32 : MO_16;
+ MemOp d_ot = s->dflag;
int size = 1 << d_ot;
int i;
@@ -2442,8 +2442,8 @@ static void gen_popa(DisasContext *s)
static void gen_enter(DisasContext *s, int esp_addend, int level)
{
- TCGMemOp d_ot = mo_pushpop(s, s->dflag);
- TCGMemOp a_ot = CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16;
+ MemOp d_ot = mo_pushpop(s, s->dflag);
+ MemOp a_ot = CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16;
int size = 1 << d_ot;
/* Push BP; compute FrameTemp into T1. */
@@ -2482,8 +2482,8 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
static void gen_leave(DisasContext *s)
{
- TCGMemOp d_ot = mo_pushpop(s, s->dflag);
- TCGMemOp a_ot = mo_stacksize(s);
+ MemOp d_ot = mo_pushpop(s, s->dflag);
+ MemOp a_ot = mo_stacksize(s);
gen_lea_v_seg(s, a_ot, cpu_regs[R_EBP], R_SS, -1);
gen_op_ld_v(s, d_ot, s->T0, s->A0);
@@ -3045,7 +3045,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
SSEFunc_0_eppi sse_fn_eppi;
SSEFunc_0_ppi sse_fn_ppi;
SSEFunc_0_eppt sse_fn_eppt;
- TCGMemOp ot;
+ MemOp ot;
b &= 0xff;
if (s->prefix & PREFIX_DATA)
@@ -4488,7 +4488,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
CPUX86State *env = cpu->env_ptr;
int b, prefixes;
int shift;
- TCGMemOp ot, aflag, dflag;
+ MemOp ot, aflag, dflag;
int modrm, reg, rm, mod, op, opreg, val;
target_ulong next_eip, tval;
int rex_w, rex_r;
@@ -5566,8 +5566,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x1be: /* movsbS Gv, Eb */
case 0x1bf: /* movswS Gv, Eb */
{
- TCGMemOp d_ot;
- TCGMemOp s_ot;
+ MemOp d_ot;
+ MemOp s_ot;
/* d_ot is the size of destination */
d_ot = dflag;
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 60bcfb7bd0..24c1dd3408 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -2414,7 +2414,7 @@ DISAS_INSN(cas)
uint16_t ext;
TCGv load;
TCGv cmp;
- TCGMemOp opc;
+ MemOp opc;
switch ((insn >> 9) & 3) {
case 1:
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 95ff663292..761f535357 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -919,7 +919,7 @@ static void dec_load(DisasContext *dc)
unsigned int size;
bool rev = false, ex = false, ea = false;
int mem_index = cpu_mmu_index(&dc->cpu->env, false);
- TCGMemOp mop;
+ MemOp mop;
mop = dc->opcode & 3;
size = 1 << mop;
@@ -1035,7 +1035,7 @@ static void dec_store(DisasContext *dc)
unsigned int size;
bool rev = false, ex = false, ea = false;
int mem_index = cpu_mmu_index(&dc->cpu->env, false);
- TCGMemOp mop;
+ MemOp mop;
mop = dc->opcode & 3;
size = 1 << mop;
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 1fd4a180e1..ca00f41daf 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -192,14 +192,14 @@ typedef struct mips_def_t mips_def_t;
* Register 16 Register 17 Register 18 Register 19
* ----------- ----------- ----------- -----------
*
- * 0 Config LLAddr WatchLo WatchHi
- * 1 Config1 MAAR WatchLo WatchHi
- * 2 Config2 MAARI WatchLo WatchHi
- * 3 Config3 WatchLo WatchHi
- * 4 Config4 WatchLo WatchHi
- * 5 Config5 WatchLo WatchHi
- * 6 WatchLo WatchHi
- * 7 WatchLo WatchHi
+ * 0 Config LLAddr WatchLo0 WatchHi
+ * 1 Config1 MAAR WatchLo1 WatchHi
+ * 2 Config2 MAARI WatchLo2 WatchHi
+ * 3 Config3 WatchLo3 WatchHi
+ * 4 Config4 WatchLo4 WatchHi
+ * 5 Config5 WatchLo5 WatchHi
+ * 6 WatchLo6 WatchHi
+ * 7 WatchLo7 WatchHi
*
*
* Register 20 Register 21 Register 22 Register 23
@@ -233,12 +233,12 @@ typedef struct mips_def_t mips_def_t;
*
* 0 DataLo DataHi ErrorEPC DESAVE
* 1 TagLo TagHi
- * 2 DataLo DataHi KScratch<n>
- * 3 TagLo TagHi KScratch<n>
- * 4 DataLo DataHi KScratch<n>
- * 5 TagLo TagHi KScratch<n>
- * 6 DataLo DataHi KScratch<n>
- * 7 TagLo TagHi KScratch<n>
+ * 2 DataLo1 DataHi1 KScratch<n>
+ * 3 TagLo1 TagHi1 KScratch<n>
+ * 4 DataLo2 DataHi2 KScratch<n>
+ * 5 TagLo2 TagHi2 KScratch<n>
+ * 6 DataLo3 DataHi3 KScratch<n>
+ * 7 TagLo3 TagHi3 KScratch<n>
*
*/
#define CP0_REGISTER_00 0
@@ -277,29 +277,63 @@ typedef struct mips_def_t mips_def_t;
/* CP0 Register 00 */
#define CP0_REG00__INDEX 0
+#define CP0_REG00__MVPCONTROL 1
+#define CP0_REG00__MVPCONF0 2
+#define CP0_REG00__MVPCONF1 3
#define CP0_REG00__VPCONTROL 4
/* CP0 Register 01 */
+#define CP0_REG01__RANDOM 0
+#define CP0_REG01__VPECONTROL 1
+#define CP0_REG01__VPECONF0 2
+#define CP0_REG01__VPECONF1 3
+#define CP0_REG01__YQMASK 4
+#define CP0_REG01__VPESCHEDULE 5
+#define CP0_REG01__VPESCHEFBACK 6
+#define CP0_REG01__VPEOPT 7
/* CP0 Register 02 */
#define CP0_REG02__ENTRYLO0 0
+#define CP0_REG02__TCSTATUS 1
+#define CP0_REG02__TCBIND 2
+#define CP0_REG02__TCRESTART 3
+#define CP0_REG02__TCHALT 4
+#define CP0_REG02__TCCONTEXT 5
+#define CP0_REG02__TCSCHEDULE 6
+#define CP0_REG02__TCSCHEFBACK 7
/* CP0 Register 03 */
#define CP0_REG03__ENTRYLO1 0
#define CP0_REG03__GLOBALNUM 1
+#define CP0_REG03__TCOPT 7
/* CP0 Register 04 */
#define CP0_REG04__CONTEXT 0
+#define CP0_REG04__CONTEXTCONFIG 1
#define CP0_REG04__USERLOCAL 2
+#define CP0_REG04__XCONTEXTCONFIG 3
#define CP0_REG04__DBGCONTEXTID 4
#define CP0_REG00__MMID 5
/* CP0 Register 05 */
#define CP0_REG05__PAGEMASK 0
#define CP0_REG05__PAGEGRAIN 1
+#define CP0_REG05__SEGCTL0 2
+#define CP0_REG05__SEGCTL1 3
+#define CP0_REG05__SEGCTL2 4
+#define CP0_REG05__PWBASE 5
+#define CP0_REG05__PWFIELD 6
+#define CP0_REG05__PWSIZE 7
/* CP0 Register 06 */
#define CP0_REG06__WIRED 0
+#define CP0_REG06__SRSCONF0 1
+#define CP0_REG06__SRSCONF1 2
+#define CP0_REG06__SRSCONF2 3
+#define CP0_REG06__SRSCONF3 4
+#define CP0_REG06__SRSCONF4 5
+#define CP0_REG06__PWCTL 6
/* CP0 Register 07 */
#define CP0_REG07__HWRENA 0
/* CP0 Register 08 */
#define CP0_REG08__BADVADDR 0
#define CP0_REG08__BADINSTR 1
#define CP0_REG08__BADINSTRP 2
+#define CP0_REG08__BADINSTRX 3
/* CP0 Register 09 */
#define CP0_REG09__COUNT 0
#define CP0_REG09__SAARI 6
@@ -308,6 +342,7 @@ typedef struct mips_def_t mips_def_t;
#define CP0_REG10__ENTRYHI 0
#define CP0_REG10__GUESTCTL1 4
#define CP0_REG10__GUESTCTL2 5
+#define CP0_REG10__GUESTCTL3 6
/* CP0 Register 11 */
#define CP0_REG11__COMPARE 0
#define CP0_REG11__GUESTCTL0EXT 4
@@ -315,17 +350,24 @@ typedef struct mips_def_t mips_def_t;
#define CP0_REG12__STATUS 0
#define CP0_REG12__INTCTL 1
#define CP0_REG12__SRSCTL 2
+#define CP0_REG12__SRSMAP 3
+#define CP0_REG12__VIEW_IPL 4
+#define CP0_REG12__SRSMAP2 5
#define CP0_REG12__GUESTCTL0 6
#define CP0_REG12__GTOFFSET 7
/* CP0 Register 13 */
#define CP0_REG13__CAUSE 0
+#define CP0_REG13__VIEW_RIPL 4
+#define CP0_REG13__NESTEDEXC 5
/* CP0 Register 14 */
#define CP0_REG14__EPC 0
+#define CP0_REG14__NESTEDEPC 2
/* CP0 Register 15 */
#define CP0_REG15__PRID 0
#define CP0_REG15__EBASE 1
#define CP0_REG15__CDMMBASE 2
#define CP0_REG15__CMGCRBASE 3
+#define CP0_REG15__BEVVA 4
/* CP0 Register 16 */
#define CP0_REG16__CONFIG 0
#define CP0_REG16__CONFIG1 1
@@ -333,7 +375,8 @@ typedef struct mips_def_t mips_def_t;
#define CP0_REG16__CONFIG3 3
#define CP0_REG16__CONFIG4 4
#define CP0_REG16__CONFIG5 5
-#define CP0_REG00__CONFIG7 7
+#define CP0_REG16__CONFIG6 6
+#define CP0_REG16__CONFIG7 7
/* CP0 Register 17 */
#define CP0_REG17__LLADDR 0
#define CP0_REG17__MAAR 1
@@ -343,17 +386,31 @@ typedef struct mips_def_t mips_def_t;
#define CP0_REG18__WATCHLO1 1
#define CP0_REG18__WATCHLO2 2
#define CP0_REG18__WATCHLO3 3
+#define CP0_REG18__WATCHLO4 4
+#define CP0_REG18__WATCHLO5 5
+#define CP0_REG18__WATCHLO6 6
+#define CP0_REG18__WATCHLO7 7
/* CP0 Register 19 */
#define CP0_REG19__WATCHHI0 0
#define CP0_REG19__WATCHHI1 1
#define CP0_REG19__WATCHHI2 2
#define CP0_REG19__WATCHHI3 3
+#define CP0_REG19__WATCHHI4 4
+#define CP0_REG19__WATCHHI5 5
+#define CP0_REG19__WATCHHI6 6
+#define CP0_REG19__WATCHHI7 7
/* CP0 Register 20 */
#define CP0_REG20__XCONTEXT 0
/* CP0 Register 21 */
/* CP0 Register 22 */
/* CP0 Register 23 */
#define CP0_REG23__DEBUG 0
+#define CP0_REG23__TRACECONTROL 1
+#define CP0_REG23__TRACECONTROL2 2
+#define CP0_REG23__USERTRACEDATA1 3
+#define CP0_REG23__TRACEIBPC 4
+#define CP0_REG23__TRACEDBPC 5
+#define CP0_REG23__DEBUG2 6
/* CP0 Register 24 */
#define CP0_REG24__DEPC 0
/* CP0 Register 25 */
@@ -366,17 +423,27 @@ typedef struct mips_def_t mips_def_t;
#define CP0_REG25__PERFCTL3 6
#define CP0_REG25__PERFCNT3 7
/* CP0 Register 26 */
-#define CP0_REG00__ERRCTL 0
+#define CP0_REG26__ERRCTL 0
/* CP0 Register 27 */
#define CP0_REG27__CACHERR 0
/* CP0 Register 28 */
-#define CP0_REG28__ITAGLO 0
-#define CP0_REG28__IDATALO 1
-#define CP0_REG28__DTAGLO 2
-#define CP0_REG28__DDATALO 3
+#define CP0_REG28__TAGLO 0
+#define CP0_REG28__DATALO 1
+#define CP0_REG28__TAGLO1 2
+#define CP0_REG28__DATALO1 3
+#define CP0_REG28__TAGLO2 4
+#define CP0_REG28__DATALO2 5
+#define CP0_REG28__TAGLO3 6
+#define CP0_REG28__DATALO3 7
/* CP0 Register 29 */
-#define CP0_REG29__IDATAHI 1
-#define CP0_REG29__DDATAHI 3
+#define CP0_REG29__TAGHI 0
+#define CP0_REG29__DATAHI 1
+#define CP0_REG29__TAGHI1 2
+#define CP0_REG29__DATAHI1 3
+#define CP0_REG29__TAGHI2 4
+#define CP0_REG29__DATAHI2 5
+#define CP0_REG29__TAGHI3 6
+#define CP0_REG29__DATAHI3 7
/* CP0 Register 30 */
#define CP0_REG30__ERROREPC 0
/* CP0 Register 31 */
@@ -546,7 +613,6 @@ struct CPUMIPSState {
* CP0 Register 4
*/
target_ulong CP0_Context;
- target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM];
int32_t CP0_MemoryMapID;
/*
* CP0 Register 5
@@ -957,6 +1023,7 @@ struct CPUMIPSState {
* CP0 Register 31
*/
int32_t CP0_DESAVE;
+ target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM];
/* We waste some space so we can handle shadow registers like TCs. */
TCState tcs[MIPS_SHADOW_SET_MAX];
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index f88a3ab904..01b9e78bf3 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -24,6 +24,7 @@
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
+#include "exec/memop.h"
#include "sysemu/kvm.h"
#include "fpu/softfloat.h"
@@ -4536,16 +4537,14 @@ static inline void ensure_writable_pages(CPUMIPSState *env,
int mmu_idx,
uintptr_t retaddr)
{
-#if !defined(CONFIG_USER_ONLY)
- target_ulong page_addr;
+ /* FIXME: Probe the actual accesses (pass and use a size) */
if (unlikely(MSA_PAGESPAN(addr))) {
/* first page */
probe_write(env, addr, 0, mmu_idx, retaddr);
/* second page */
- page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
- probe_write(env, page_addr, 0, mmu_idx, retaddr);
+ addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+ probe_write(env, addr, 0, mmu_idx, retaddr);
}
-#endif
}
void helper_msa_st_b(CPUMIPSState *env, uint32_t wd,
@@ -4692,15 +4691,15 @@ void helper_msa_st_w(CPUMIPSState *env, uint32_t wd,
ensure_writable_pages(env, addr, mmu_idx, GETPC());
#if !defined(CONFIG_USER_ONLY)
#if !defined(HOST_WORDS_BIGENDIAN)
- helper_ret_stl_mmu(env, addr + (0 << DF_WORD), oi, GETPC(), pwd->w[0]);
- helper_ret_stl_mmu(env, addr + (1 << DF_WORD), oi, GETPC(), pwd->w[1]);
- helper_ret_stl_mmu(env, addr + (2 << DF_WORD), oi, GETPC(), pwd->w[2]);
- helper_ret_stl_mmu(env, addr + (3 << DF_WORD), oi, GETPC(), pwd->w[3]);
+ helper_ret_stl_mmu(env, addr + (0 << DF_WORD), pwd->w[0], oi, GETPC());
+ helper_ret_stl_mmu(env, addr + (1 << DF_WORD), pwd->w[1], oi, GETPC());
+ helper_ret_stl_mmu(env, addr + (2 << DF_WORD), pwd->w[2], oi, GETPC());
+ helper_ret_stl_mmu(env, addr + (3 << DF_WORD), pwd->w[3], oi, GETPC());
#else
- helper_ret_stl_mmu(env, addr + (1 << DF_WORD), oi, GETPC(), pwd->w[0]);
- helper_ret_stl_mmu(env, addr + (0 << DF_WORD), oi, GETPC(), pwd->w[1]);
- helper_ret_stl_mmu(env, addr + (3 << DF_WORD), oi, GETPC(), pwd->w[2]);
- helper_ret_stl_mmu(env, addr + (2 << DF_WORD), oi, GETPC(), pwd->w[3]);
+ helper_ret_stl_mmu(env, addr + (1 << DF_WORD), pwd->w[0], oi, GETPC());
+ helper_ret_stl_mmu(env, addr + (0 << DF_WORD), pwd->w[1], oi, GETPC());
+ helper_ret_stl_mmu(env, addr + (3 << DF_WORD), pwd->w[2], oi, GETPC());
+ helper_ret_stl_mmu(env, addr + (2 << DF_WORD), pwd->w[3], oi, GETPC());
#endif
#else
#if !defined(HOST_WORDS_BIGENDIAN)
@@ -4741,11 +4740,11 @@ void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
if (op == 9) {
/* Index Store Tag */
memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
- 8, MEMTXATTRS_UNSPECIFIED);
+ MO_64, MEMTXATTRS_UNSPECIFIED);
} else if (op == 5) {
/* Index Load Tag */
memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
- 8, MEMTXATTRS_UNSPECIFIED);
+ MO_64, MEMTXATTRS_UNSPECIFIED);
}
#endif
}
diff --git a/target/mips/translate.c b/target/mips/translate.c
index 8ebde6ffee..f2119955cf 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -2526,7 +2526,7 @@ typedef struct DisasContext {
int32_t CP0_Config5;
/* Routine used to access memory */
int mem_idx;
- TCGMemOp default_tcg_memop_mask;
+ MemOp default_tcg_memop_mask;
uint32_t hflags, saved_hflags;
target_ulong btarget;
bool ulri;
@@ -3706,7 +3706,7 @@ static void gen_st(DisasContext *ctx, uint32_t opc, int rt,
/* Store conditional */
static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset,
- TCGMemOp tcg_mo, bool eva)
+ MemOp tcg_mo, bool eva)
{
TCGv addr, t0, val;
TCGLabel *l1 = gen_new_label();
@@ -4549,7 +4549,7 @@ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg)
}
static inline void gen_r6_ld(target_long addr, int reg, int memidx,
- TCGMemOp memop)
+ MemOp memop)
{
TCGv t0 = tcg_const_tl(addr);
tcg_gen_qemu_ld_tl(t0, t0, memidx, memop);
@@ -6647,7 +6647,7 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_03:
switch (sel) {
- case 0:
+ case CP0_REG03__ENTRYLO1:
CP0_CHECK(ctx->hflags & MIPS_HFLAG_ELPA);
gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1));
register_name = "EntryLo1";
@@ -6658,7 +6658,7 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_09:
switch (sel) {
- case 7:
+ case CP0_REG09__SAAR:
CP0_CHECK(ctx->saar);
gen_helper_mfhc0_saar(arg, cpu_env);
register_name = "SAAR";
@@ -6669,12 +6669,12 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_17:
switch (sel) {
- case 0:
+ case CP0_REG17__LLADDR:
gen_mfhc0_load64(arg, offsetof(CPUMIPSState, CP0_LLAddr),
ctx->CP0_LLAddr_shift);
register_name = "LLAddr";
break;
- case 1:
+ case CP0_REG17__MAAR:
CP0_CHECK(ctx->mrp);
gen_helper_mfhc0_maar(arg, cpu_env);
register_name = "MAAR";
@@ -6728,7 +6728,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_03:
switch (sel) {
- case 0:
+ case CP0_REG03__ENTRYLO1:
CP0_CHECK(ctx->hflags & MIPS_HFLAG_ELPA);
tcg_gen_andi_tl(arg, arg, mask);
gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1));
@@ -6740,7 +6740,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_09:
switch (sel) {
- case 7:
+ case CP0_REG09__SAAR:
CP0_CHECK(ctx->saar);
gen_helper_mthc0_saar(cpu_env, arg);
register_name = "SAAR";
@@ -6751,7 +6751,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_17:
switch (sel) {
- case 0:
+ case CP0_REG17__LLADDR:
/*
* LLAddr is read-only (the only exception is bit 0 if LLB is
* supported); the CP0_LLAddr_rw_bitmask does not seem to be
@@ -6760,7 +6760,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel)
*/
register_name = "LLAddr";
break;
- case 1:
+ case CP0_REG17__MAAR:
CP0_CHECK(ctx->mrp);
gen_helper_mthc0_maar(cpu_env, arg);
register_name = "MAAR";
@@ -6813,26 +6813,26 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
switch (reg) {
case CP0_REGISTER_00:
switch (sel) {
- case 0:
+ case CP0_REG00__INDEX:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Index));
register_name = "Index";
break;
- case 1:
+ case CP0_REG00__MVPCONTROL:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpcontrol(arg, cpu_env);
register_name = "MVPControl";
break;
- case 2:
+ case CP0_REG00__MVPCONF0:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpconf0(arg, cpu_env);
register_name = "MVPConf0";
break;
- case 3:
+ case CP0_REG00__MVPCONF1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpconf1(arg, cpu_env);
register_name = "MVPConf1";
break;
- case 4:
+ case CP0_REG00__VPCONTROL:
CP0_CHECK(ctx->vp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPControl));
register_name = "VPControl";
@@ -6843,42 +6843,42 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_01:
switch (sel) {
- case 0:
+ case CP0_REG01__RANDOM:
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
gen_helper_mfc0_random(arg, cpu_env);
register_name = "Random";
break;
- case 1:
+ case CP0_REG01__VPECONTROL:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl));
register_name = "VPEControl";
break;
- case 2:
+ case CP0_REG01__VPECONF0:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0));
register_name = "VPEConf0";
break;
- case 3:
+ case CP0_REG01__VPECONF1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1));
register_name = "VPEConf1";
break;
- case 4:
+ case CP0_REG01__YQMASK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_YQMask));
register_name = "YQMask";
break;
- case 5:
+ case CP0_REG01__VPESCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
- case 6:
+ case CP0_REG01__VPESCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
- case 7:
+ case CP0_REG01__VPEOPT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt));
register_name = "VPEOpt";
@@ -6889,7 +6889,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_02:
switch (sel) {
- case 0:
+ case CP0_REG02__ENTRYLO0:
{
TCGv_i64 tmp = tcg_temp_new_i64();
tcg_gen_ld_i64(tmp, cpu_env,
@@ -6906,37 +6906,37 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
register_name = "EntryLo0";
break;
- case 1:
+ case CP0_REG02__TCSTATUS:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcstatus(arg, cpu_env);
register_name = "TCStatus";
break;
- case 2:
+ case CP0_REG02__TCBIND:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcbind(arg, cpu_env);
register_name = "TCBind";
break;
- case 3:
+ case CP0_REG02__TCRESTART:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcrestart(arg, cpu_env);
register_name = "TCRestart";
break;
- case 4:
+ case CP0_REG02__TCHALT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tchalt(arg, cpu_env);
register_name = "TCHalt";
break;
- case 5:
+ case CP0_REG02__TCCONTEXT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tccontext(arg, cpu_env);
register_name = "TCContext";
break;
- case 6:
+ case CP0_REG02__TCSCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcschedule(arg, cpu_env);
register_name = "TCSchedule";
break;
- case 7:
+ case CP0_REG02__TCSCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcschefback(arg, cpu_env);
register_name = "TCScheFBack";
@@ -6947,7 +6947,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_03:
switch (sel) {
- case 0:
+ case CP0_REG03__ENTRYLO1:
{
TCGv_i64 tmp = tcg_temp_new_i64();
tcg_gen_ld_i64(tmp, cpu_env,
@@ -6964,7 +6964,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
register_name = "EntryLo1";
break;
- case 1:
+ case CP0_REG03__GLOBALNUM:
CP0_CHECK(ctx->vp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_GlobalNumber));
register_name = "GlobalNumber";
@@ -6975,16 +6975,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_04:
switch (sel) {
- case 0:
+ case CP0_REG04__CONTEXT:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context));
tcg_gen_ext32s_tl(arg, arg);
register_name = "Context";
break;
- case 1:
- /* gen_helper_mfc0_contextconfig(arg); - SmartMIPS ASE */
+ case CP0_REG04__CONTEXTCONFIG:
+ /* SmartMIPS ASE */
+ /* gen_helper_mfc0_contextconfig(arg); */
register_name = "ContextConfig";
goto cp0_unimplemented;
- case 2:
+ case CP0_REG04__USERLOCAL:
CP0_CHECK(ctx->ulri);
tcg_gen_ld_tl(arg, cpu_env,
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
@@ -6997,44 +6998,44 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_05:
switch (sel) {
- case 0:
+ case CP0_REG05__PAGEMASK:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageMask));
register_name = "PageMask";
break;
- case 1:
+ case CP0_REG05__PAGEGRAIN:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain));
register_name = "PageGrain";
break;
- case 2:
+ case CP0_REG05__SEGCTL0:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0));
tcg_gen_ext32s_tl(arg, arg);
register_name = "SegCtl0";
break;
- case 3:
+ case CP0_REG05__SEGCTL1:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1));
tcg_gen_ext32s_tl(arg, arg);
register_name = "SegCtl1";
break;
- case 4:
+ case CP0_REG05__SEGCTL2:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2));
tcg_gen_ext32s_tl(arg, arg);
register_name = "SegCtl2";
break;
- case 5:
+ case CP0_REG05__PWBASE:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWBase));
register_name = "PWBase";
break;
- case 6:
+ case CP0_REG05__PWFIELD:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWField));
register_name = "PWField";
break;
- case 7:
+ case CP0_REG05__PWSIZE:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWSize));
register_name = "PWSize";
@@ -7045,36 +7046,36 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_06:
switch (sel) {
- case 0:
+ case CP0_REG06__WIRED:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Wired));
register_name = "Wired";
break;
- case 1:
+ case CP0_REG06__SRSCONF0:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0));
register_name = "SRSConf0";
break;
- case 2:
+ case CP0_REG06__SRSCONF1:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1));
register_name = "SRSConf1";
break;
- case 3:
+ case CP0_REG06__SRSCONF2:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2));
register_name = "SRSConf2";
break;
- case 4:
+ case CP0_REG06__SRSCONF3:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3));
register_name = "SRSConf3";
break;
- case 5:
+ case CP0_REG06__SRSCONF4:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4));
register_name = "SRSConf4";
break;
- case 6:
+ case CP0_REG06__PWCTL:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWCtl));
register_name = "PWCtl";
@@ -7085,7 +7086,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_07:
switch (sel) {
- case 0:
+ case CP0_REG07__HWRENA:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna));
register_name = "HWREna";
@@ -7096,22 +7097,22 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_08:
switch (sel) {
- case 0:
+ case CP0_REG08__BADVADDR:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr));
tcg_gen_ext32s_tl(arg, arg);
register_name = "BadVAddr";
break;
- case 1:
+ case CP0_REG08__BADINSTR:
CP0_CHECK(ctx->bi);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr));
register_name = "BadInstr";
break;
- case 2:
+ case CP0_REG08__BADINSTRP:
CP0_CHECK(ctx->bp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP));
register_name = "BadInstrP";
break;
- case 3:
+ case CP0_REG08__BADINSTRX:
CP0_CHECK(ctx->bi);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrX));
tcg_gen_andi_tl(arg, arg, ~0xffff);
@@ -7123,7 +7124,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_09:
switch (sel) {
- case 0:
+ case CP0_REG09__COUNT:
/* Mark as an IO operation because we read the time. */
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
@@ -7138,12 +7139,12 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Count";
break;
- case 6:
+ case CP0_REG09__SAARI:
CP0_CHECK(ctx->saar);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SAARI));
register_name = "SAARI";
break;
- case 7:
+ case CP0_REG09__SAAR:
CP0_CHECK(ctx->saar);
gen_helper_mfc0_saar(arg, cpu_env);
register_name = "SAAR";
@@ -7154,7 +7155,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_10:
switch (sel) {
- case 0:
+ case CP0_REG10__ENTRYHI:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi));
tcg_gen_ext32s_tl(arg, arg);
register_name = "EntryHi";
@@ -7165,7 +7166,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_11:
switch (sel) {
- case 0:
+ case CP0_REG11__COMPARE:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare));
register_name = "Compare";
break;
@@ -7176,21 +7177,21 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_12:
switch (sel) {
- case 0:
+ case CP0_REG12__STATUS:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Status));
register_name = "Status";
break;
- case 1:
+ case CP0_REG12__INTCTL:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl));
register_name = "IntCtl";
break;
- case 2:
+ case CP0_REG12__SRSCTL:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl));
register_name = "SRSCtl";
break;
- case 3:
+ case CP0_REG12__SRSMAP:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
register_name = "SRSMap";
@@ -7201,7 +7202,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_13:
switch (sel) {
- case 0:
+ case CP0_REG13__CAUSE:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Cause));
register_name = "Cause";
break;
@@ -7211,7 +7212,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_14:
switch (sel) {
- case 0:
+ case CP0_REG14__EPC:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
tcg_gen_ext32s_tl(arg, arg);
register_name = "EPC";
@@ -7222,17 +7223,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_15:
switch (sel) {
- case 0:
+ case CP0_REG15__PRID:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PRid));
register_name = "PRid";
break;
- case 1:
+ case CP0_REG15__EBASE:
check_insn(ctx, ISA_MIPS32R2);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase));
tcg_gen_ext32s_tl(arg, arg);
register_name = "EBase";
break;
- case 3:
+ case CP0_REG15__CMGCRBASE:
check_insn(ctx, ISA_MIPS32R2);
CP0_CHECK(ctx->cmgcr);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_CMGCRBase));
@@ -7245,36 +7246,36 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_16:
switch (sel) {
- case 0:
+ case CP0_REG16__CONFIG:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config0));
register_name = "Config";
break;
- case 1:
+ case CP0_REG16__CONFIG1:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config1));
register_name = "Config1";
break;
- case 2:
+ case CP0_REG16__CONFIG2:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config2));
register_name = "Config2";
break;
- case 3:
+ case CP0_REG16__CONFIG3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3));
register_name = "Config3";
break;
- case 4:
+ case CP0_REG16__CONFIG4:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config4));
register_name = "Config4";
break;
- case 5:
+ case CP0_REG16__CONFIG5:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5));
register_name = "Config5";
break;
/* 6,7 are implementation dependent */
- case 6:
+ case CP0_REG16__CONFIG6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6));
register_name = "Config6";
break;
- case 7:
+ case CP0_REG16__CONFIG7:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config7));
register_name = "Config7";
break;
@@ -7284,16 +7285,16 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_17:
switch (sel) {
- case 0:
+ case CP0_REG17__LLADDR:
gen_helper_mfc0_lladdr(arg, cpu_env);
register_name = "LLAddr";
break;
- case 1:
+ case CP0_REG17__MAAR:
CP0_CHECK(ctx->mrp);
gen_helper_mfc0_maar(arg, cpu_env);
register_name = "MAAR";
break;
- case 2:
+ case CP0_REG17__MAARI:
CP0_CHECK(ctx->mrp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_MAARI));
register_name = "MAARI";
@@ -7304,14 +7305,14 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_18:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG18__WATCHLO0:
+ case CP0_REG18__WATCHLO1:
+ case CP0_REG18__WATCHLO2:
+ case CP0_REG18__WATCHLO3:
+ case CP0_REG18__WATCHLO4:
+ case CP0_REG18__WATCHLO5:
+ case CP0_REG18__WATCHLO6:
+ case CP0_REG18__WATCHLO7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_1e0i(mfc0_watchlo, arg, sel);
register_name = "WatchLo";
@@ -7322,14 +7323,14 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_19:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG19__WATCHHI0:
+ case CP0_REG19__WATCHHI1:
+ case CP0_REG19__WATCHHI2:
+ case CP0_REG19__WATCHHI3:
+ case CP0_REG19__WATCHHI4:
+ case CP0_REG19__WATCHHI5:
+ case CP0_REG19__WATCHHI6:
+ case CP0_REG19__WATCHHI7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_1e0i(mfc0_watchhi, arg, sel);
register_name = "WatchHi";
@@ -7340,7 +7341,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_20:
switch (sel) {
- case 0:
+ case CP0_REG20__XCONTEXT:
#if defined(TARGET_MIPS64)
check_insn(ctx, ISA_MIPS3);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext));
@@ -7370,25 +7371,34 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_23:
switch (sel) {
- case 0:
+ case CP0_REG23__DEBUG:
gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */
register_name = "Debug";
break;
- case 1:
-// gen_helper_mfc0_tracecontrol(arg); /* PDtrace support */
+ case CP0_REG23__TRACECONTROL:
+ /* PDtrace support */
+ /* gen_helper_mfc0_tracecontrol(arg); */
register_name = "TraceControl";
goto cp0_unimplemented;
- case 2:
-// gen_helper_mfc0_tracecontrol2(arg); /* PDtrace support */
+ case CP0_REG23__TRACECONTROL2:
+ /* PDtrace support */
+ /* gen_helper_mfc0_tracecontrol2(arg); */
register_name = "TraceControl2";
goto cp0_unimplemented;
- case 3:
-// gen_helper_mfc0_usertracedata(arg); /* PDtrace support */
- register_name = "UserTraceData";
+ case CP0_REG23__USERTRACEDATA1:
+ /* PDtrace support */
+ /* gen_helper_mfc0_usertracedata1(arg);*/
+ register_name = "UserTraceData1";
goto cp0_unimplemented;
- case 4:
-// gen_helper_mfc0_tracebpc(arg); /* PDtrace support */
- register_name = "TraceBPC";
+ case CP0_REG23__TRACEIBPC:
+ /* PDtrace support */
+ /* gen_helper_mfc0_traceibpc(arg); */
+ register_name = "TraceIBPC";
+ goto cp0_unimplemented;
+ case CP0_REG23__TRACEDBPC:
+ /* PDtrace support */
+ /* gen_helper_mfc0_tracedbpc(arg); */
+ register_name = "TraceDBPC";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
@@ -7396,7 +7406,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_24:
switch (sel) {
- case 0:
+ case CP0_REG24__DEPC:
/* EJTAG support */
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
tcg_gen_ext32s_tl(arg, arg);
@@ -7408,35 +7418,35 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_25:
switch (sel) {
- case 0:
+ case CP0_REG25__PERFCTL0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Performance0));
register_name = "Performance0";
break;
- case 1:
+ case CP0_REG25__PERFCNT0:
/* gen_helper_mfc0_performance1(arg); */
register_name = "Performance1";
goto cp0_unimplemented;
- case 2:
+ case CP0_REG25__PERFCTL1:
/* gen_helper_mfc0_performance2(arg); */
register_name = "Performance2";
goto cp0_unimplemented;
- case 3:
+ case CP0_REG25__PERFCNT1:
/* gen_helper_mfc0_performance3(arg); */
register_name = "Performance3";
goto cp0_unimplemented;
- case 4:
+ case CP0_REG25__PERFCTL2:
/* gen_helper_mfc0_performance4(arg); */
register_name = "Performance4";
goto cp0_unimplemented;
- case 5:
+ case CP0_REG25__PERFCNT2:
/* gen_helper_mfc0_performance5(arg); */
register_name = "Performance5";
goto cp0_unimplemented;
- case 6:
+ case CP0_REG25__PERFCTL3:
/* gen_helper_mfc0_performance6(arg); */
register_name = "Performance6";
goto cp0_unimplemented;
- case 7:
+ case CP0_REG25__PERFCNT3:
/* gen_helper_mfc0_performance7(arg); */
register_name = "Performance7";
goto cp0_unimplemented;
@@ -7446,7 +7456,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_26:
switch (sel) {
- case 0:
+ case CP0_REG26__ERRCTL:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_ErrCtl));
register_name = "ErrCtl";
break;
@@ -7456,10 +7466,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_27:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
+ case CP0_REG27__CACHERR:
tcg_gen_movi_tl(arg, 0); /* unimplemented */
register_name = "CacheErr";
break;
@@ -7469,10 +7476,10 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_28:
switch (sel) {
- case 0:
- case 2:
- case 4:
- case 6:
+ case CP0_REG28__TAGLO:
+ case CP0_REG28__TAGLO1:
+ case CP0_REG28__TAGLO2:
+ case CP0_REG28__TAGLO3:
{
TCGv_i64 tmp = tcg_temp_new_i64();
tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUMIPSState, CP0_TagLo));
@@ -7481,10 +7488,10 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
register_name = "TagLo";
break;
- case 1:
- case 3:
- case 5:
- case 7:
+ case CP0_REG28__DATALO:
+ case CP0_REG28__DATALO1:
+ case CP0_REG28__DATALO2:
+ case CP0_REG28__DATALO3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataLo));
register_name = "DataLo";
break;
@@ -7494,17 +7501,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_29:
switch (sel) {
- case 0:
- case 2:
- case 4:
- case 6:
+ case CP0_REG29__TAGHI:
+ case CP0_REG29__TAGHI1:
+ case CP0_REG29__TAGHI2:
+ case CP0_REG29__TAGHI3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagHi));
register_name = "TagHi";
break;
- case 1:
- case 3:
- case 5:
- case 7:
+ case CP0_REG29__DATAHI:
+ case CP0_REG29__DATAHI1:
+ case CP0_REG29__DATAHI2:
+ case CP0_REG29__DATAHI3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataHi));
register_name = "DataHi";
break;
@@ -7514,7 +7521,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_30:
switch (sel) {
- case 0:
+ case CP0_REG30__ERROREPC:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
tcg_gen_ext32s_tl(arg, arg);
register_name = "ErrorEPC";
@@ -7525,17 +7532,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_31:
switch (sel) {
- case 0:
+ case CP0_REG31__DESAVE:
/* EJTAG support */
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
register_name = "DESAVE";
break;
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG31__KSCRATCH1:
+ case CP0_REG31__KSCRATCH2:
+ case CP0_REG31__KSCRATCH3:
+ case CP0_REG31__KSCRATCH4:
+ case CP0_REG31__KSCRATCH5:
+ case CP0_REG31__KSCRATCH6:
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_ld_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
@@ -7573,26 +7580,26 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
switch (reg) {
case CP0_REGISTER_00:
switch (sel) {
- case 0:
+ case CP0_REG00__INDEX:
gen_helper_mtc0_index(cpu_env, arg);
register_name = "Index";
break;
- case 1:
+ case CP0_REG00__MVPCONTROL:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_mvpcontrol(cpu_env, arg);
register_name = "MVPControl";
break;
- case 2:
+ case CP0_REG00__MVPCONF0:
CP0_CHECK(ctx->insn_flags & ASE_MT);
/* ignored */
register_name = "MVPConf0";
break;
- case 3:
+ case CP0_REG00__MVPCONF1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
/* ignored */
register_name = "MVPConf1";
break;
- case 4:
+ case CP0_REG00__VPCONTROL:
CP0_CHECK(ctx->vp);
/* ignored */
register_name = "VPControl";
@@ -7603,43 +7610,43 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_01:
switch (sel) {
- case 0:
+ case CP0_REG01__RANDOM:
/* ignored */
register_name = "Random";
break;
- case 1:
+ case CP0_REG01__VPECONTROL:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpecontrol(cpu_env, arg);
register_name = "VPEControl";
break;
- case 2:
+ case CP0_REG01__VPECONF0:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeconf0(cpu_env, arg);
register_name = "VPEConf0";
break;
- case 3:
+ case CP0_REG01__VPECONF1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeconf1(cpu_env, arg);
register_name = "VPEConf1";
break;
- case 4:
+ case CP0_REG01__YQMASK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_yqmask(cpu_env, arg);
register_name = "YQMask";
break;
- case 5:
+ case CP0_REG01__VPESCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
- case 6:
+ case CP0_REG01__VPESCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
- case 7:
+ case CP0_REG01__VPEOPT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeopt(cpu_env, arg);
register_name = "VPEOpt";
@@ -7650,41 +7657,41 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_02:
switch (sel) {
- case 0:
+ case CP0_REG02__ENTRYLO0:
gen_helper_mtc0_entrylo0(cpu_env, arg);
register_name = "EntryLo0";
break;
- case 1:
+ case CP0_REG02__TCSTATUS:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcstatus(cpu_env, arg);
register_name = "TCStatus";
break;
- case 2:
+ case CP0_REG02__TCBIND:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcbind(cpu_env, arg);
register_name = "TCBind";
break;
- case 3:
+ case CP0_REG02__TCRESTART:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcrestart(cpu_env, arg);
register_name = "TCRestart";
break;
- case 4:
+ case CP0_REG02__TCHALT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tchalt(cpu_env, arg);
register_name = "TCHalt";
break;
- case 5:
+ case CP0_REG02__TCCONTEXT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tccontext(cpu_env, arg);
register_name = "TCContext";
break;
- case 6:
+ case CP0_REG02__TCSCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcschedule(cpu_env, arg);
register_name = "TCSchedule";
break;
- case 7:
+ case CP0_REG02__TCSCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcschefback(cpu_env, arg);
register_name = "TCScheFBack";
@@ -7695,11 +7702,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_03:
switch (sel) {
- case 0:
+ case CP0_REG03__ENTRYLO1:
gen_helper_mtc0_entrylo1(cpu_env, arg);
register_name = "EntryLo1";
break;
- case 1:
+ case CP0_REG03__GLOBALNUM:
CP0_CHECK(ctx->vp);
/* ignored */
register_name = "GlobalNumber";
@@ -7710,15 +7717,16 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_04:
switch (sel) {
- case 0:
+ case CP0_REG04__CONTEXT:
gen_helper_mtc0_context(cpu_env, arg);
register_name = "Context";
break;
- case 1:
-// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
+ case CP0_REG04__CONTEXTCONFIG:
+ /* SmartMIPS ASE */
+ /* gen_helper_mtc0_contextconfig(arg); */
register_name = "ContextConfig";
goto cp0_unimplemented;
- case 2:
+ case CP0_REG04__USERLOCAL:
CP0_CHECK(ctx->ulri);
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
@@ -7730,42 +7738,42 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_05:
switch (sel) {
- case 0:
+ case CP0_REG05__PAGEMASK:
gen_helper_mtc0_pagemask(cpu_env, arg);
register_name = "PageMask";
break;
- case 1:
+ case CP0_REG05__PAGEGRAIN:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_pagegrain(cpu_env, arg);
register_name = "PageGrain";
ctx->base.is_jmp = DISAS_STOP;
break;
- case 2:
+ case CP0_REG05__SEGCTL0:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl0(cpu_env, arg);
register_name = "SegCtl0";
break;
- case 3:
+ case CP0_REG05__SEGCTL1:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl1(cpu_env, arg);
register_name = "SegCtl1";
break;
- case 4:
+ case CP0_REG05__SEGCTL2:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl2(cpu_env, arg);
register_name = "SegCtl2";
break;
- case 5:
+ case CP0_REG05__PWBASE:
check_pw(ctx);
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_PWBase));
register_name = "PWBase";
break;
- case 6:
+ case CP0_REG05__PWFIELD:
check_pw(ctx);
gen_helper_mtc0_pwfield(cpu_env, arg);
register_name = "PWField";
break;
- case 7:
+ case CP0_REG05__PWSIZE:
check_pw(ctx);
gen_helper_mtc0_pwsize(cpu_env, arg);
register_name = "PWSize";
@@ -7776,36 +7784,36 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_06:
switch (sel) {
- case 0:
+ case CP0_REG06__WIRED:
gen_helper_mtc0_wired(cpu_env, arg);
register_name = "Wired";
break;
- case 1:
+ case CP0_REG06__SRSCONF0:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf0(cpu_env, arg);
register_name = "SRSConf0";
break;
- case 2:
+ case CP0_REG06__SRSCONF1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf1(cpu_env, arg);
register_name = "SRSConf1";
break;
- case 3:
+ case CP0_REG06__SRSCONF2:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf2(cpu_env, arg);
register_name = "SRSConf2";
break;
- case 4:
+ case CP0_REG06__SRSCONF3:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf3(cpu_env, arg);
register_name = "SRSConf3";
break;
- case 5:
+ case CP0_REG06__SRSCONF4:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf4(cpu_env, arg);
register_name = "SRSConf4";
break;
- case 6:
+ case CP0_REG06__PWCTL:
check_pw(ctx);
gen_helper_mtc0_pwctl(cpu_env, arg);
register_name = "PWCtl";
@@ -7816,7 +7824,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_07:
switch (sel) {
- case 0:
+ case CP0_REG07__HWRENA:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_hwrena(cpu_env, arg);
ctx->base.is_jmp = DISAS_STOP;
@@ -7828,19 +7836,19 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_08:
switch (sel) {
- case 0:
+ case CP0_REG08__BADVADDR:
/* ignored */
register_name = "BadVAddr";
break;
- case 1:
+ case CP0_REG08__BADINSTR:
/* ignored */
register_name = "BadInstr";
break;
- case 2:
+ case CP0_REG08__BADINSTRP:
/* ignored */
register_name = "BadInstrP";
break;
- case 3:
+ case CP0_REG08__BADINSTRX:
/* ignored */
register_name = "BadInstrX";
break;
@@ -7850,16 +7858,16 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_09:
switch (sel) {
- case 0:
+ case CP0_REG09__COUNT:
gen_helper_mtc0_count(cpu_env, arg);
register_name = "Count";
break;
- case 6:
+ case CP0_REG09__SAARI:
CP0_CHECK(ctx->saar);
gen_helper_mtc0_saari(cpu_env, arg);
register_name = "SAARI";
break;
- case 7:
+ case CP0_REG09__SAAR:
CP0_CHECK(ctx->saar);
gen_helper_mtc0_saar(cpu_env, arg);
register_name = "SAAR";
@@ -7870,7 +7878,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_10:
switch (sel) {
- case 0:
+ case CP0_REG10__ENTRYHI:
gen_helper_mtc0_entryhi(cpu_env, arg);
register_name = "EntryHi";
break;
@@ -7880,7 +7888,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_11:
switch (sel) {
- case 0:
+ case CP0_REG11__COMPARE:
gen_helper_mtc0_compare(cpu_env, arg);
register_name = "Compare";
break;
@@ -7891,7 +7899,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_12:
switch (sel) {
- case 0:
+ case CP0_REG12__STATUS:
save_cpu_state(ctx, 1);
gen_helper_mtc0_status(cpu_env, arg);
/* DISAS_STOP isn't good enough here, hflags may have changed. */
@@ -7899,21 +7907,21 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Status";
break;
- case 1:
+ case CP0_REG12__INTCTL:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_intctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
register_name = "IntCtl";
break;
- case 2:
+ case CP0_REG12__SRSCTL:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
register_name = "SRSCtl";
break;
- case 3:
+ case CP0_REG12__SRSMAP:
check_insn(ctx, ISA_MIPS32R2);
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
/* Stop translation as we may have switched the execution mode */
@@ -7926,7 +7934,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_13:
switch (sel) {
- case 0:
+ case CP0_REG13__CAUSE:
save_cpu_state(ctx, 1);
gen_helper_mtc0_cause(cpu_env, arg);
/*
@@ -7944,7 +7952,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_14:
switch (sel) {
- case 0:
+ case CP0_REG14__EPC:
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
register_name = "EPC";
break;
@@ -7954,11 +7962,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_15:
switch (sel) {
- case 0:
+ case CP0_REG15__PRID:
/* ignored */
register_name = "PRid";
break;
- case 1:
+ case CP0_REG15__EBASE:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_ebase(cpu_env, arg);
register_name = "EBase";
@@ -7969,45 +7977,45 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_16:
switch (sel) {
- case 0:
+ case CP0_REG16__CONFIG:
gen_helper_mtc0_config0(cpu_env, arg);
register_name = "Config";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
- case 1:
+ case CP0_REG16__CONFIG1:
/* ignored, read only */
register_name = "Config1";
break;
- case 2:
+ case CP0_REG16__CONFIG2:
gen_helper_mtc0_config2(cpu_env, arg);
register_name = "Config2";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
- case 3:
+ case CP0_REG16__CONFIG3:
gen_helper_mtc0_config3(cpu_env, arg);
register_name = "Config3";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
- case 4:
+ case CP0_REG16__CONFIG4:
gen_helper_mtc0_config4(cpu_env, arg);
register_name = "Config4";
ctx->base.is_jmp = DISAS_STOP;
break;
- case 5:
+ case CP0_REG16__CONFIG5:
gen_helper_mtc0_config5(cpu_env, arg);
register_name = "Config5";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
/* 6,7 are implementation dependent */
- case 6:
+ case CP0_REG16__CONFIG6:
/* ignored */
register_name = "Config6";
break;
- case 7:
+ case CP0_REG16__CONFIG7:
/* ignored */
register_name = "Config7";
break;
@@ -8018,16 +8026,16 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_17:
switch (sel) {
- case 0:
+ case CP0_REG17__LLADDR:
gen_helper_mtc0_lladdr(cpu_env, arg);
register_name = "LLAddr";
break;
- case 1:
+ case CP0_REG17__MAAR:
CP0_CHECK(ctx->mrp);
gen_helper_mtc0_maar(cpu_env, arg);
register_name = "MAAR";
break;
- case 2:
+ case CP0_REG17__MAARI:
CP0_CHECK(ctx->mrp);
gen_helper_mtc0_maari(cpu_env, arg);
register_name = "MAARI";
@@ -8038,14 +8046,14 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_18:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG18__WATCHLO0:
+ case CP0_REG18__WATCHLO1:
+ case CP0_REG18__WATCHLO2:
+ case CP0_REG18__WATCHLO3:
+ case CP0_REG18__WATCHLO4:
+ case CP0_REG18__WATCHLO5:
+ case CP0_REG18__WATCHLO6:
+ case CP0_REG18__WATCHLO7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_0e1i(mtc0_watchlo, arg, sel);
register_name = "WatchLo";
@@ -8056,14 +8064,14 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_19:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG19__WATCHHI0:
+ case CP0_REG19__WATCHHI1:
+ case CP0_REG19__WATCHHI2:
+ case CP0_REG19__WATCHHI3:
+ case CP0_REG19__WATCHHI4:
+ case CP0_REG19__WATCHHI5:
+ case CP0_REG19__WATCHHI6:
+ case CP0_REG19__WATCHHI7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_0e1i(mtc0_watchhi, arg, sel);
register_name = "WatchHi";
@@ -8074,7 +8082,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_20:
switch (sel) {
- case 0:
+ case CP0_REG20__XCONTEXT:
#if defined(TARGET_MIPS64)
check_insn(ctx, ISA_MIPS3);
gen_helper_mtc0_xcontext(cpu_env, arg);
@@ -8103,38 +8111,49 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_23:
switch (sel) {
- case 0:
+ case CP0_REG23__DEBUG:
gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */
/* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Debug";
break;
- case 1:
-// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */
+ case CP0_REG23__TRACECONTROL:
+ /* PDtrace support */
+ /* gen_helper_mtc0_tracecontrol(cpu_env, arg); */
register_name = "TraceControl";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
goto cp0_unimplemented;
- case 2:
-// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */
+ case CP0_REG23__TRACECONTROL2:
+ /* PDtrace support */
+ /* gen_helper_mtc0_tracecontrol2(cpu_env, arg); */
register_name = "TraceControl2";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
goto cp0_unimplemented;
- case 3:
+ case CP0_REG23__USERTRACEDATA1:
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
-// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */
+ /* PDtrace support */
+ /* gen_helper_mtc0_usertracedata1(cpu_env, arg);*/
register_name = "UserTraceData";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
goto cp0_unimplemented;
- case 4:
-// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */
+ case CP0_REG23__TRACEIBPC:
+ /* PDtrace support */
+ /* gen_helper_mtc0_traceibpc(cpu_env, arg); */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- register_name = "TraceBPC";
+ register_name = "TraceIBPC";
+ goto cp0_unimplemented;
+ case CP0_REG23__TRACEDBPC:
+ /* PDtrace support */
+ /* gen_helper_mtc0_tracedbpc(cpu_env, arg); */
+ /* Stop translation as we may have switched the execution mode */
+ ctx->base.is_jmp = DISAS_STOP;
+ register_name = "TraceDBPC";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
@@ -8142,7 +8161,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_24:
switch (sel) {
- case 0:
+ case CP0_REG24__DEPC:
/* EJTAG support */
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
register_name = "DEPC";
@@ -8153,35 +8172,35 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_25:
switch (sel) {
- case 0:
+ case CP0_REG25__PERFCTL0:
gen_helper_mtc0_performance0(cpu_env, arg);
register_name = "Performance0";
break;
- case 1:
+ case CP0_REG25__PERFCNT0:
/* gen_helper_mtc0_performance1(arg); */
register_name = "Performance1";
goto cp0_unimplemented;
- case 2:
+ case CP0_REG25__PERFCTL1:
/* gen_helper_mtc0_performance2(arg); */
register_name = "Performance2";
goto cp0_unimplemented;
- case 3:
+ case CP0_REG25__PERFCNT1:
/* gen_helper_mtc0_performance3(arg); */
register_name = "Performance3";
goto cp0_unimplemented;
- case 4:
+ case CP0_REG25__PERFCTL2:
/* gen_helper_mtc0_performance4(arg); */
register_name = "Performance4";
goto cp0_unimplemented;
- case 5:
+ case CP0_REG25__PERFCNT2:
/* gen_helper_mtc0_performance5(arg); */
register_name = "Performance5";
goto cp0_unimplemented;
- case 6:
+ case CP0_REG25__PERFCTL3:
/* gen_helper_mtc0_performance6(arg); */
register_name = "Performance6";
goto cp0_unimplemented;
- case 7:
+ case CP0_REG25__PERFCNT3:
/* gen_helper_mtc0_performance7(arg); */
register_name = "Performance7";
goto cp0_unimplemented;
@@ -8191,7 +8210,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_26:
switch (sel) {
- case 0:
+ case CP0_REG26__ERRCTL:
gen_helper_mtc0_errctl(cpu_env, arg);
ctx->base.is_jmp = DISAS_STOP;
register_name = "ErrCtl";
@@ -8202,10 +8221,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_27:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
+ case CP0_REG27__CACHERR:
/* ignored */
register_name = "CacheErr";
break;
@@ -8215,17 +8231,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_28:
switch (sel) {
- case 0:
- case 2:
- case 4:
- case 6:
+ case CP0_REG28__TAGLO:
+ case CP0_REG28__TAGLO1:
+ case CP0_REG28__TAGLO2:
+ case CP0_REG28__TAGLO3:
gen_helper_mtc0_taglo(cpu_env, arg);
register_name = "TagLo";
break;
- case 1:
- case 3:
- case 5:
- case 7:
+ case CP0_REG28__DATALO:
+ case CP0_REG28__DATALO1:
+ case CP0_REG28__DATALO2:
+ case CP0_REG28__DATALO3:
gen_helper_mtc0_datalo(cpu_env, arg);
register_name = "DataLo";
break;
@@ -8235,17 +8251,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_29:
switch (sel) {
- case 0:
- case 2:
- case 4:
- case 6:
+ case CP0_REG29__TAGHI:
+ case CP0_REG29__TAGHI1:
+ case CP0_REG29__TAGHI2:
+ case CP0_REG29__TAGHI3:
gen_helper_mtc0_taghi(cpu_env, arg);
register_name = "TagHi";
break;
- case 1:
- case 3:
- case 5:
- case 7:
+ case CP0_REG29__DATAHI:
+ case CP0_REG29__DATAHI1:
+ case CP0_REG29__DATAHI2:
+ case CP0_REG29__DATAHI3:
gen_helper_mtc0_datahi(cpu_env, arg);
register_name = "DataHi";
break;
@@ -8256,7 +8272,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_30:
switch (sel) {
- case 0:
+ case CP0_REG30__ERROREPC:
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
register_name = "ErrorEPC";
break;
@@ -8266,17 +8282,17 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_31:
switch (sel) {
- case 0:
+ case CP0_REG31__DESAVE:
/* EJTAG support */
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
register_name = "DESAVE";
break;
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG31__KSCRATCH1:
+ case CP0_REG31__KSCRATCH2:
+ case CP0_REG31__KSCRATCH3:
+ case CP0_REG31__KSCRATCH4:
+ case CP0_REG31__KSCRATCH5:
+ case CP0_REG31__KSCRATCH6:
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
@@ -8319,26 +8335,26 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
switch (reg) {
case CP0_REGISTER_00:
switch (sel) {
- case 0:
+ case CP0_REG00__INDEX:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Index));
register_name = "Index";
break;
- case 1:
+ case CP0_REG00__MVPCONTROL:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpcontrol(arg, cpu_env);
register_name = "MVPControl";
break;
- case 2:
+ case CP0_REG00__MVPCONF0:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpconf0(arg, cpu_env);
register_name = "MVPConf0";
break;
- case 3:
+ case CP0_REG00__MVPCONF1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpconf1(arg, cpu_env);
register_name = "MVPConf1";
break;
- case 4:
+ case CP0_REG00__VPCONTROL:
CP0_CHECK(ctx->vp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPControl));
register_name = "VPControl";
@@ -8349,42 +8365,42 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_01:
switch (sel) {
- case 0:
+ case CP0_REG01__RANDOM:
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
gen_helper_mfc0_random(arg, cpu_env);
register_name = "Random";
break;
- case 1:
+ case CP0_REG01__VPECONTROL:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl));
register_name = "VPEControl";
break;
- case 2:
+ case CP0_REG01__VPECONF0:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0));
register_name = "VPEConf0";
break;
- case 3:
+ case CP0_REG01__VPECONF1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1));
register_name = "VPEConf1";
break;
- case 4:
+ case CP0_REG01__YQMASK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_YQMask));
register_name = "YQMask";
break;
- case 5:
+ case CP0_REG01__VPESCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
- case 6:
+ case CP0_REG01__VPESCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
- case 7:
+ case CP0_REG01__VPEOPT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt));
register_name = "VPEOpt";
@@ -8395,41 +8411,41 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_02:
switch (sel) {
- case 0:
+ case CP0_REG02__ENTRYLO0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0));
register_name = "EntryLo0";
break;
- case 1:
+ case CP0_REG02__TCSTATUS:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcstatus(arg, cpu_env);
register_name = "TCStatus";
break;
- case 2:
+ case CP0_REG02__TCBIND:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcbind(arg, cpu_env);
register_name = "TCBind";
break;
- case 3:
+ case CP0_REG02__TCRESTART:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tcrestart(arg, cpu_env);
register_name = "TCRestart";
break;
- case 4:
+ case CP0_REG02__TCHALT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tchalt(arg, cpu_env);
register_name = "TCHalt";
break;
- case 5:
+ case CP0_REG02__TCCONTEXT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tccontext(arg, cpu_env);
register_name = "TCContext";
break;
- case 6:
+ case CP0_REG02__TCSCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tcschedule(arg, cpu_env);
register_name = "TCSchedule";
break;
- case 7:
+ case CP0_REG02__TCSCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tcschefback(arg, cpu_env);
register_name = "TCScheFBack";
@@ -8440,11 +8456,11 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_03:
switch (sel) {
- case 0:
+ case CP0_REG03__ENTRYLO1:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1));
register_name = "EntryLo1";
break;
- case 1:
+ case CP0_REG03__GLOBALNUM:
CP0_CHECK(ctx->vp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_GlobalNumber));
register_name = "GlobalNumber";
@@ -8455,15 +8471,16 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_04:
switch (sel) {
- case 0:
+ case CP0_REG04__CONTEXT:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context));
register_name = "Context";
break;
- case 1:
-// gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */
+ case CP0_REG04__CONTEXTCONFIG:
+ /* SmartMIPS ASE */
+ /* gen_helper_dmfc0_contextconfig(arg); */
register_name = "ContextConfig";
goto cp0_unimplemented;
- case 2:
+ case CP0_REG04__USERLOCAL:
CP0_CHECK(ctx->ulri);
tcg_gen_ld_tl(arg, cpu_env,
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
@@ -8475,41 +8492,41 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_05:
switch (sel) {
- case 0:
+ case CP0_REG05__PAGEMASK:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageMask));
register_name = "PageMask";
break;
- case 1:
+ case CP0_REG05__PAGEGRAIN:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain));
register_name = "PageGrain";
break;
- case 2:
+ case CP0_REG05__SEGCTL0:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0));
register_name = "SegCtl0";
break;
- case 3:
+ case CP0_REG05__SEGCTL1:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1));
register_name = "SegCtl1";
break;
- case 4:
+ case CP0_REG05__SEGCTL2:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2));
register_name = "SegCtl2";
break;
- case 5:
+ case CP0_REG05__PWBASE:
check_pw(ctx);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWBase));
register_name = "PWBase";
break;
- case 6:
+ case CP0_REG05__PWFIELD:
check_pw(ctx);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWField));
register_name = "PWField";
break;
- case 7:
+ case CP0_REG05__PWSIZE:
check_pw(ctx);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWSize));
register_name = "PWSize";
@@ -8520,36 +8537,36 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_06:
switch (sel) {
- case 0:
+ case CP0_REG06__WIRED:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Wired));
register_name = "Wired";
break;
- case 1:
+ case CP0_REG06__SRSCONF0:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0));
register_name = "SRSConf0";
break;
- case 2:
+ case CP0_REG06__SRSCONF1:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1));
register_name = "SRSConf1";
break;
- case 3:
+ case CP0_REG06__SRSCONF2:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2));
register_name = "SRSConf2";
break;
- case 4:
+ case CP0_REG06__SRSCONF3:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3));
register_name = "SRSConf3";
break;
- case 5:
+ case CP0_REG06__SRSCONF4:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4));
register_name = "SRSConf4";
break;
- case 6:
+ case CP0_REG06__PWCTL:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWCtl));
register_name = "PWCtl";
@@ -8560,7 +8577,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_07:
switch (sel) {
- case 0:
+ case CP0_REG07__HWRENA:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna));
register_name = "HWREna";
@@ -8571,21 +8588,21 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_08:
switch (sel) {
- case 0:
+ case CP0_REG08__BADVADDR:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr));
register_name = "BadVAddr";
break;
- case 1:
+ case CP0_REG08__BADINSTR:
CP0_CHECK(ctx->bi);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr));
register_name = "BadInstr";
break;
- case 2:
+ case CP0_REG08__BADINSTRP:
CP0_CHECK(ctx->bp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP));
register_name = "BadInstrP";
break;
- case 3:
+ case CP0_REG08__BADINSTRX:
CP0_CHECK(ctx->bi);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrX));
tcg_gen_andi_tl(arg, arg, ~0xffff);
@@ -8597,7 +8614,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_09:
switch (sel) {
- case 0:
+ case CP0_REG09__COUNT:
/* Mark as an IO operation because we read the time. */
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
@@ -8612,12 +8629,12 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Count";
break;
- case 6:
+ case CP0_REG09__SAARI:
CP0_CHECK(ctx->saar);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SAARI));
register_name = "SAARI";
break;
- case 7:
+ case CP0_REG09__SAAR:
CP0_CHECK(ctx->saar);
gen_helper_dmfc0_saar(arg, cpu_env);
register_name = "SAAR";
@@ -8628,7 +8645,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_10:
switch (sel) {
- case 0:
+ case CP0_REG10__ENTRYHI:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi));
register_name = "EntryHi";
break;
@@ -8638,7 +8655,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_11:
switch (sel) {
- case 0:
+ case CP0_REG11__COMPARE:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare));
register_name = "Compare";
break;
@@ -8649,21 +8666,21 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_12:
switch (sel) {
- case 0:
+ case CP0_REG12__STATUS:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Status));
register_name = "Status";
break;
- case 1:
+ case CP0_REG12__INTCTL:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl));
register_name = "IntCtl";
break;
- case 2:
+ case CP0_REG12__SRSCTL:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl));
register_name = "SRSCtl";
break;
- case 3:
+ case CP0_REG12__SRSMAP:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
register_name = "SRSMap";
@@ -8674,7 +8691,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_13:
switch (sel) {
- case 0:
+ case CP0_REG13__CAUSE:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Cause));
register_name = "Cause";
break;
@@ -8684,7 +8701,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_14:
switch (sel) {
- case 0:
+ case CP0_REG14__EPC:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
register_name = "EPC";
break;
@@ -8694,16 +8711,16 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_15:
switch (sel) {
- case 0:
+ case CP0_REG15__PRID:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PRid));
register_name = "PRid";
break;
- case 1:
+ case CP0_REG15__EBASE:
check_insn(ctx, ISA_MIPS32R2);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase));
register_name = "EBase";
break;
- case 3:
+ case CP0_REG15__CMGCRBASE:
check_insn(ctx, ISA_MIPS32R2);
CP0_CHECK(ctx->cmgcr);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_CMGCRBase));
@@ -8715,36 +8732,36 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_16:
switch (sel) {
- case 0:
+ case CP0_REG16__CONFIG:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config0));
register_name = "Config";
break;
- case 1:
+ case CP0_REG16__CONFIG1:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config1));
register_name = "Config1";
break;
- case 2:
+ case CP0_REG16__CONFIG2:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config2));
register_name = "Config2";
break;
- case 3:
+ case CP0_REG16__CONFIG3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3));
register_name = "Config3";
break;
- case 4:
+ case CP0_REG16__CONFIG4:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config4));
register_name = "Config4";
break;
- case 5:
+ case CP0_REG16__CONFIG5:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5));
register_name = "Config5";
break;
/* 6,7 are implementation dependent */
- case 6:
+ case CP0_REG16__CONFIG6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6));
register_name = "Config6";
break;
- case 7:
+ case CP0_REG16__CONFIG7:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config7));
register_name = "Config7";
break;
@@ -8754,16 +8771,16 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_17:
switch (sel) {
- case 0:
+ case CP0_REG17__LLADDR:
gen_helper_dmfc0_lladdr(arg, cpu_env);
register_name = "LLAddr";
break;
- case 1:
+ case CP0_REG17__MAAR:
CP0_CHECK(ctx->mrp);
gen_helper_dmfc0_maar(arg, cpu_env);
register_name = "MAAR";
break;
- case 2:
+ case CP0_REG17__MAARI:
CP0_CHECK(ctx->mrp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_MAARI));
register_name = "MAARI";
@@ -8774,14 +8791,14 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_18:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG18__WATCHLO0:
+ case CP0_REG18__WATCHLO1:
+ case CP0_REG18__WATCHLO2:
+ case CP0_REG18__WATCHLO3:
+ case CP0_REG18__WATCHLO4:
+ case CP0_REG18__WATCHLO5:
+ case CP0_REG18__WATCHLO6:
+ case CP0_REG18__WATCHLO7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_1e0i(dmfc0_watchlo, arg, sel);
register_name = "WatchLo";
@@ -8792,14 +8809,14 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_19:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG19__WATCHHI0:
+ case CP0_REG19__WATCHHI1:
+ case CP0_REG19__WATCHHI2:
+ case CP0_REG19__WATCHHI3:
+ case CP0_REG19__WATCHHI4:
+ case CP0_REG19__WATCHHI5:
+ case CP0_REG19__WATCHHI6:
+ case CP0_REG19__WATCHHI7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_1e0i(mfc0_watchhi, arg, sel);
register_name = "WatchHi";
@@ -8810,7 +8827,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_20:
switch (sel) {
- case 0:
+ case CP0_REG20__XCONTEXT:
check_insn(ctx, ISA_MIPS3);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext));
register_name = "XContext";
@@ -8837,25 +8854,34 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_23:
switch (sel) {
- case 0:
+ case CP0_REG23__DEBUG:
gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */
register_name = "Debug";
break;
- case 1:
-// gen_helper_dmfc0_tracecontrol(arg, cpu_env); /* PDtrace support */
+ case CP0_REG23__TRACECONTROL:
+ /* PDtrace support */
+ /* gen_helper_dmfc0_tracecontrol(arg, cpu_env); */
register_name = "TraceControl";
goto cp0_unimplemented;
- case 2:
-// gen_helper_dmfc0_tracecontrol2(arg, cpu_env); /* PDtrace support */
+ case CP0_REG23__TRACECONTROL2:
+ /* PDtrace support */
+ /* gen_helper_dmfc0_tracecontrol2(arg, cpu_env); */
register_name = "TraceControl2";
goto cp0_unimplemented;
- case 3:
-// gen_helper_dmfc0_usertracedata(arg, cpu_env); /* PDtrace support */
- register_name = "UserTraceData";
+ case CP0_REG23__USERTRACEDATA1:
+ /* PDtrace support */
+ /* gen_helper_dmfc0_usertracedata1(arg, cpu_env);*/
+ register_name = "UserTraceData1";
goto cp0_unimplemented;
- case 4:
-// gen_helper_dmfc0_tracebpc(arg, cpu_env); /* PDtrace support */
- register_name = "TraceBPC";
+ case CP0_REG23__TRACEIBPC:
+ /* PDtrace support */
+ /* gen_helper_dmfc0_traceibpc(arg, cpu_env); */
+ register_name = "TraceIBPC";
+ goto cp0_unimplemented;
+ case CP0_REG23__TRACEDBPC:
+ /* PDtrace support */
+ /* gen_helper_dmfc0_tracedbpc(arg, cpu_env); */
+ register_name = "TraceDBPC";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
@@ -8863,7 +8889,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_24:
switch (sel) {
- case 0:
+ case CP0_REG24__DEPC:
/* EJTAG support */
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
register_name = "DEPC";
@@ -8874,35 +8900,35 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_25:
switch (sel) {
- case 0:
+ case CP0_REG25__PERFCTL0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Performance0));
register_name = "Performance0";
break;
- case 1:
+ case CP0_REG25__PERFCNT0:
/* gen_helper_dmfc0_performance1(arg); */
register_name = "Performance1";
goto cp0_unimplemented;
- case 2:
+ case CP0_REG25__PERFCTL1:
/* gen_helper_dmfc0_performance2(arg); */
register_name = "Performance2";
goto cp0_unimplemented;
- case 3:
+ case CP0_REG25__PERFCNT1:
/* gen_helper_dmfc0_performance3(arg); */
register_name = "Performance3";
goto cp0_unimplemented;
- case 4:
+ case CP0_REG25__PERFCTL2:
/* gen_helper_dmfc0_performance4(arg); */
register_name = "Performance4";
goto cp0_unimplemented;
- case 5:
+ case CP0_REG25__PERFCNT2:
/* gen_helper_dmfc0_performance5(arg); */
register_name = "Performance5";
goto cp0_unimplemented;
- case 6:
+ case CP0_REG25__PERFCTL3:
/* gen_helper_dmfc0_performance6(arg); */
register_name = "Performance6";
goto cp0_unimplemented;
- case 7:
+ case CP0_REG25__PERFCNT3:
/* gen_helper_dmfc0_performance7(arg); */
register_name = "Performance7";
goto cp0_unimplemented;
@@ -8912,7 +8938,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_26:
switch (sel) {
- case 0:
+ case CP0_REG26__ERRCTL:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_ErrCtl));
register_name = "ErrCtl";
break;
@@ -8923,10 +8949,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case CP0_REGISTER_27:
switch (sel) {
/* ignored */
- case 0:
- case 1:
- case 2:
- case 3:
+ case CP0_REG27__CACHERR:
tcg_gen_movi_tl(arg, 0); /* unimplemented */
register_name = "CacheErr";
break;
@@ -8936,17 +8959,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_28:
switch (sel) {
- case 0:
- case 2:
- case 4:
- case 6:
+ case CP0_REG28__TAGLO:
+ case CP0_REG28__TAGLO1:
+ case CP0_REG28__TAGLO2:
+ case CP0_REG28__TAGLO3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagLo));
register_name = "TagLo";
break;
- case 1:
- case 3:
- case 5:
- case 7:
+ case CP0_REG28__DATALO:
+ case CP0_REG28__DATALO1:
+ case CP0_REG28__DATALO2:
+ case CP0_REG28__DATALO3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataLo));
register_name = "DataLo";
break;
@@ -8956,17 +8979,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_29:
switch (sel) {
- case 0:
- case 2:
- case 4:
- case 6:
+ case CP0_REG29__TAGHI:
+ case CP0_REG29__TAGHI1:
+ case CP0_REG29__TAGHI2:
+ case CP0_REG29__TAGHI3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagHi));
register_name = "TagHi";
break;
- case 1:
- case 3:
- case 5:
- case 7:
+ case CP0_REG29__DATAHI:
+ case CP0_REG29__DATAHI1:
+ case CP0_REG29__DATAHI2:
+ case CP0_REG29__DATAHI3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataHi));
register_name = "DataHi";
break;
@@ -8976,7 +8999,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_30:
switch (sel) {
- case 0:
+ case CP0_REG30__ERROREPC:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
register_name = "ErrorEPC";
break;
@@ -8986,17 +9009,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_31:
switch (sel) {
- case 0:
+ case CP0_REG31__DESAVE:
/* EJTAG support */
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
register_name = "DESAVE";
break;
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG31__KSCRATCH1:
+ case CP0_REG31__KSCRATCH2:
+ case CP0_REG31__KSCRATCH3:
+ case CP0_REG31__KSCRATCH4:
+ case CP0_REG31__KSCRATCH5:
+ case CP0_REG31__KSCRATCH6:
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_ld_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
@@ -9033,26 +9056,26 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
switch (reg) {
case CP0_REGISTER_00:
switch (sel) {
- case 0:
+ case CP0_REG00__INDEX:
gen_helper_mtc0_index(cpu_env, arg);
register_name = "Index";
break;
- case 1:
+ case CP0_REG00__MVPCONTROL:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_mvpcontrol(cpu_env, arg);
register_name = "MVPControl";
break;
- case 2:
+ case CP0_REG00__MVPCONF0:
CP0_CHECK(ctx->insn_flags & ASE_MT);
/* ignored */
register_name = "MVPConf0";
break;
- case 3:
+ case CP0_REG00__MVPCONF1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
/* ignored */
register_name = "MVPConf1";
break;
- case 4:
+ case CP0_REG00__VPCONTROL:
CP0_CHECK(ctx->vp);
/* ignored */
register_name = "VPControl";
@@ -9063,41 +9086,41 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_01:
switch (sel) {
- case 0:
+ case CP0_REG01__RANDOM:
/* ignored */
register_name = "Random";
break;
- case 1:
+ case CP0_REG01__VPECONTROL:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpecontrol(cpu_env, arg);
register_name = "VPEControl";
break;
- case 2:
+ case CP0_REG01__VPECONF0:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeconf0(cpu_env, arg);
register_name = "VPEConf0";
break;
- case 3:
+ case CP0_REG01__VPECONF1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeconf1(cpu_env, arg);
register_name = "VPEConf1";
break;
- case 4:
+ case CP0_REG01__YQMASK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_yqmask(cpu_env, arg);
register_name = "YQMask";
break;
- case 5:
+ case CP0_REG01__VPESCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
- case 6:
+ case CP0_REG01__VPESCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
- case 7:
+ case CP0_REG01__VPEOPT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeopt(cpu_env, arg);
register_name = "VPEOpt";
@@ -9108,41 +9131,41 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_02:
switch (sel) {
- case 0:
+ case CP0_REG02__ENTRYLO0:
gen_helper_dmtc0_entrylo0(cpu_env, arg);
register_name = "EntryLo0";
break;
- case 1:
+ case CP0_REG02__TCSTATUS:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcstatus(cpu_env, arg);
register_name = "TCStatus";
break;
- case 2:
+ case CP0_REG02__TCBIND:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcbind(cpu_env, arg);
register_name = "TCBind";
break;
- case 3:
+ case CP0_REG02__TCRESTART:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcrestart(cpu_env, arg);
register_name = "TCRestart";
break;
- case 4:
+ case CP0_REG02__TCHALT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tchalt(cpu_env, arg);
register_name = "TCHalt";
break;
- case 5:
+ case CP0_REG02__TCCONTEXT:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tccontext(cpu_env, arg);
register_name = "TCContext";
break;
- case 6:
+ case CP0_REG02__TCSCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcschedule(cpu_env, arg);
register_name = "TCSchedule";
break;
- case 7:
+ case CP0_REG02__TCSCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcschefback(cpu_env, arg);
register_name = "TCScheFBack";
@@ -9153,11 +9176,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_03:
switch (sel) {
- case 0:
+ case CP0_REG03__ENTRYLO1:
gen_helper_dmtc0_entrylo1(cpu_env, arg);
register_name = "EntryLo1";
break;
- case 1:
+ case CP0_REG03__GLOBALNUM:
CP0_CHECK(ctx->vp);
/* ignored */
register_name = "GlobalNumber";
@@ -9168,15 +9191,16 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_04:
switch (sel) {
- case 0:
+ case CP0_REG04__CONTEXT:
gen_helper_mtc0_context(cpu_env, arg);
register_name = "Context";
break;
- case 1:
-// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
+ case CP0_REG04__CONTEXTCONFIG:
+ /* SmartMIPS ASE */
+ /* gen_helper_dmtc0_contextconfig(arg); */
register_name = "ContextConfig";
goto cp0_unimplemented;
- case 2:
+ case CP0_REG04__USERLOCAL:
CP0_CHECK(ctx->ulri);
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
@@ -9188,41 +9212,41 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_05:
switch (sel) {
- case 0:
+ case CP0_REG05__PAGEMASK:
gen_helper_mtc0_pagemask(cpu_env, arg);
register_name = "PageMask";
break;
- case 1:
+ case CP0_REG05__PAGEGRAIN:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_pagegrain(cpu_env, arg);
register_name = "PageGrain";
break;
- case 2:
+ case CP0_REG05__SEGCTL0:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl0(cpu_env, arg);
register_name = "SegCtl0";
break;
- case 3:
+ case CP0_REG05__SEGCTL1:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl1(cpu_env, arg);
register_name = "SegCtl1";
break;
- case 4:
+ case CP0_REG05__SEGCTL2:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl2(cpu_env, arg);
register_name = "SegCtl2";
break;
- case 5:
+ case CP0_REG05__PWBASE:
check_pw(ctx);
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWBase));
register_name = "PWBase";
break;
- case 6:
+ case CP0_REG05__PWFIELD:
check_pw(ctx);
gen_helper_mtc0_pwfield(cpu_env, arg);
register_name = "PWField";
break;
- case 7:
+ case CP0_REG05__PWSIZE:
check_pw(ctx);
gen_helper_mtc0_pwsize(cpu_env, arg);
register_name = "PWSize";
@@ -9233,36 +9257,36 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_06:
switch (sel) {
- case 0:
+ case CP0_REG06__WIRED:
gen_helper_mtc0_wired(cpu_env, arg);
register_name = "Wired";
break;
- case 1:
+ case CP0_REG06__SRSCONF0:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf0(cpu_env, arg);
register_name = "SRSConf0";
break;
- case 2:
+ case CP0_REG06__SRSCONF1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf1(cpu_env, arg);
register_name = "SRSConf1";
break;
- case 3:
+ case CP0_REG06__SRSCONF2:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf2(cpu_env, arg);
register_name = "SRSConf2";
break;
- case 4:
+ case CP0_REG06__SRSCONF3:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf3(cpu_env, arg);
register_name = "SRSConf3";
break;
- case 5:
+ case CP0_REG06__SRSCONF4:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf4(cpu_env, arg);
register_name = "SRSConf4";
break;
- case 6:
+ case CP0_REG06__PWCTL:
check_pw(ctx);
gen_helper_mtc0_pwctl(cpu_env, arg);
register_name = "PWCtl";
@@ -9273,7 +9297,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_07:
switch (sel) {
- case 0:
+ case CP0_REG07__HWRENA:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_hwrena(cpu_env, arg);
ctx->base.is_jmp = DISAS_STOP;
@@ -9285,19 +9309,19 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_08:
switch (sel) {
- case 0:
+ case CP0_REG08__BADVADDR:
/* ignored */
register_name = "BadVAddr";
break;
- case 1:
+ case CP0_REG08__BADINSTR:
/* ignored */
register_name = "BadInstr";
break;
- case 2:
+ case CP0_REG08__BADINSTRP:
/* ignored */
register_name = "BadInstrP";
break;
- case 3:
+ case CP0_REG08__BADINSTRX:
/* ignored */
register_name = "BadInstrX";
break;
@@ -9307,16 +9331,16 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_09:
switch (sel) {
- case 0:
+ case CP0_REG09__COUNT:
gen_helper_mtc0_count(cpu_env, arg);
register_name = "Count";
break;
- case 6:
+ case CP0_REG09__SAARI:
CP0_CHECK(ctx->saar);
gen_helper_mtc0_saari(cpu_env, arg);
register_name = "SAARI";
break;
- case 7:
+ case CP0_REG09__SAAR:
CP0_CHECK(ctx->saar);
gen_helper_mtc0_saar(cpu_env, arg);
register_name = "SAAR";
@@ -9329,7 +9353,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_10:
switch (sel) {
- case 0:
+ case CP0_REG10__ENTRYHI:
gen_helper_mtc0_entryhi(cpu_env, arg);
register_name = "EntryHi";
break;
@@ -9339,7 +9363,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_11:
switch (sel) {
- case 0:
+ case CP0_REG11__COMPARE:
gen_helper_mtc0_compare(cpu_env, arg);
register_name = "Compare";
break;
@@ -9352,7 +9376,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_12:
switch (sel) {
- case 0:
+ case CP0_REG12__STATUS:
save_cpu_state(ctx, 1);
gen_helper_mtc0_status(cpu_env, arg);
/* DISAS_STOP isn't good enough here, hflags may have changed. */
@@ -9360,21 +9384,21 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Status";
break;
- case 1:
+ case CP0_REG12__INTCTL:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_intctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
register_name = "IntCtl";
break;
- case 2:
+ case CP0_REG12__SRSCTL:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
register_name = "SRSCtl";
break;
- case 3:
+ case CP0_REG12__SRSMAP:
check_insn(ctx, ISA_MIPS32R2);
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
/* Stop translation as we may have switched the execution mode */
@@ -9387,7 +9411,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_13:
switch (sel) {
- case 0:
+ case CP0_REG13__CAUSE:
save_cpu_state(ctx, 1);
gen_helper_mtc0_cause(cpu_env, arg);
/*
@@ -9405,7 +9429,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_14:
switch (sel) {
- case 0:
+ case CP0_REG14__EPC:
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
register_name = "EPC";
break;
@@ -9415,11 +9439,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_15:
switch (sel) {
- case 0:
+ case CP0_REG15__PRID:
/* ignored */
register_name = "PRid";
break;
- case 1:
+ case CP0_REG15__EBASE:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_ebase(cpu_env, arg);
register_name = "EBase";
@@ -9430,33 +9454,33 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_16:
switch (sel) {
- case 0:
+ case CP0_REG16__CONFIG:
gen_helper_mtc0_config0(cpu_env, arg);
register_name = "Config";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
- case 1:
+ case CP0_REG16__CONFIG1:
/* ignored, read only */
register_name = "Config1";
break;
- case 2:
+ case CP0_REG16__CONFIG2:
gen_helper_mtc0_config2(cpu_env, arg);
register_name = "Config2";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
- case 3:
+ case CP0_REG16__CONFIG3:
gen_helper_mtc0_config3(cpu_env, arg);
register_name = "Config3";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
- case 4:
+ case CP0_REG16__CONFIG4:
/* currently ignored */
register_name = "Config4";
break;
- case 5:
+ case CP0_REG16__CONFIG5:
gen_helper_mtc0_config5(cpu_env, arg);
register_name = "Config5";
/* Stop translation as we may have switched the execution mode */
@@ -9470,16 +9494,16 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_17:
switch (sel) {
- case 0:
+ case CP0_REG17__LLADDR:
gen_helper_mtc0_lladdr(cpu_env, arg);
register_name = "LLAddr";
break;
- case 1:
+ case CP0_REG17__MAAR:
CP0_CHECK(ctx->mrp);
gen_helper_mtc0_maar(cpu_env, arg);
register_name = "MAAR";
break;
- case 2:
+ case CP0_REG17__MAARI:
CP0_CHECK(ctx->mrp);
gen_helper_mtc0_maari(cpu_env, arg);
register_name = "MAARI";
@@ -9490,14 +9514,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_18:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG18__WATCHLO0:
+ case CP0_REG18__WATCHLO1:
+ case CP0_REG18__WATCHLO2:
+ case CP0_REG18__WATCHLO3:
+ case CP0_REG18__WATCHLO4:
+ case CP0_REG18__WATCHLO5:
+ case CP0_REG18__WATCHLO6:
+ case CP0_REG18__WATCHLO7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_0e1i(mtc0_watchlo, arg, sel);
register_name = "WatchLo";
@@ -9508,14 +9532,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_19:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG19__WATCHHI0:
+ case CP0_REG19__WATCHHI1:
+ case CP0_REG19__WATCHHI2:
+ case CP0_REG19__WATCHHI3:
+ case CP0_REG19__WATCHHI4:
+ case CP0_REG19__WATCHHI5:
+ case CP0_REG19__WATCHHI6:
+ case CP0_REG19__WATCHHI7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_0e1i(mtc0_watchhi, arg, sel);
register_name = "WatchHi";
@@ -9526,7 +9550,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_20:
switch (sel) {
- case 0:
+ case CP0_REG20__XCONTEXT:
check_insn(ctx, ISA_MIPS3);
gen_helper_mtc0_xcontext(cpu_env, arg);
register_name = "XContext";
@@ -9553,36 +9577,47 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_23:
switch (sel) {
- case 0:
+ case CP0_REG23__DEBUG:
gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */
/* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Debug";
break;
- case 1:
-// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */
+ case CP0_REG23__TRACECONTROL:
+ /* PDtrace support */
+ /* gen_helper_mtc0_tracecontrol(cpu_env, arg); */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
register_name = "TraceControl";
goto cp0_unimplemented;
- case 2:
-// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */
+ case CP0_REG23__TRACECONTROL2:
+ /* PDtrace support */
+ /* gen_helper_mtc0_tracecontrol2(cpu_env, arg); */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
register_name = "TraceControl2";
goto cp0_unimplemented;
- case 3:
-// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */
+ case CP0_REG23__USERTRACEDATA1:
+ /* PDtrace support */
+ /* gen_helper_mtc0_usertracedata1(cpu_env, arg);*/
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- register_name = "UserTraceData";
+ register_name = "UserTraceData1";
goto cp0_unimplemented;
- case 4:
-// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */
+ case CP0_REG23__TRACEIBPC:
+ /* PDtrace support */
+ /* gen_helper_mtc0_traceibpc(cpu_env, arg); */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- register_name = "TraceBPC";
+ register_name = "TraceIBPC";
+ goto cp0_unimplemented;
+ case CP0_REG23__TRACEDBPC:
+ /* PDtrace support */
+ /* gen_helper_mtc0_tracedbpc(cpu_env, arg); */
+ /* Stop translation as we may have switched the execution mode */
+ ctx->base.is_jmp = DISAS_STOP;
+ register_name = "TraceDBPC";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
@@ -9590,7 +9625,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_24:
switch (sel) {
- case 0:
+ case CP0_REG24__DEPC:
/* EJTAG support */
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
register_name = "DEPC";
@@ -9601,35 +9636,35 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_25:
switch (sel) {
- case 0:
+ case CP0_REG25__PERFCTL0:
gen_helper_mtc0_performance0(cpu_env, arg);
register_name = "Performance0";
break;
- case 1:
+ case CP0_REG25__PERFCNT0:
/* gen_helper_mtc0_performance1(cpu_env, arg); */
register_name = "Performance1";
goto cp0_unimplemented;
- case 2:
+ case CP0_REG25__PERFCTL1:
/* gen_helper_mtc0_performance2(cpu_env, arg); */
register_name = "Performance2";
goto cp0_unimplemented;
- case 3:
+ case CP0_REG25__PERFCNT1:
/* gen_helper_mtc0_performance3(cpu_env, arg); */
register_name = "Performance3";
goto cp0_unimplemented;
- case 4:
+ case CP0_REG25__PERFCTL2:
/* gen_helper_mtc0_performance4(cpu_env, arg); */
register_name = "Performance4";
goto cp0_unimplemented;
- case 5:
+ case CP0_REG25__PERFCNT2:
/* gen_helper_mtc0_performance5(cpu_env, arg); */
register_name = "Performance5";
goto cp0_unimplemented;
- case 6:
+ case CP0_REG25__PERFCTL3:
/* gen_helper_mtc0_performance6(cpu_env, arg); */
register_name = "Performance6";
goto cp0_unimplemented;
- case 7:
+ case CP0_REG25__PERFCNT3:
/* gen_helper_mtc0_performance7(cpu_env, arg); */
register_name = "Performance7";
goto cp0_unimplemented;
@@ -9639,7 +9674,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_26:
switch (sel) {
- case 0:
+ case CP0_REG26__ERRCTL:
gen_helper_mtc0_errctl(cpu_env, arg);
ctx->base.is_jmp = DISAS_STOP;
register_name = "ErrCtl";
@@ -9650,10 +9685,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_27:
switch (sel) {
- case 0:
- case 1:
- case 2:
- case 3:
+ case CP0_REG27__CACHERR:
/* ignored */
register_name = "CacheErr";
break;
@@ -9663,17 +9695,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_28:
switch (sel) {
- case 0:
- case 2:
- case 4:
- case 6:
+ case CP0_REG28__TAGLO:
+ case CP0_REG28__TAGLO1:
+ case CP0_REG28__TAGLO2:
+ case CP0_REG28__TAGLO3:
gen_helper_mtc0_taglo(cpu_env, arg);
register_name = "TagLo";
break;
- case 1:
- case 3:
- case 5:
- case 7:
+ case CP0_REG28__DATALO:
+ case CP0_REG28__DATALO1:
+ case CP0_REG28__DATALO2:
+ case CP0_REG28__DATALO3:
gen_helper_mtc0_datalo(cpu_env, arg);
register_name = "DataLo";
break;
@@ -9683,17 +9715,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_29:
switch (sel) {
- case 0:
- case 2:
- case 4:
- case 6:
+ case CP0_REG29__TAGHI:
+ case CP0_REG29__TAGHI1:
+ case CP0_REG29__TAGHI2:
+ case CP0_REG29__TAGHI3:
gen_helper_mtc0_taghi(cpu_env, arg);
register_name = "TagHi";
break;
- case 1:
- case 3:
- case 5:
- case 7:
+ case CP0_REG29__DATAHI:
+ case CP0_REG29__DATAHI1:
+ case CP0_REG29__DATAHI2:
+ case CP0_REG29__DATAHI3:
gen_helper_mtc0_datahi(cpu_env, arg);
register_name = "DataHi";
break;
@@ -9704,7 +9736,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_30:
switch (sel) {
- case 0:
+ case CP0_REG30__ERROREPC:
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
register_name = "ErrorEPC";
break;
@@ -9714,17 +9746,17 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REGISTER_31:
switch (sel) {
- case 0:
+ case CP0_REG31__DESAVE:
/* EJTAG support */
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
register_name = "DESAVE";
break;
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
+ case CP0_REG31__KSCRATCH1:
+ case CP0_REG31__KSCRATCH2:
+ case CP0_REG31__KSCRATCH3:
+ case CP0_REG31__KSCRATCH4:
+ case CP0_REG31__KSCRATCH5:
+ case CP0_REG31__KSCRATCH6:
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_KScratch[sel - 2]));
@@ -21827,7 +21859,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
extract32(ctx->opcode, 0, 8);
TCGv va = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGMemOp memop = (extract32(ctx->opcode, 8, 3)) ==
+ MemOp memop = (extract32(ctx->opcode, 8, 3)) ==
NM_P_LS_UAWM ? MO_UNALN : 0;
count = (count == 0) ? 8 : count;
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index f19e482a55..506aec6bfb 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -55,13 +55,7 @@ static void openrisc_cpu_reset(CPUState *s)
cpu->env.sr = SR_FO | SR_SM;
cpu->env.lock_addr = -1;
s->exception_index = -1;
-
- cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP |
- UPR_PMP;
- cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2))
- | (DMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
- cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2))
- | (IMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
+ cpu_set_fpcsr(&cpu->env, 0);
#ifndef CONFIG_USER_ONLY
cpu->env.picmr = 0x00000000;
@@ -117,15 +111,35 @@ static void or1200_initfn(Object *obj)
{
OpenRISCCPU *cpu = OPENRISC_CPU(obj);
+ cpu->env.vr = 0x13000008;
+ cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP | UPR_PMP;
cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_OF32S |
CPUCFGR_EVBARP;
+
+ /* 1Way, TLB_SIZE entries. */
+ cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2))
+ | (DMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
+ cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2))
+ | (IMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
}
static void openrisc_any_initfn(Object *obj)
{
OpenRISCCPU *cpu = OPENRISC_CPU(obj);
- cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_EVBARP;
+ cpu->env.vr = 0x13000040; /* Obsolete VER + UVRP for new SPRs */
+ cpu->env.vr2 = 0; /* No version specific id */
+ cpu->env.avr = 0x01030000; /* Architecture v1.3 */
+
+ cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP | UPR_PMP;
+ cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_OF32S |
+ CPUCFGR_AVRP | CPUCFGR_EVBARP | CPUCFGR_OF64A32S;
+
+ /* 1Way, TLB_SIZE entries. */
+ cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2))
+ | (DMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
+ cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2))
+ | (IMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
}
static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index 561f0f7fad..0ad02eab79 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -68,9 +68,6 @@ enum {
(reg) |= ((v & 0x1f) << 2);\
} while (0)
-/* Version Register */
-#define SPR_VR 0xFFFF003F
-
/* Interrupt */
#define NR_IRQS 32
@@ -99,11 +96,12 @@ enum {
CPUCFGR_OF32S = (1 << 7),
CPUCFGR_OF64S = (1 << 8),
CPUCFGR_OV64S = (1 << 9),
- /* CPUCFGR_ND = (1 << 10), */
- /* CPUCFGR_AVRP = (1 << 11), */
+ CPUCFGR_ND = (1 << 10),
+ CPUCFGR_AVRP = (1 << 11),
CPUCFGR_EVBARP = (1 << 12),
- /* CPUCFGR_ISRP = (1 << 13), */
- /* CPUCFGR_AECSRP = (1 << 14), */
+ CPUCFGR_ISRP = (1 << 13),
+ CPUCFGR_AECSRP = (1 << 14),
+ CPUCFGR_OF64A32S = (1 << 15),
};
/* DMMU configure register */
@@ -263,10 +261,6 @@ typedef struct CPUOpenRISCState {
target_ulong sr_cy; /* the SR_CY bit, values 0, 1. */
target_long sr_ov; /* the SR_OV bit (in the sign bit only) */
uint32_t sr; /* Supervisor register, without SR_{F,CY,OV} */
- uint32_t vr; /* Version register */
- uint32_t upr; /* Unit presence register */
- uint32_t dmmucfgr; /* DMMU configure register */
- uint32_t immucfgr; /* IMMU configure register */
uint32_t esr; /* Exception supervisor register */
uint32_t evbar; /* Exception vector base address register */
uint32_t pmr; /* Power Management Register */
@@ -286,7 +280,13 @@ typedef struct CPUOpenRISCState {
struct {} end_reset_fields;
/* Fields from here on are preserved across CPU reset. */
+ uint32_t vr; /* Version register */
+ uint32_t vr2; /* Version register 2 */
+ uint32_t avr; /* Architecture version register */
+ uint32_t upr; /* Unit presence register */
uint32_t cpucfgr; /* CPU configure register */
+ uint32_t dmmucfgr; /* DMMU configure register */
+ uint32_t immucfgr; /* IMMU configure register */
#ifndef CONFIG_USER_ONLY
QEMUTimer *timer;
@@ -413,6 +413,8 @@ static inline void cpu_set_sr(CPUOpenRISCState *env, uint32_t val)
env->sr = (val & ~(SR_F | SR_CY | SR_OV)) | SR_FO;
}
+void cpu_set_fpcsr(CPUOpenRISCState *env, uint32_t val);
+
#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0
#endif /* OPENRISC_CPU_H */
diff --git a/target/openrisc/disas.c b/target/openrisc/disas.c
index 7091832347..ce112640b9 100644
--- a/target/openrisc/disas.c
+++ b/target/openrisc/disas.c
@@ -98,6 +98,7 @@ INSN(sw, "%d(r%d), r%d", a->i, a->a, a->b)
INSN(sb, "%d(r%d), r%d", a->i, a->a, a->b)
INSN(sh, "%d(r%d), r%d", a->i, a->a, a->b)
INSN(nop, "")
+INSN(adrp, "r%d, %d", a->d, a->i)
INSN(addi, "r%d, r%d, %d", a->d, a->a, a->i)
INSN(addic, "r%d, r%d, %d", a->d, a->a, a->i)
INSN(muli, "r%d, r%d, %d", a->d, a->a, a->i)
@@ -166,3 +167,83 @@ FP_INSN(sfgt, s, "r%d, r%d", a->a, a->b)
FP_INSN(sfge, s, "r%d, r%d", a->a, a->b)
FP_INSN(sflt, s, "r%d, r%d", a->a, a->b)
FP_INSN(sfle, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfun, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfueq, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfuge, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfugt, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfule, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfult, s, "r%d, r%d", a->a, a->b)
+
+FP_INSN(add, d, "r%d,r%d, r%d,r%d, r%d,r%d",
+ a->d, a->d + a->dp + 1,
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sub, d, "r%d,r%d, r%d,r%d, r%d,r%d",
+ a->d, a->d + a->dp + 1,
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(mul, d, "r%d,r%d, r%d,r%d, r%d,r%d",
+ a->d, a->d + a->dp + 1,
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(div, d, "r%d,r%d, r%d,r%d, r%d,r%d",
+ a->d, a->d + a->dp + 1,
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(rem, d, "r%d,r%d, r%d,r%d, r%d,r%d",
+ a->d, a->d + a->dp + 1,
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(madd, d, "r%d,r%d, r%d,r%d, r%d,r%d",
+ a->d, a->d + a->dp + 1,
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+
+FP_INSN(itof, d, "r%d,r%d, r%d,r%d",
+ a->d, a->d + a->dp + 1,
+ a->a, a->a + a->ap + 1)
+FP_INSN(ftoi, d, "r%d,r%d, r%d,r%d",
+ a->d, a->d + a->dp + 1,
+ a->a, a->a + a->ap + 1)
+
+FP_INSN(stod, d, "r%d,r%d, r%d",
+ a->d, a->d + a->dp + 1, a->a)
+FP_INSN(dtos, d, "r%d r%d,r%d",
+ a->d, a->a, a->a + a->ap + 1)
+
+FP_INSN(sfeq, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfne, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfgt, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfge, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sflt, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfle, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfun, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfueq, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfuge, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfugt, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfule, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
+FP_INSN(sfult, d, "r%d,r%d, r%d,r%d",
+ a->a, a->a + a->ap + 1,
+ a->b, a->b + a->bp + 1)
diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c
index b9d2ebbb8c..59e1413279 100644
--- a/target/openrisc/fpu_helper.c
+++ b/target/openrisc/fpu_helper.c
@@ -61,9 +61,22 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env)
}
}
+void cpu_set_fpcsr(CPUOpenRISCState *env, uint32_t val)
+{
+ static const int rm_to_sf[] = {
+ float_round_nearest_even,
+ float_round_to_zero,
+ float_round_up,
+ float_round_down
+ };
+
+ env->fpcsr = val & 0x7ff;
+ set_float_rounding_mode(rm_to_sf[extract32(val, 1, 2)], &env->fp_status);
+}
+
uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val)
{
- return int32_to_float64(val, &env->fp_status);
+ return int64_to_float64(val, &env->fp_status);
}
uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val)
@@ -73,12 +86,22 @@ uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val)
uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val)
{
- return float32_to_int64(val, &env->fp_status);
+ return float64_to_int64_round_to_zero(val, &env->fp_status);
}
uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val)
{
- return float32_to_int32(val, &env->fp_status);
+ return float32_to_int32_round_to_zero(val, &env->fp_status);
+}
+
+uint64_t HELPER(stod)(CPUOpenRISCState *env, uint32_t val)
+{
+ return float32_to_float64(val, &env->fp_status);
+}
+
+uint32_t HELPER(dtos)(CPUOpenRISCState *env, uint64_t val)
+{
+ return float64_to_float32(val, &env->fp_status);
}
#define FLOAT_CALC(name) \
@@ -125,4 +148,24 @@ target_ulong helper_float_ ## name ## _s(CPUOpenRISCState *env, \
FLOAT_CMP(le, le)
FLOAT_CMP(lt, lt)
FLOAT_CMP(eq, eq_quiet)
+FLOAT_CMP(un, unordered_quiet)
#undef FLOAT_CMP
+
+#define FLOAT_UCMP(name, expr) \
+target_ulong helper_float_ ## name ## _d(CPUOpenRISCState *env, \
+ uint64_t fdt0, uint64_t fdt1) \
+{ \
+ int r = float64_compare_quiet(fdt0, fdt1, &env->fp_status); \
+ return expr; \
+} \
+target_ulong helper_float_ ## name ## _s(CPUOpenRISCState *env, \
+ uint32_t fdt0, uint32_t fdt1) \
+{ \
+ int r = float32_compare_quiet(fdt0, fdt1, &env->fp_status); \
+ return expr; \
+}
+
+FLOAT_UCMP(ueq, r == float_relation_equal || r == float_relation_unordered)
+FLOAT_UCMP(ult, r == float_relation_less || r == float_relation_unordered)
+FLOAT_UCMP(ule, r != float_relation_greater)
+#undef FLOAT_UCMP
diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h
index 96d79a8113..d847814a28 100644
--- a/target/openrisc/helper.h
+++ b/target/openrisc/helper.h
@@ -30,6 +30,8 @@ DEF_HELPER_FLAGS_2(itofd, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_2(itofs, TCG_CALL_NO_RWG, i32, env, i32)
DEF_HELPER_FLAGS_2(ftoid, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_2(ftois, TCG_CALL_NO_RWG, i32, env, i32)
+DEF_HELPER_FLAGS_2(stod, TCG_CALL_NO_RWG, i64, env, i32)
+DEF_HELPER_FLAGS_2(dtos, TCG_CALL_NO_RWG, i32, env, i64)
DEF_HELPER_FLAGS_4(float_madd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
DEF_HELPER_FLAGS_4(float_madd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
@@ -50,6 +52,10 @@ DEF_HELPER_FLAGS_3(float_ ## op ## _d, TCG_CALL_NO_RWG, tl, env, i64, i64)
FOP_CMP(eq)
FOP_CMP(lt)
FOP_CMP(le)
+FOP_CMP(un)
+FOP_CMP(ueq)
+FOP_CMP(ule)
+FOP_CMP(ult)
#undef FOP_CMP
/* interrupt */
diff --git a/target/openrisc/insns.decode b/target/openrisc/insns.decode
index 7df81c1f22..0d6f7c29f8 100644
--- a/target/openrisc/insns.decode
+++ b/target/openrisc/insns.decode
@@ -22,6 +22,9 @@
&ab a b
&dal d a l
&ai a i
+&dab_pair d a b dp ap bp
+&ab_pair a b ap bp
+&da_pair d a dp ap
####
# System Instructions
@@ -99,6 +102,8 @@ l_maci 010011 ----- a:5 i:s16
l_movhi 000110 d:5 ----0 k:16
l_macrc 000110 d:5 ----1 00000000 00000000
+l_adrp 000010 d:5 i:s21
+
####
# Arithmetic Instructions
####
@@ -187,3 +192,43 @@ lf_sfgt_s 110010 ----- a:5 b:5 --- 00001010
lf_sfge_s 110010 ----- a:5 b:5 --- 00001011
lf_sflt_s 110010 ----- a:5 b:5 --- 00001100
lf_sfle_s 110010 ----- a:5 b:5 --- 00001101
+lf_sfueq_s 110010 ----- a:5 b:5 --- 00101000
+lf_sfuge_s 110010 ----- a:5 b:5 --- 00101011
+lf_sfugt_s 110010 ----- a:5 b:5 --- 00101010
+lf_sfule_s 110010 ----- a:5 b:5 --- 00101101
+lf_sfult_s 110010 ----- a:5 b:5 --- 00101100
+lf_sfun_s 110010 ----- a:5 b:5 --- 00101110
+
+####
+# DP Instructions
+####
+
+@dab_pair ...... d:5 a:5 b:5 dp:1 ap:1 bp:1 ........ &dab_pair
+@ab_pair ...... ..... a:5 b:5 . ap:1 bp:1 ........ &ab_pair
+@da_pair ...... d:5 a:5 ..... dp:1 ap:1 . ........ &da_pair
+
+lf_add_d 110010 ..... ..... ..... ... 00010000 @dab_pair
+lf_sub_d 110010 ..... ..... ..... ... 00010001 @dab_pair
+lf_mul_d 110010 ..... ..... ..... ... 00010010 @dab_pair
+lf_div_d 110010 ..... ..... ..... ... 00010011 @dab_pair
+lf_rem_d 110010 ..... ..... ..... ... 00010110 @dab_pair
+lf_madd_d 110010 ..... ..... ..... ... 00010111 @dab_pair
+
+lf_itof_d 110010 ..... ..... 00000 ..0 00010100 @da_pair
+lf_ftoi_d 110010 ..... ..... 00000 ..0 00010101 @da_pair
+
+lf_stod_d 110010 d:5 a:5 00000 dp:1 0 0 00110100
+lf_dtos_d 110010 d:5 a:5 00000 0 ap:1 0 00110101
+
+lf_sfeq_d 110010 00000 ..... ..... 0.. 00011000 @ab_pair
+lf_sfne_d 110010 00000 ..... ..... 0.. 00011001 @ab_pair
+lf_sfgt_d 110010 00000 ..... ..... 0.. 00011010 @ab_pair
+lf_sfge_d 110010 00000 ..... ..... 0.. 00011011 @ab_pair
+lf_sflt_d 110010 00000 ..... ..... 0.. 00011100 @ab_pair
+lf_sfle_d 110010 00000 ..... ..... 0.. 00011101 @ab_pair
+lf_sfueq_d 110010 00000 ..... ..... 0.. 00111000 @ab_pair
+lf_sfuge_d 110010 00000 ..... ..... 0.. 00111011 @ab_pair
+lf_sfugt_d 110010 00000 ..... ..... 0.. 00111010 @ab_pair
+lf_sfule_d 110010 00000 ..... ..... 0.. 00111101 @ab_pair
+lf_sfult_d 110010 00000 ..... ..... 0.. 00111100 @ab_pair
+lf_sfun_d 110010 00000 ..... ..... 0.. 00111110 @ab_pair
diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c
index 0a96404dc6..b92985d99b 100644
--- a/target/openrisc/machine.c
+++ b/target/openrisc/machine.c
@@ -121,10 +121,21 @@ static const VMStateDescription vmstate_env = {
}
};
+static int cpu_post_load(void *opaque, int version_id)
+{
+ OpenRISCCPU *cpu = opaque;
+ CPUOpenRISCState *env = &cpu->env;
+
+ /* Update env->fp_status to match env->fpcsr. */
+ cpu_set_fpcsr(env, env->fpcsr);
+ return 0;
+}
+
const VMStateDescription vmstate_openrisc_cpu = {
.name = "cpu",
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = cpu_post_load,
.fields = (VMStateField[]) {
VMSTATE_CPU(),
VMSTATE_STRUCT(env, OpenRISCCPU, 1, vmstate_env, CPUOpenRISCState),
diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c
index 1053409a04..d9fe6c5948 100644
--- a/target/openrisc/sys_helper.c
+++ b/target/openrisc/sys_helper.c
@@ -37,12 +37,10 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
CPUState *cs = env_cpu(env);
target_ulong mr;
int idx;
+#endif
switch (spr) {
- case TO_SPR(0, 0): /* VR */
- env->vr = rb;
- break;
-
+#ifndef CONFIG_USER_ONLY
case TO_SPR(0, 11): /* EVBAR */
env->evbar = rb;
break;
@@ -62,10 +60,6 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
cpu_set_sr(env, rb);
break;
- case TO_SPR(0, 18): /* PPC */
- env->ppc = rb;
- break;
-
case TO_SPR(0, 32): /* EPCR */
env->epcr = rb;
break;
@@ -187,10 +181,12 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
}
cpu_openrisc_timer_update(cpu);
break;
- default:
+#endif
+
+ case TO_SPR(0, 20): /* FPCSR */
+ cpu_set_fpcsr(env, rb);
break;
}
-#endif
}
target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
@@ -201,23 +197,31 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
OpenRISCCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
int idx;
+#endif
switch (spr) {
+#ifndef CONFIG_USER_ONLY
case TO_SPR(0, 0): /* VR */
- return env->vr & SPR_VR;
+ return env->vr;
case TO_SPR(0, 1): /* UPR */
- return env->upr; /* TT, DM, IM, UP present */
+ return env->upr;
case TO_SPR(0, 2): /* CPUCFGR */
return env->cpucfgr;
case TO_SPR(0, 3): /* DMMUCFGR */
- return env->dmmucfgr; /* 1Way, 64 entries */
+ return env->dmmucfgr;
case TO_SPR(0, 4): /* IMMUCFGR */
return env->immucfgr;
+ case TO_SPR(0, 9): /* VR2 */
+ return env->vr2;
+
+ case TO_SPR(0, 10): /* AVR */
+ return env->avr;
+
case TO_SPR(0, 11): /* EVBAR */
return env->evbar;
@@ -305,11 +309,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
case TO_SPR(10, 1): /* TTCR */
cpu_openrisc_count_update(cpu);
return cpu_openrisc_count_get(cpu);
+#endif
- default:
- break;
+ case TO_SPR(0, 20): /* FPCSR */
+ return env->fpcsr;
}
-#endif
/* for rd is passed in, if rd unchanged, just keep it back. */
return rd;
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index 4360ce4045..6addbac8d6 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -45,9 +45,14 @@ typedef struct DisasContext {
uint32_t mem_idx;
uint32_t tb_flags;
uint32_t delayed_branch;
+ uint32_t cpucfgr;
+ uint32_t avr;
/* If not -1, jmp_pc contains this value and so is a direct jump. */
target_ulong jmp_pc_imm;
+
+ /* The temporary corresponding to register 0 for this compilation. */
+ TCGv R0;
} DisasContext;
static inline bool is_user(DisasContext *dc)
@@ -63,8 +68,7 @@ static inline bool is_user(DisasContext *dc)
#include "decode.inc.c"
static TCGv cpu_sr;
-static TCGv cpu_R[32];
-static TCGv cpu_R0;
+static TCGv cpu_regs[32];
static TCGv cpu_pc;
static TCGv jmp_pc; /* l.jr/l.jalr temp pc */
static TCGv cpu_ppc;
@@ -117,12 +121,11 @@ void openrisc_translate_init(void)
offsetof(CPUOpenRISCState, mac),
"mac");
for (i = 0; i < 32; i++) {
- cpu_R[i] = tcg_global_mem_new(cpu_env,
- offsetof(CPUOpenRISCState,
- shadow_gpr[0][i]),
- regnames[i]);
+ cpu_regs[i] = tcg_global_mem_new(cpu_env,
+ offsetof(CPUOpenRISCState,
+ shadow_gpr[0][i]),
+ regnames[i]);
}
- cpu_R0 = cpu_R[0];
}
static void gen_exception(DisasContext *dc, unsigned int excp)
@@ -139,38 +142,40 @@ static void gen_illegal_exception(DisasContext *dc)
dc->base.is_jmp = DISAS_NORETURN;
}
-/* not used yet, open it when we need or64. */
-/*#ifdef TARGET_OPENRISC64
-static void check_ob64s(DisasContext *dc)
+static bool check_v1_3(DisasContext *dc)
{
- if (!(dc->flags & CPUCFGR_OB64S)) {
- gen_illegal_exception(dc);
- }
+ return dc->avr >= 0x01030000;
}
-static void check_of64s(DisasContext *dc)
+static bool check_of32s(DisasContext *dc)
{
- if (!(dc->flags & CPUCFGR_OF64S)) {
- gen_illegal_exception(dc);
- }
+ return dc->cpucfgr & CPUCFGR_OF32S;
}
-static void check_ov64s(DisasContext *dc)
+static bool check_of64a32s(DisasContext *dc)
{
- if (!(dc->flags & CPUCFGR_OV64S)) {
- gen_illegal_exception(dc);
+ return dc->cpucfgr & CPUCFGR_OF64A32S;
+}
+
+static TCGv cpu_R(DisasContext *dc, int reg)
+{
+ if (reg == 0) {
+ return dc->R0;
+ } else {
+ return cpu_regs[reg];
}
}
-#endif*/
-/* We're about to write to REG. On the off-chance that the user is
- writing to R0, re-instate the architectural register. */
-#define check_r0_write(reg) \
- do { \
- if (unlikely(reg == 0)) { \
- cpu_R[0] = cpu_R0; \
- } \
- } while (0)
+/*
+ * We're about to write to REG. On the off-chance that the user is
+ * writing to R0, re-instate the architectural register.
+ */
+static void check_r0_write(DisasContext *dc, int reg)
+{
+ if (unlikely(reg == 0)) {
+ dc->R0 = cpu_regs[0];
+ }
+}
static void gen_ove_cy(DisasContext *dc)
{
@@ -436,99 +441,99 @@ static void gen_msbu(DisasContext *dc, TCGv srca, TCGv srcb)
static bool trans_l_add(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- gen_add(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_addc(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- gen_addc(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sub(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- gen_sub(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ gen_sub(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_and(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- tcg_gen_and_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ tcg_gen_and_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_or(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- tcg_gen_or_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ tcg_gen_or_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_xor(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- tcg_gen_xor_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ tcg_gen_xor_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sll(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- tcg_gen_shl_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ tcg_gen_shl_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_srl(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- tcg_gen_shr_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ tcg_gen_shr_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sra(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- tcg_gen_sar_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ tcg_gen_sar_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_ror(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- tcg_gen_rotr_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ tcg_gen_rotr_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_exths(DisasContext *dc, arg_da *a)
{
- check_r0_write(a->d);
- tcg_gen_ext16s_tl(cpu_R[a->d], cpu_R[a->a]);
+ check_r0_write(dc, a->d);
+ tcg_gen_ext16s_tl(cpu_R(dc, a->d), cpu_R(dc, a->a));
return true;
}
static bool trans_l_extbs(DisasContext *dc, arg_da *a)
{
- check_r0_write(a->d);
- tcg_gen_ext8s_tl(cpu_R[a->d], cpu_R[a->a]);
+ check_r0_write(dc, a->d);
+ tcg_gen_ext8s_tl(cpu_R(dc, a->d), cpu_R(dc, a->a));
return true;
}
static bool trans_l_exthz(DisasContext *dc, arg_da *a)
{
- check_r0_write(a->d);
- tcg_gen_ext16u_tl(cpu_R[a->d], cpu_R[a->a]);
+ check_r0_write(dc, a->d);
+ tcg_gen_ext16u_tl(cpu_R(dc, a->d), cpu_R(dc, a->a));
return true;
}
static bool trans_l_extbz(DisasContext *dc, arg_da *a)
{
- check_r0_write(a->d);
- tcg_gen_ext8u_tl(cpu_R[a->d], cpu_R[a->a]);
+ check_r0_write(dc, a->d);
+ tcg_gen_ext8u_tl(cpu_R(dc, a->d), cpu_R(dc, a->a));
return true;
}
@@ -536,67 +541,67 @@ static bool trans_l_cmov(DisasContext *dc, arg_dab *a)
{
TCGv zero;
- check_r0_write(a->d);
+ check_r0_write(dc, a->d);
zero = tcg_const_tl(0);
- tcg_gen_movcond_tl(TCG_COND_NE, cpu_R[a->d], cpu_sr_f, zero,
- cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_movcond_tl(TCG_COND_NE, cpu_R(dc, a->d), cpu_sr_f, zero,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
tcg_temp_free(zero);
return true;
}
static bool trans_l_ff1(DisasContext *dc, arg_da *a)
{
- check_r0_write(a->d);
- tcg_gen_ctzi_tl(cpu_R[a->d], cpu_R[a->a], -1);
- tcg_gen_addi_tl(cpu_R[a->d], cpu_R[a->d], 1);
+ check_r0_write(dc, a->d);
+ tcg_gen_ctzi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), -1);
+ tcg_gen_addi_tl(cpu_R(dc, a->d), cpu_R(dc, a->d), 1);
return true;
}
static bool trans_l_fl1(DisasContext *dc, arg_da *a)
{
- check_r0_write(a->d);
- tcg_gen_clzi_tl(cpu_R[a->d], cpu_R[a->a], TARGET_LONG_BITS);
- tcg_gen_subfi_tl(cpu_R[a->d], TARGET_LONG_BITS, cpu_R[a->d]);
+ check_r0_write(dc, a->d);
+ tcg_gen_clzi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), TARGET_LONG_BITS);
+ tcg_gen_subfi_tl(cpu_R(dc, a->d), TARGET_LONG_BITS, cpu_R(dc, a->d));
return true;
}
static bool trans_l_mul(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- gen_mul(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_mulu(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- gen_mulu(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ gen_mulu(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_div(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- gen_div(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ gen_div(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_divu(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- gen_divu(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
+ check_r0_write(dc, a->d);
+ gen_divu(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_muld(DisasContext *dc, arg_ab *a)
{
- gen_muld(dc, cpu_R[a->a], cpu_R[a->b]);
+ gen_muld(dc, cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_muldu(DisasContext *dc, arg_ab *a)
{
- gen_muldu(dc, cpu_R[a->a], cpu_R[a->b]);
+ gen_muldu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
@@ -615,7 +620,7 @@ static bool trans_l_jal(DisasContext *dc, arg_l_jal *a)
target_ulong tmp_pc = dc->base.pc_next + a->n * 4;
target_ulong ret_pc = dc->base.pc_next + 8;
- tcg_gen_movi_tl(cpu_R[9], ret_pc);
+ tcg_gen_movi_tl(cpu_regs[9], ret_pc);
/* Optimize jal being used to load the PC for PIC. */
if (tmp_pc != ret_pc) {
tcg_gen_movi_tl(jmp_pc, tmp_pc);
@@ -654,15 +659,15 @@ static bool trans_l_bnf(DisasContext *dc, arg_l_bf *a)
static bool trans_l_jr(DisasContext *dc, arg_l_jr *a)
{
- tcg_gen_mov_tl(jmp_pc, cpu_R[a->b]);
+ tcg_gen_mov_tl(jmp_pc, cpu_R(dc, a->b));
dc->delayed_branch = 2;
return true;
}
static bool trans_l_jalr(DisasContext *dc, arg_l_jalr *a)
{
- tcg_gen_mov_tl(jmp_pc, cpu_R[a->b]);
- tcg_gen_movi_tl(cpu_R[9], dc->base.pc_next + 8);
+ tcg_gen_mov_tl(jmp_pc, cpu_R(dc, a->b));
+ tcg_gen_movi_tl(cpu_regs[9], dc->base.pc_next + 8);
dc->delayed_branch = 2;
return true;
}
@@ -671,24 +676,24 @@ static bool trans_l_lwa(DisasContext *dc, arg_load *a)
{
TCGv ea;
- check_r0_write(a->d);
+ check_r0_write(dc, a->d);
ea = tcg_temp_new();
- tcg_gen_addi_tl(ea, cpu_R[a->a], a->i);
- tcg_gen_qemu_ld_tl(cpu_R[a->d], ea, dc->mem_idx, MO_TEUL);
+ tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i);
+ tcg_gen_qemu_ld_tl(cpu_R(dc, a->d), ea, dc->mem_idx, MO_TEUL);
tcg_gen_mov_tl(cpu_lock_addr, ea);
- tcg_gen_mov_tl(cpu_lock_value, cpu_R[a->d]);
+ tcg_gen_mov_tl(cpu_lock_value, cpu_R(dc, a->d));
tcg_temp_free(ea);
return true;
}
-static void do_load(DisasContext *dc, arg_load *a, TCGMemOp mop)
+static void do_load(DisasContext *dc, arg_load *a, MemOp mop)
{
TCGv ea;
- check_r0_write(a->d);
+ check_r0_write(dc, a->d);
ea = tcg_temp_new();
- tcg_gen_addi_tl(ea, cpu_R[a->a], a->i);
- tcg_gen_qemu_ld_tl(cpu_R[a->d], ea, dc->mem_idx, mop);
+ tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i);
+ tcg_gen_qemu_ld_tl(cpu_R(dc, a->d), ea, dc->mem_idx, mop);
tcg_temp_free(ea);
}
@@ -734,13 +739,13 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a)
TCGLabel *lab_fail, *lab_done;
ea = tcg_temp_new();
- tcg_gen_addi_tl(ea, cpu_R[a->a], a->i);
+ tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i);
/* For TB_FLAGS_R0_0, the branch below invalidates the temporary assigned
- to cpu_R[0]. Since l.swa is quite often immediately followed by a
+ to cpu_regs[0]. Since l.swa is quite often immediately followed by a
branch, don't bother reallocating; finish the TB using the "real" R0.
This also takes care of RB input across the branch. */
- cpu_R[0] = cpu_R0;
+ dc->R0 = cpu_regs[0];
lab_fail = gen_new_label();
lab_done = gen_new_label();
@@ -749,7 +754,7 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a)
val = tcg_temp_new();
tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value,
- cpu_R[a->b], dc->mem_idx, MO_TEUL);
+ cpu_regs[a->b], dc->mem_idx, MO_TEUL);
tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, val, cpu_lock_value);
tcg_temp_free(val);
@@ -763,11 +768,11 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a)
return true;
}
-static void do_store(DisasContext *dc, arg_store *a, TCGMemOp mop)
+static void do_store(DisasContext *dc, arg_store *a, MemOp mop)
{
TCGv t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[a->a], a->i);
- tcg_gen_qemu_st_tl(cpu_R[a->b], t0, dc->mem_idx, mop);
+ tcg_gen_addi_tl(t0, cpu_R(dc, a->a), a->i);
+ tcg_gen_qemu_st_tl(cpu_R(dc, a->b), t0, dc->mem_idx, mop);
tcg_temp_free(t0);
}
@@ -794,13 +799,26 @@ static bool trans_l_nop(DisasContext *dc, arg_l_nop *a)
return true;
}
+static bool trans_l_adrp(DisasContext *dc, arg_l_adrp *a)
+{
+ if (!check_v1_3(dc)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+
+ tcg_gen_movi_i32(cpu_R(dc, a->d),
+ (dc->base.pc_next & TARGET_PAGE_MASK) +
+ ((target_long)a->i << TARGET_PAGE_BITS));
+ return true;
+}
+
static bool trans_l_addi(DisasContext *dc, arg_rri *a)
{
TCGv t0;
- check_r0_write(a->d);
+ check_r0_write(dc, a->d);
t0 = tcg_const_tl(a->i);
- gen_add(dc, cpu_R[a->d], cpu_R[a->a], t0);
+ gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0);
tcg_temp_free(t0);
return true;
}
@@ -809,9 +827,9 @@ static bool trans_l_addic(DisasContext *dc, arg_rri *a)
{
TCGv t0;
- check_r0_write(a->d);
+ check_r0_write(dc, a->d);
t0 = tcg_const_tl(a->i);
- gen_addc(dc, cpu_R[a->d], cpu_R[a->a], t0);
+ gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0);
tcg_temp_free(t0);
return true;
}
@@ -820,9 +838,9 @@ static bool trans_l_muli(DisasContext *dc, arg_rri *a)
{
TCGv t0;
- check_r0_write(a->d);
+ check_r0_write(dc, a->d);
t0 = tcg_const_tl(a->i);
- gen_mul(dc, cpu_R[a->d], cpu_R[a->a], t0);
+ gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), t0);
tcg_temp_free(t0);
return true;
}
@@ -832,42 +850,42 @@ static bool trans_l_maci(DisasContext *dc, arg_l_maci *a)
TCGv t0;
t0 = tcg_const_tl(a->i);
- gen_mac(dc, cpu_R[a->a], t0);
+ gen_mac(dc, cpu_R(dc, a->a), t0);
tcg_temp_free(t0);
return true;
}
static bool trans_l_andi(DisasContext *dc, arg_rrk *a)
{
- check_r0_write(a->d);
- tcg_gen_andi_tl(cpu_R[a->d], cpu_R[a->a], a->k);
+ check_r0_write(dc, a->d);
+ tcg_gen_andi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->k);
return true;
}
static bool trans_l_ori(DisasContext *dc, arg_rrk *a)
{
- check_r0_write(a->d);
- tcg_gen_ori_tl(cpu_R[a->d], cpu_R[a->a], a->k);
+ check_r0_write(dc, a->d);
+ tcg_gen_ori_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->k);
return true;
}
static bool trans_l_xori(DisasContext *dc, arg_rri *a)
{
- check_r0_write(a->d);
- tcg_gen_xori_tl(cpu_R[a->d], cpu_R[a->a], a->i);
+ check_r0_write(dc, a->d);
+ tcg_gen_xori_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
{
- check_r0_write(a->d);
+ check_r0_write(dc, a->d);
if (is_user(dc)) {
gen_illegal_exception(dc);
} else {
TCGv spr = tcg_temp_new();
- tcg_gen_ori_tl(spr, cpu_R[a->a], a->k);
- gen_helper_mfspr(cpu_R[a->d], cpu_env, cpu_R[a->d], spr);
+ tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
+ gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
tcg_temp_free(spr);
}
return true;
@@ -894,8 +912,8 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
dc->base.is_jmp = DISAS_EXIT;
spr = tcg_temp_new();
- tcg_gen_ori_tl(spr, cpu_R[a->a], a->k);
- gen_helper_mtspr(cpu_env, spr, cpu_R[a->b]);
+ tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
+ gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b));
tcg_temp_free(spr);
}
return true;
@@ -903,188 +921,202 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
static bool trans_l_mac(DisasContext *dc, arg_ab *a)
{
- gen_mac(dc, cpu_R[a->a], cpu_R[a->b]);
+ gen_mac(dc, cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_msb(DisasContext *dc, arg_ab *a)
{
- gen_msb(dc, cpu_R[a->a], cpu_R[a->b]);
+ gen_msb(dc, cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_macu(DisasContext *dc, arg_ab *a)
{
- gen_macu(dc, cpu_R[a->a], cpu_R[a->b]);
+ gen_macu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_msbu(DisasContext *dc, arg_ab *a)
{
- gen_msbu(dc, cpu_R[a->a], cpu_R[a->b]);
+ gen_msbu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_slli(DisasContext *dc, arg_dal *a)
{
- check_r0_write(a->d);
- tcg_gen_shli_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
+ check_r0_write(dc, a->d);
+ tcg_gen_shli_tl(cpu_R(dc, a->d), cpu_R(dc, a->a),
+ a->l & (TARGET_LONG_BITS - 1));
return true;
}
static bool trans_l_srli(DisasContext *dc, arg_dal *a)
{
- check_r0_write(a->d);
- tcg_gen_shri_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
+ check_r0_write(dc, a->d);
+ tcg_gen_shri_tl(cpu_R(dc, a->d), cpu_R(dc, a->a),
+ a->l & (TARGET_LONG_BITS - 1));
return true;
}
static bool trans_l_srai(DisasContext *dc, arg_dal *a)
{
- check_r0_write(a->d);
- tcg_gen_sari_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
+ check_r0_write(dc, a->d);
+ tcg_gen_sari_tl(cpu_R(dc, a->d), cpu_R(dc, a->a),
+ a->l & (TARGET_LONG_BITS - 1));
return true;
}
static bool trans_l_rori(DisasContext *dc, arg_dal *a)
{
- check_r0_write(a->d);
- tcg_gen_rotri_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
+ check_r0_write(dc, a->d);
+ tcg_gen_rotri_tl(cpu_R(dc, a->d), cpu_R(dc, a->a),
+ a->l & (TARGET_LONG_BITS - 1));
return true;
}
static bool trans_l_movhi(DisasContext *dc, arg_l_movhi *a)
{
- check_r0_write(a->d);
- tcg_gen_movi_tl(cpu_R[a->d], a->k << 16);
+ check_r0_write(dc, a->d);
+ tcg_gen_movi_tl(cpu_R(dc, a->d), a->k << 16);
return true;
}
static bool trans_l_macrc(DisasContext *dc, arg_l_macrc *a)
{
- check_r0_write(a->d);
- tcg_gen_trunc_i64_tl(cpu_R[a->d], cpu_mac);
+ check_r0_write(dc, a->d);
+ tcg_gen_trunc_i64_tl(cpu_R(dc, a->d), cpu_mac);
tcg_gen_movi_i64(cpu_mac, 0);
return true;
}
static bool trans_l_sfeq(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfne(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfgtu(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfgeu(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfltu(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfleu(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfgts(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfges(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sflts(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f,
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfles(DisasContext *dc, arg_ab *a)
{
- tcg_gen_setcond_tl(TCG_COND_LE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
+ tcg_gen_setcond_tl(TCG_COND_LE,
+ cpu_sr_f, cpu_R(dc, a->a), cpu_R(dc, a->b));
return true;
}
static bool trans_l_sfeqi(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sfnei(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sfgtui(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sfgeui(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sfltui(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sfleui(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sfgtsi(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sfgesi(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sfltsi(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
static bool trans_l_sflesi(DisasContext *dc, arg_ai *a)
{
- tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R[a->a], a->i);
+ tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R(dc, a->a), a->i);
return true;
}
@@ -1131,124 +1163,430 @@ static bool trans_l_rfe(DisasContext *dc, arg_l_rfe *a)
return true;
}
-static void do_fp2(DisasContext *dc, arg_da *a,
+static bool do_fp2(DisasContext *dc, arg_da *a,
void (*fn)(TCGv, TCGv_env, TCGv))
{
- check_r0_write(a->d);
- fn(cpu_R[a->d], cpu_env, cpu_R[a->a]);
+ if (!check_of32s(dc)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+ fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a));
gen_helper_update_fpcsr(cpu_env);
+ return true;
}
-static void do_fp3(DisasContext *dc, arg_dab *a,
+static bool do_fp3(DisasContext *dc, arg_dab *a,
void (*fn)(TCGv, TCGv_env, TCGv, TCGv))
{
- check_r0_write(a->d);
- fn(cpu_R[a->d], cpu_env, cpu_R[a->a], cpu_R[a->b]);
+ if (!check_of32s(dc)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+ fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b));
gen_helper_update_fpcsr(cpu_env);
+ return true;
}
-static void do_fpcmp(DisasContext *dc, arg_ab *a,
+static bool do_fpcmp(DisasContext *dc, arg_ab *a,
void (*fn)(TCGv, TCGv_env, TCGv, TCGv),
bool inv, bool swap)
{
+ if (!check_of32s(dc)) {
+ return false;
+ }
if (swap) {
- fn(cpu_sr_f, cpu_env, cpu_R[a->b], cpu_R[a->a]);
+ fn(cpu_sr_f, cpu_env, cpu_R(dc, a->b), cpu_R(dc, a->a));
} else {
- fn(cpu_sr_f, cpu_env, cpu_R[a->a], cpu_R[a->b]);
+ fn(cpu_sr_f, cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b));
}
if (inv) {
tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1);
}
gen_helper_update_fpcsr(cpu_env);
+ return true;
}
static bool trans_lf_add_s(DisasContext *dc, arg_dab *a)
{
- do_fp3(dc, a, gen_helper_float_add_s);
- return true;
+ return do_fp3(dc, a, gen_helper_float_add_s);
}
static bool trans_lf_sub_s(DisasContext *dc, arg_dab *a)
{
- do_fp3(dc, a, gen_helper_float_sub_s);
- return true;
+ return do_fp3(dc, a, gen_helper_float_sub_s);
}
static bool trans_lf_mul_s(DisasContext *dc, arg_dab *a)
{
- do_fp3(dc, a, gen_helper_float_mul_s);
- return true;
+ return do_fp3(dc, a, gen_helper_float_mul_s);
}
static bool trans_lf_div_s(DisasContext *dc, arg_dab *a)
{
- do_fp3(dc, a, gen_helper_float_div_s);
- return true;
+ return do_fp3(dc, a, gen_helper_float_div_s);
}
static bool trans_lf_rem_s(DisasContext *dc, arg_dab *a)
{
- do_fp3(dc, a, gen_helper_float_rem_s);
+ return do_fp3(dc, a, gen_helper_float_rem_s);
return true;
}
static bool trans_lf_itof_s(DisasContext *dc, arg_da *a)
{
- do_fp2(dc, a, gen_helper_itofs);
- return true;
+ return do_fp2(dc, a, gen_helper_itofs);
}
static bool trans_lf_ftoi_s(DisasContext *dc, arg_da *a)
{
- do_fp2(dc, a, gen_helper_ftois);
- return true;
+ return do_fp2(dc, a, gen_helper_ftois);
}
static bool trans_lf_madd_s(DisasContext *dc, arg_dab *a)
{
- check_r0_write(a->d);
- gen_helper_float_madd_s(cpu_R[a->d], cpu_env, cpu_R[a->d],
- cpu_R[a->a], cpu_R[a->b]);
+ if (!check_of32s(dc)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+ gen_helper_float_madd_s(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d),
+ cpu_R(dc, a->a), cpu_R(dc, a->b));
gen_helper_update_fpcsr(cpu_env);
return true;
}
static bool trans_lf_sfeq_s(DisasContext *dc, arg_ab *a)
{
- do_fpcmp(dc, a, gen_helper_float_eq_s, false, false);
- return true;
+ return do_fpcmp(dc, a, gen_helper_float_eq_s, false, false);
}
static bool trans_lf_sfne_s(DisasContext *dc, arg_ab *a)
{
- do_fpcmp(dc, a, gen_helper_float_eq_s, true, false);
- return true;
+ return do_fpcmp(dc, a, gen_helper_float_eq_s, true, false);
}
static bool trans_lf_sfgt_s(DisasContext *dc, arg_ab *a)
{
- do_fpcmp(dc, a, gen_helper_float_lt_s, false, true);
- return true;
+ return do_fpcmp(dc, a, gen_helper_float_lt_s, false, true);
}
static bool trans_lf_sfge_s(DisasContext *dc, arg_ab *a)
{
- do_fpcmp(dc, a, gen_helper_float_le_s, false, true);
- return true;
+ return do_fpcmp(dc, a, gen_helper_float_le_s, false, true);
}
static bool trans_lf_sflt_s(DisasContext *dc, arg_ab *a)
{
- do_fpcmp(dc, a, gen_helper_float_lt_s, false, false);
- return true;
+ return do_fpcmp(dc, a, gen_helper_float_lt_s, false, false);
}
static bool trans_lf_sfle_s(DisasContext *dc, arg_ab *a)
{
- do_fpcmp(dc, a, gen_helper_float_le_s, false, false);
+ return do_fpcmp(dc, a, gen_helper_float_le_s, false, false);
+}
+
+static bool trans_lf_sfueq_s(DisasContext *dc, arg_ab *a)
+{
+ if (!check_v1_3(dc)) {
+ return false;
+ }
+ return do_fpcmp(dc, a, gen_helper_float_ueq_s, false, false);
+}
+
+static bool trans_lf_sfult_s(DisasContext *dc, arg_ab *a)
+{
+ if (!check_v1_3(dc)) {
+ return false;
+ }
+ return do_fpcmp(dc, a, gen_helper_float_ult_s, false, false);
+}
+
+static bool trans_lf_sfugt_s(DisasContext *dc, arg_ab *a)
+{
+ if (!check_v1_3(dc)) {
+ return false;
+ }
+ return do_fpcmp(dc, a, gen_helper_float_ult_s, false, true);
+}
+
+static bool trans_lf_sfule_s(DisasContext *dc, arg_ab *a)
+{
+ if (!check_v1_3(dc)) {
+ return false;
+ }
+ return do_fpcmp(dc, a, gen_helper_float_ule_s, false, false);
+}
+
+static bool trans_lf_sfuge_s(DisasContext *dc, arg_ab *a)
+{
+ if (!check_v1_3(dc)) {
+ return false;
+ }
+ return do_fpcmp(dc, a, gen_helper_float_ule_s, false, true);
+}
+
+static bool trans_lf_sfun_s(DisasContext *dc, arg_ab *a)
+{
+ if (!check_v1_3(dc)) {
+ return false;
+ }
+ return do_fpcmp(dc, a, gen_helper_float_un_s, false, false);
+}
+
+static bool check_pair(DisasContext *dc, int r, int p)
+{
+ return r + 1 + p < 32;
+}
+
+static void load_pair(DisasContext *dc, TCGv_i64 t, int r, int p)
+{
+ tcg_gen_concat_i32_i64(t, cpu_R(dc, r + 1 + p), cpu_R(dc, r));
+}
+
+static void save_pair(DisasContext *dc, TCGv_i64 t, int r, int p)
+{
+ tcg_gen_extr_i64_i32(cpu_R(dc, r + 1 + p), cpu_R(dc, r), t);
+}
+
+static bool do_dp3(DisasContext *dc, arg_dab_pair *a,
+ void (*fn)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
+{
+ TCGv_i64 t0, t1;
+
+ if (!check_of64a32s(dc) ||
+ !check_pair(dc, a->a, a->ap) ||
+ !check_pair(dc, a->b, a->bp) ||
+ !check_pair(dc, a->d, a->dp)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ load_pair(dc, t0, a->a, a->ap);
+ load_pair(dc, t1, a->b, a->bp);
+ fn(t0, cpu_env, t0, t1);
+ save_pair(dc, t0, a->d, a->dp);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+
+ gen_helper_update_fpcsr(cpu_env);
+ return true;
+}
+
+static bool do_dp2(DisasContext *dc, arg_da_pair *a,
+ void (*fn)(TCGv_i64, TCGv_env, TCGv_i64))
+{
+ TCGv_i64 t0;
+
+ if (!check_of64a32s(dc) ||
+ !check_pair(dc, a->a, a->ap) ||
+ !check_pair(dc, a->d, a->dp)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+
+ t0 = tcg_temp_new_i64();
+ load_pair(dc, t0, a->a, a->ap);
+ fn(t0, cpu_env, t0);
+ save_pair(dc, t0, a->d, a->dp);
+ tcg_temp_free_i64(t0);
+
+ gen_helper_update_fpcsr(cpu_env);
return true;
}
+static bool do_dpcmp(DisasContext *dc, arg_ab_pair *a,
+ void (*fn)(TCGv, TCGv_env, TCGv_i64, TCGv_i64),
+ bool inv, bool swap)
+{
+ TCGv_i64 t0, t1;
+
+ if (!check_of64a32s(dc) ||
+ !check_pair(dc, a->a, a->ap) ||
+ !check_pair(dc, a->b, a->bp)) {
+ return false;
+ }
+
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ load_pair(dc, t0, a->a, a->ap);
+ load_pair(dc, t1, a->b, a->bp);
+ if (swap) {
+ fn(cpu_sr_f, cpu_env, t1, t0);
+ } else {
+ fn(cpu_sr_f, cpu_env, t0, t1);
+ }
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+
+ if (inv) {
+ tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1);
+ }
+ gen_helper_update_fpcsr(cpu_env);
+ return true;
+}
+
+static bool trans_lf_add_d(DisasContext *dc, arg_dab_pair *a)
+{
+ return do_dp3(dc, a, gen_helper_float_add_d);
+}
+
+static bool trans_lf_sub_d(DisasContext *dc, arg_dab_pair *a)
+{
+ return do_dp3(dc, a, gen_helper_float_sub_d);
+}
+
+static bool trans_lf_mul_d(DisasContext *dc, arg_dab_pair *a)
+{
+ return do_dp3(dc, a, gen_helper_float_mul_d);
+}
+
+static bool trans_lf_div_d(DisasContext *dc, arg_dab_pair *a)
+{
+ return do_dp3(dc, a, gen_helper_float_div_d);
+}
+
+static bool trans_lf_rem_d(DisasContext *dc, arg_dab_pair *a)
+{
+ return do_dp3(dc, a, gen_helper_float_rem_d);
+}
+
+static bool trans_lf_itof_d(DisasContext *dc, arg_da_pair *a)
+{
+ return do_dp2(dc, a, gen_helper_itofd);
+}
+
+static bool trans_lf_ftoi_d(DisasContext *dc, arg_da_pair *a)
+{
+ return do_dp2(dc, a, gen_helper_ftoid);
+}
+
+static bool trans_lf_stod_d(DisasContext *dc, arg_lf_stod_d *a)
+{
+ TCGv_i64 t0;
+
+ if (!check_of64a32s(dc) ||
+ !check_pair(dc, a->d, a->dp)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+
+ t0 = tcg_temp_new_i64();
+ gen_helper_stod(t0, cpu_env, cpu_R(dc, a->a));
+ save_pair(dc, t0, a->d, a->dp);
+ tcg_temp_free_i64(t0);
+
+ gen_helper_update_fpcsr(cpu_env);
+ return true;
+}
+
+static bool trans_lf_dtos_d(DisasContext *dc, arg_lf_dtos_d *a)
+{
+ TCGv_i64 t0;
+
+ if (!check_of64a32s(dc) ||
+ !check_pair(dc, a->a, a->ap)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+
+ t0 = tcg_temp_new_i64();
+ load_pair(dc, t0, a->a, a->ap);
+ gen_helper_dtos(cpu_R(dc, a->d), cpu_env, t0);
+ tcg_temp_free_i64(t0);
+
+ gen_helper_update_fpcsr(cpu_env);
+ return true;
+}
+
+static bool trans_lf_madd_d(DisasContext *dc, arg_dab_pair *a)
+{
+ TCGv_i64 t0, t1, t2;
+
+ if (!check_of64a32s(dc) ||
+ !check_pair(dc, a->a, a->ap) ||
+ !check_pair(dc, a->b, a->bp) ||
+ !check_pair(dc, a->d, a->dp)) {
+ return false;
+ }
+ check_r0_write(dc, a->d);
+
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ t2 = tcg_temp_new_i64();
+ load_pair(dc, t0, a->d, a->dp);
+ load_pair(dc, t1, a->a, a->ap);
+ load_pair(dc, t2, a->b, a->bp);
+ gen_helper_float_madd_d(t0, cpu_env, t0, t1, t2);
+ save_pair(dc, t0, a->d, a->dp);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
+
+ gen_helper_update_fpcsr(cpu_env);
+ return true;
+}
+
+static bool trans_lf_sfeq_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_eq_d, false, false);
+}
+
+static bool trans_lf_sfne_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_eq_d, true, false);
+}
+
+static bool trans_lf_sfgt_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_lt_d, false, true);
+}
+
+static bool trans_lf_sfge_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_le_d, false, true);
+}
+
+static bool trans_lf_sflt_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_lt_d, false, false);
+}
+
+static bool trans_lf_sfle_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_le_d, false, false);
+}
+
+static bool trans_lf_sfueq_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_ueq_d, false, false);
+}
+
+static bool trans_lf_sfule_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_ule_d, false, false);
+}
+
+static bool trans_lf_sfuge_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_ule_d, false, true);
+}
+
+static bool trans_lf_sfult_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_ult_d, false, false);
+}
+
+static bool trans_lf_sfugt_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_ult_d, false, true);
+}
+
+static bool trans_lf_sfun_d(DisasContext *dc, arg_ab_pair *a)
+{
+ return do_dpcmp(dc, a, gen_helper_float_un_d, false, false);
+}
+
static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
{
DisasContext *dc = container_of(dcb, DisasContext, base);
@@ -1258,6 +1596,8 @@ static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
dc->mem_idx = cpu_mmu_index(env, false);
dc->tb_flags = dc->base.tb->flags;
dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0;
+ dc->cpucfgr = env->cpucfgr;
+ dc->avr = env->avr;
dc->jmp_pc_imm = -1;
bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
@@ -1271,9 +1611,9 @@ static void openrisc_tr_tb_start(DisasContextBase *db, CPUState *cs)
/* Allow the TCG optimizer to see that R0 == 0,
when it's true, which is the common case. */
if (dc->tb_flags & TB_FLAGS_R0_0) {
- cpu_R[0] = tcg_const_tl(0);
+ dc->R0 = tcg_const_tl(0);
} else {
- cpu_R[0] = cpu_R0;
+ dc->R0 = cpu_regs[0];
}
}
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index 7ffdb0a706..e499575dc8 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -191,6 +191,7 @@ typedef struct PowerPCCPUClass {
const PPCHash64Options *hash64_opts;
struct ppc_radix_page_info *radix_page_info;
uint32_t lrg_decr_bits;
+ int n_host_threads;
void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env);
int (*handle_mmu_fault)(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx);
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 07bc9051b0..4b1a2e6178 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -630,19 +630,15 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr)
{
CPUState *cs = env_cpu(env);
int status = get_float_exception_flags(&env->fp_status);
- bool inexact_happened = false;
if (status & float_flag_overflow) {
float_overflow_excp(env);
} else if (status & float_flag_underflow) {
float_underflow_excp(env);
- } else if (status & float_flag_inexact) {
- float_inexact_excp(env);
- inexact_happened = true;
}
-
- /* if the inexact flag was not set */
- if (inexact_happened == false) {
+ if (status & float_flag_inexact) {
+ float_inexact_excp(env);
+ } else {
env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */
}
@@ -2887,12 +2883,40 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode,
uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
{
- uint64_t result;
+ uint64_t result, sign, exp, frac;
float_status tstat = env->fp_status;
set_float_exception_flags(0, &tstat);
- result = (uint64_t)float64_to_float32(xb, &tstat);
+ sign = extract64(xb, 63, 1);
+ exp = extract64(xb, 52, 11);
+ frac = extract64(xb, 0, 52) | 0x10000000000000ULL;
+
+ if (unlikely(exp == 0 && extract64(frac, 0, 52) != 0)) {
+ /* DP denormal operand. */
+ /* Exponent override to DP min exp. */
+ exp = 1;
+ /* Implicit bit override to 0. */
+ frac = deposit64(frac, 53, 1, 0);
+ }
+
+ if (unlikely(exp < 897 && frac != 0)) {
+ /* SP tiny operand. */
+ if (897 - exp > 63) {
+ frac = 0;
+ } else {
+ /* Denormalize until exp = SP min exp. */
+ frac >>= (897 - exp);
+ }
+ /* Exponent override to SP min exp - 1. */
+ exp = 896;
+ }
+
+ result = sign << 31;
+ result |= extract64(exp, 10, 1) << 30;
+ result |= extract64(exp, 0, 7) << 23;
+ result |= extract64(frac, 29, 23);
+
/* hardware replicates result to both words of the doubleword result. */
return (result << 32) | result;
}
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 0cf3f979e2..adb8fd516f 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -163,7 +163,7 @@ struct DisasContext {
int mem_idx;
int access_type;
/* Translation flags */
- TCGMemOp default_tcg_memop_mask;
+ MemOp default_tcg_memop_mask;
#if defined(TARGET_PPC64)
bool sf_mode;
bool has_cfar;
@@ -3142,7 +3142,7 @@ static void gen_isync(DisasContext *ctx)
#define MEMOP_GET_SIZE(x) (1 << ((x) & MO_SIZE))
-static void gen_load_locked(DisasContext *ctx, TCGMemOp memop)
+static void gen_load_locked(DisasContext *ctx, MemOp memop)
{
TCGv gpr = cpu_gpr[rD(ctx->opcode)];
TCGv t0 = tcg_temp_new();
@@ -3167,7 +3167,7 @@ LARX(lbarx, DEF_MEMOP(MO_UB))
LARX(lharx, DEF_MEMOP(MO_UW))
LARX(lwarx, DEF_MEMOP(MO_UL))
-static void gen_fetch_inc_conditional(DisasContext *ctx, TCGMemOp memop,
+static void gen_fetch_inc_conditional(DisasContext *ctx, MemOp memop,
TCGv EA, TCGCond cond, int addend)
{
TCGv t = tcg_temp_new();
@@ -3193,7 +3193,7 @@ static void gen_fetch_inc_conditional(DisasContext *ctx, TCGMemOp memop,
tcg_temp_free(u);
}
-static void gen_ld_atomic(DisasContext *ctx, TCGMemOp memop)
+static void gen_ld_atomic(DisasContext *ctx, MemOp memop)
{
uint32_t gpr_FC = FC(ctx->opcode);
TCGv EA = tcg_temp_new();
@@ -3306,7 +3306,7 @@ static void gen_ldat(DisasContext *ctx)
}
#endif
-static void gen_st_atomic(DisasContext *ctx, TCGMemOp memop)
+static void gen_st_atomic(DisasContext *ctx, MemOp memop)
{
uint32_t gpr_FC = FC(ctx->opcode);
TCGv EA = tcg_temp_new();
@@ -3389,7 +3389,7 @@ static void gen_stdat(DisasContext *ctx)
}
#endif
-static void gen_conditional_store(DisasContext *ctx, TCGMemOp memop)
+static void gen_conditional_store(DisasContext *ctx, MemOp memop)
{
TCGLabel *l1 = gen_new_label();
TCGLabel *l2 = gen_new_label();
diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c
index 0d71c10428..2472a5217a 100644
--- a/target/ppc/translate/vmx-impl.inc.c
+++ b/target/ppc/translate/vmx-impl.inc.c
@@ -350,6 +350,28 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
} \
}
+/*
+ * We use this macro if one instruction is realized with direct
+ * translation, and second one with helper.
+ */
+#define GEN_VXFORM_TRANS_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)\
+static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
+{ \
+ if ((Rc(ctx->opcode) == 0) && \
+ ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ trans_##name0(ctx); \
+ } else if ((Rc(ctx->opcode) == 1) && \
+ ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
+ gen_##name1(ctx); \
+ } else { \
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \
+ } \
+}
+
/* Adds support to provide invalid mask */
#define GEN_VXFORM_DUAL_EXT(name0, flg0, flg2_0, inval0, \
name1, flg1, flg2_1, inval1) \
@@ -431,20 +453,13 @@ GEN_VXFORM(vmrglb, 6, 4);
GEN_VXFORM(vmrglh, 6, 5);
GEN_VXFORM(vmrglw, 6, 6);
-static void gen_vmrgew(DisasContext *ctx)
+static void trans_vmrgew(DisasContext *ctx)
{
- TCGv_i64 tmp;
- TCGv_i64 avr;
- int VT, VA, VB;
- if (unlikely(!ctx->altivec_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VPU);
- return;
- }
- VT = rD(ctx->opcode);
- VA = rA(ctx->opcode);
- VB = rB(ctx->opcode);
- tmp = tcg_temp_new_i64();
- avr = tcg_temp_new_i64();
+ int VT = rD(ctx->opcode);
+ int VA = rA(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ TCGv_i64 avr = tcg_temp_new_i64();
get_avr64(avr, VB, true);
tcg_gen_shri_i64(tmp, avr, 32);
@@ -462,21 +477,14 @@ static void gen_vmrgew(DisasContext *ctx)
tcg_temp_free_i64(avr);
}
-static void gen_vmrgow(DisasContext *ctx)
+static void trans_vmrgow(DisasContext *ctx)
{
- TCGv_i64 t0, t1;
- TCGv_i64 avr;
- int VT, VA, VB;
- if (unlikely(!ctx->altivec_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VPU);
- return;
- }
- VT = rD(ctx->opcode);
- VA = rA(ctx->opcode);
- VB = rB(ctx->opcode);
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
- avr = tcg_temp_new_i64();
+ int VT = rD(ctx->opcode);
+ int VA = rA(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 avr = tcg_temp_new_i64();
get_avr64(t0, VB, true);
get_avr64(t1, VA, true);
@@ -936,14 +944,14 @@ GEN_VXFORM_ENV(vminfp, 5, 17);
GEN_VXFORM_HETRO(vextublx, 6, 24)
GEN_VXFORM_HETRO(vextuhlx, 6, 25)
GEN_VXFORM_HETRO(vextuwlx, 6, 26)
-GEN_VXFORM_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207,
+GEN_VXFORM_TRANS_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207,
vextuwlx, PPC_NONE, PPC2_ISA300)
GEN_VXFORM_HETRO(vextubrx, 6, 28)
GEN_VXFORM_HETRO(vextuhrx, 6, 29)
GEN_VXFORM_HETRO(vextuwrx, 6, 30)
GEN_VXFORM_TRANS(lvsl, 6, 31)
GEN_VXFORM_TRANS(lvsr, 6, 32)
-GEN_VXFORM_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, \
+GEN_VXFORM_TRANS_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207,
vextuwrx, PPC_NONE, PPC2_ISA300)
#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \
diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c
index 3922686ad6..8287e272f5 100644
--- a/target/ppc/translate/vsx-impl.inc.c
+++ b/target/ppc/translate/vsx-impl.inc.c
@@ -1308,7 +1308,7 @@ static void gen_##name(DisasContext *ctx) \
} \
xt = gen_vsr_ptr(xT(ctx->opcode)); \
xa = gen_vsr_ptr(xA(ctx->opcode)); \
- if (ctx->opcode & PPC_BIT(25)) { \
+ if (ctx->opcode & PPC_BIT32(25)) { \
/* \
* AxT + B \
*/ \
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index 4a21ed7289..0fb11c7ac6 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -8770,6 +8770,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->hash64_opts = &ppc_hash64_opts_POWER7;
pcc->lrg_decr_bits = 32;
+ pcc->n_host_threads = 8;
#endif
pcc->excp_model = POWERPC_EXCP_POWER8;
pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
@@ -8981,6 +8982,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
pcc->hash64_opts = &ppc_hash64_opts_POWER7;
pcc->radix_page_info = &POWER9_radix_page_info;
pcc->lrg_decr_bits = 56;
+ pcc->n_host_threads = 4;
#endif
pcc->excp_model = POWERPC_EXCP_POWER9;
pcc->bus_model = PPC_FLAGS_INPUT_POWER9;
@@ -10461,6 +10463,10 @@ static void ppc_cpu_reset(CPUState *s)
s->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
+ /* tininess for underflow is detected before rounding */
+ set_float_detect_tininess(float_tininess_before_rounding,
+ &env->fp_status);
+
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
ppc_spr_t *spr = &env->spr_cb[i];
diff --git a/target/riscv/insn_trans/trans_rva.inc.c b/target/riscv/insn_trans/trans_rva.inc.c
index fadd88849e..be8a9f06dd 100644
--- a/target/riscv/insn_trans/trans_rva.inc.c
+++ b/target/riscv/insn_trans/trans_rva.inc.c
@@ -18,7 +18,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
-static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, TCGMemOp mop)
+static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
{
TCGv src1 = tcg_temp_new();
/* Put addr in load_res, data in load_val. */
@@ -37,7 +37,7 @@ static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, TCGMemOp mop)
return true;
}
-static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop)
+static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
{
TCGv src1 = tcg_temp_new();
TCGv src2 = tcg_temp_new();
@@ -82,8 +82,8 @@ static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop)
}
static bool gen_amo(DisasContext *ctx, arg_atomic *a,
- void(*func)(TCGv, TCGv, TCGv, TCGArg, TCGMemOp),
- TCGMemOp mop)
+ void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp),
+ MemOp mop)
{
TCGv src1 = tcg_temp_new();
TCGv src2 = tcg_temp_new();
diff --git a/target/riscv/insn_trans/trans_rvi.inc.c b/target/riscv/insn_trans/trans_rvi.inc.c
index 1af795e05d..d04ca0394c 100644
--- a/target/riscv/insn_trans/trans_rvi.inc.c
+++ b/target/riscv/insn_trans/trans_rvi.inc.c
@@ -135,7 +135,7 @@ static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
return gen_branch(ctx, a, TCG_COND_GEU);
}
-static bool gen_load(DisasContext *ctx, arg_lb *a, TCGMemOp memop)
+static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
{
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
@@ -174,7 +174,7 @@ static bool trans_lhu(DisasContext *ctx, arg_lhu *a)
return gen_load(ctx, a, MO_TEUW);
}
-static bool gen_store(DisasContext *ctx, arg_sb *a, TCGMemOp memop)
+static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
{
TCGv t0 = tcg_temp_new();
TCGv dat = tcg_temp_new();
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c
index 91ba2e03d9..29fcce426e 100644
--- a/target/s390x/mem_helper.c
+++ b/target/s390x/mem_helper.c
@@ -1443,9 +1443,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
}
/* Sanity check writability of the store address. */
-#ifndef CONFIG_USER_ONLY
- probe_write(env, a2, 0, mem_idx, ra);
-#endif
+ probe_write(env, a2, 1 << sc, mem_idx, ra);
/*
* Note that the compare-and-swap is atomic, and the store is atomic,
@@ -2615,22 +2613,15 @@ uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
uintptr_t ra)
{
-#ifdef CONFIG_USER_ONLY
- if (!h2g_valid(addr) || !h2g_valid(addr + len - 1) ||
- page_check_range(addr, len, PAGE_WRITE) < 0) {
- s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
- }
-#else
/* test the actual access, not just any access to the page due to LAP */
while (len) {
- const uint64_t pagelen = -(addr | -TARGET_PAGE_MASK);
+ const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
const uint64_t curlen = MIN(pagelen, len);
probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
addr = wrap_address(env, addr + curlen);
len -= curlen;
}
-#endif
}
void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index ac0d8b6410..2927247c82 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -152,7 +152,7 @@ static inline int vec_full_reg_offset(uint8_t reg)
return offsetof(CPUS390XState, vregs[reg][0]);
}
-static inline int vec_reg_offset(uint8_t reg, uint8_t enr, TCGMemOp es)
+static inline int vec_reg_offset(uint8_t reg, uint8_t enr, MemOp es)
{
/* Convert element size (es) - e.g. MO_8 - to bytes */
const uint8_t bytes = 1 << es;
@@ -2262,7 +2262,7 @@ static DisasJumpType op_csst(DisasContext *s, DisasOps *o)
#ifndef CONFIG_USER_ONLY
static DisasJumpType op_csp(DisasContext *s, DisasOps *o)
{
- TCGMemOp mop = s->insn->data;
+ MemOp mop = s->insn->data;
TCGv_i64 addr, old, cc;
TCGLabel *lab = gen_new_label();
@@ -3228,7 +3228,7 @@ static DisasJumpType op_lm64(DisasContext *s, DisasOps *o)
static DisasJumpType op_lpd(DisasContext *s, DisasOps *o)
{
TCGv_i64 a1, a2;
- TCGMemOp mop = s->insn->data;
+ MemOp mop = s->insn->data;
/* In a parallel context, stop the world and single step. */
if (tb_cflags(s->base.tb) & CF_PARALLEL) {
diff --git a/target/s390x/translate_vx.inc.c b/target/s390x/translate_vx.inc.c
index 0caddb3958..5ce7bfb0af 100644
--- a/target/s390x/translate_vx.inc.c
+++ b/target/s390x/translate_vx.inc.c
@@ -57,13 +57,13 @@
#define FPF_LONG 3
#define FPF_EXT 4
-static inline bool valid_vec_element(uint8_t enr, TCGMemOp es)
+static inline bool valid_vec_element(uint8_t enr, MemOp es)
{
return !(enr & ~(NUM_VEC_ELEMENTS(es) - 1));
}
static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr,
- TCGMemOp memop)
+ MemOp memop)
{
const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
@@ -96,7 +96,7 @@ static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr,
}
static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
- TCGMemOp memop)
+ MemOp memop)
{
const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
@@ -123,7 +123,7 @@ static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
}
static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
- TCGMemOp memop)
+ MemOp memop)
{
const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
@@ -146,7 +146,7 @@ static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
}
static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr,
- TCGMemOp memop)
+ MemOp memop)
{
const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 694d7139cf..490e14dfcf 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -275,6 +275,7 @@ enum {
#define TTE_VALID_BIT (1ULL << 63)
#define TTE_NFO_BIT (1ULL << 60)
+#define TTE_IE_BIT (1ULL << 59)
#define TTE_USED_BIT (1ULL << 41)
#define TTE_LOCKED_BIT (1ULL << 6)
#define TTE_SIDEEFFECT_BIT (1ULL << 3)
@@ -291,6 +292,7 @@ enum {
#define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT)
#define TTE_IS_NFO(tte) ((tte) & TTE_NFO_BIT)
+#define TTE_IS_IE(tte) ((tte) & TTE_IE_BIT)
#define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT)
#define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT)
#define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT)
diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c
index cbd1e91179..77dc86ac5c 100644
--- a/target/sparc/mmu_helper.c
+++ b/target/sparc/mmu_helper.c
@@ -88,7 +88,7 @@ static const int perm_table[2][8] = {
};
static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
- int *prot, int *access_index,
+ int *prot, int *access_index, MemTxAttrs *attrs,
target_ulong address, int rw, int mmu_idx,
target_ulong *page_size)
{
@@ -219,6 +219,7 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
target_ulong vaddr;
target_ulong page_size;
int error_code = 0, prot, access_index;
+ MemTxAttrs attrs = {};
/*
* TODO: If we ever need tlb_vaddr_to_host for this target,
@@ -229,7 +230,7 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
assert(!probe);
address &= TARGET_PAGE_MASK;
- error_code = get_physical_address(env, &paddr, &prot, &access_index,
+ error_code = get_physical_address(env, &paddr, &prot, &access_index, &attrs,
address, access_type,
mmu_idx, &page_size);
vaddr = address;
@@ -490,8 +491,8 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
return 0;
}
-static int get_physical_address_data(CPUSPARCState *env,
- hwaddr *physical, int *prot,
+static int get_physical_address_data(CPUSPARCState *env, hwaddr *physical,
+ int *prot, MemTxAttrs *attrs,
target_ulong address, int rw, int mmu_idx)
{
CPUState *cs = env_cpu(env);
@@ -536,6 +537,10 @@ static int get_physical_address_data(CPUSPARCState *env,
if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
int do_fault = 0;
+ if (TTE_IS_IE(env->dtlb[i].tte)) {
+ attrs->byte_swap = true;
+ }
+
/* access ok? */
/* multiple bits in SFSR.FT may be set on TT_DFAULT */
if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
@@ -608,8 +613,8 @@ static int get_physical_address_data(CPUSPARCState *env,
return 1;
}
-static int get_physical_address_code(CPUSPARCState *env,
- hwaddr *physical, int *prot,
+static int get_physical_address_code(CPUSPARCState *env, hwaddr *physical,
+ int *prot, MemTxAttrs *attrs,
target_ulong address, int mmu_idx)
{
CPUState *cs = env_cpu(env);
@@ -686,7 +691,7 @@ static int get_physical_address_code(CPUSPARCState *env,
}
static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
- int *prot, int *access_index,
+ int *prot, int *access_index, MemTxAttrs *attrs,
target_ulong address, int rw, int mmu_idx,
target_ulong *page_size)
{
@@ -716,11 +721,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
}
if (rw == 2) {
- return get_physical_address_code(env, physical, prot, address,
+ return get_physical_address_code(env, physical, prot, attrs, address,
mmu_idx);
} else {
- return get_physical_address_data(env, physical, prot, address, rw,
- mmu_idx);
+ return get_physical_address_data(env, physical, prot, attrs, address,
+ rw, mmu_idx);
}
}
@@ -734,10 +739,11 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
target_ulong vaddr;
hwaddr paddr;
target_ulong page_size;
+ MemTxAttrs attrs = {};
int error_code = 0, prot, access_index;
address &= TARGET_PAGE_MASK;
- error_code = get_physical_address(env, &paddr, &prot, &access_index,
+ error_code = get_physical_address(env, &paddr, &prot, &access_index, &attrs,
address, access_type,
mmu_idx, &page_size);
if (likely(error_code == 0)) {
@@ -747,7 +753,8 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
env->dmmu.mmu_primary_context,
env->dmmu.mmu_secondary_context);
- tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
+ tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx,
+ page_size);
return true;
}
if (probe) {
@@ -789,7 +796,7 @@ void dump_mmu(CPUSPARCState *env)
}
if (TTE_IS_VALID(env->dtlb[i].tte)) {
qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx"
- ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
+ ", %s, %s, %s, %s, ie %s, ctx %" PRId64 " %s\n",
i,
env->dtlb[i].tag & (uint64_t)~0x1fffULL,
TTE_PA(env->dtlb[i].tte),
@@ -798,6 +805,8 @@ void dump_mmu(CPUSPARCState *env)
TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
TTE_IS_LOCKED(env->dtlb[i].tte) ?
"locked" : "unlocked",
+ TTE_IS_IE(env->dtlb[i].tte) ?
+ "yes" : "no",
env->dtlb[i].tag & (uint64_t)0x1fffULL,
TTE_IS_GLOBAL(env->dtlb[i].tte) ?
"global" : "local");
@@ -849,9 +858,10 @@ static int cpu_sparc_get_phys_page(CPUSPARCState *env, hwaddr *phys,
{
target_ulong page_size;
int prot, access_index;
+ MemTxAttrs attrs = {};
- return get_physical_address(env, phys, &prot, &access_index, addr, rw,
- mmu_idx, &page_size);
+ return get_physical_address(env, phys, &prot, &access_index, &attrs, addr,
+ rw, mmu_idx, &page_size);
}
#if defined(TARGET_SPARC64)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 02c16128c8..c68bf4a2e4 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -2019,7 +2019,7 @@ static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
}
static void gen_swap(DisasContext *dc, TCGv dst, TCGv src,
- TCGv addr, int mmu_idx, TCGMemOp memop)
+ TCGv addr, int mmu_idx, MemOp memop)
{
gen_address_mask(dc, addr);
tcg_gen_atomic_xchg_tl(dst, addr, src, mmu_idx, memop);
@@ -2050,10 +2050,10 @@ typedef struct {
ASIType type;
int asi;
int mem_idx;
- TCGMemOp memop;
+ MemOp memop;
} DisasASI;
-static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
+static DisasASI get_asi(DisasContext *dc, int insn, MemOp memop)
{
int asi = GET_FIELD(insn, 19, 26);
ASIType type = GET_ASI_HELPER;
@@ -2267,7 +2267,7 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
}
static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr,
- int insn, TCGMemOp memop)
+ int insn, MemOp memop)
{
DisasASI da = get_asi(dc, insn, memop);
@@ -2305,7 +2305,7 @@ static void gen_ld_asi(DisasContext *dc, TCGv dst, TCGv addr,
}
static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr,
- int insn, TCGMemOp memop)
+ int insn, MemOp memop)
{
DisasASI da = get_asi(dc, insn, memop);
@@ -2511,7 +2511,7 @@ static void gen_ldf_asi(DisasContext *dc, TCGv addr,
case GET_ASI_BLOCK:
/* Valid for lddfa on aligned registers only. */
if (size == 8 && (rd & 7) == 0) {
- TCGMemOp memop;
+ MemOp memop;
TCGv eight;
int i;
@@ -2625,7 +2625,7 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr,
case GET_ASI_BLOCK:
/* Valid for stdfa on aligned registers only. */
if (size == 8 && (rd & 7) == 0) {
- TCGMemOp memop;
+ MemOp memop;
TCGv eight;
int i;
diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c
index c46a4ab151..68dd4aa2d8 100644
--- a/target/tilegx/translate.c
+++ b/target/tilegx/translate.c
@@ -290,7 +290,7 @@ static void gen_cmul2(TCGv tdest, TCGv tsrca, TCGv tsrcb, int sh, int rd)
}
static TileExcp gen_st_opcode(DisasContext *dc, unsigned dest, unsigned srca,
- unsigned srcb, TCGMemOp memop, const char *name)
+ unsigned srcb, MemOp memop, const char *name)
{
if (dest) {
return TILEGX_EXCP_OPCODE_UNKNOWN;
@@ -305,7 +305,7 @@ static TileExcp gen_st_opcode(DisasContext *dc, unsigned dest, unsigned srca,
}
static TileExcp gen_st_add_opcode(DisasContext *dc, unsigned srca, unsigned srcb,
- int imm, TCGMemOp memop, const char *name)
+ int imm, MemOp memop, const char *name)
{
TCGv tsrca = load_gr(dc, srca);
TCGv tsrcb = load_gr(dc, srcb);
@@ -496,7 +496,7 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
{
TCGv tdest, tsrca;
const char *mnemonic;
- TCGMemOp memop;
+ MemOp memop;
TileExcp ret = TILEGX_EXCP_NONE;
bool prefetch_nofault = false;
@@ -1478,7 +1478,7 @@ static TileExcp gen_rri_opcode(DisasContext *dc, unsigned opext,
TCGv tsrca = load_gr(dc, srca);
bool prefetch_nofault = false;
const char *mnemonic;
- TCGMemOp memop;
+ MemOp memop;
int i2, i3;
TCGv t0;
@@ -2106,7 +2106,7 @@ static TileExcp decode_y2(DisasContext *dc, tilegx_bundle_bits bundle)
unsigned srca = get_SrcA_Y2(bundle);
unsigned srcbdest = get_SrcBDest_Y2(bundle);
const char *mnemonic;
- TCGMemOp memop;
+ MemOp memop;
bool prefetch_nofault = false;
switch (OEY2(opc, mode)) {
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
index 4f10407477..c574638c9f 100644
--- a/target/tricore/translate.c
+++ b/target/tricore/translate.c
@@ -219,7 +219,7 @@ static inline void generate_trap(DisasContext *ctx, int class, int tin);
/* Functions for load/save to/from memory */
static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2,
- int16_t con, TCGMemOp mop)
+ int16_t con, MemOp mop)
{
TCGv temp = tcg_temp_new();
tcg_gen_addi_tl(temp, r2, con);
@@ -228,7 +228,7 @@ static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2,
}
static inline void gen_offset_st(DisasContext *ctx, TCGv r1, TCGv r2,
- int16_t con, TCGMemOp mop)
+ int16_t con, MemOp mop)
{
TCGv temp = tcg_temp_new();
tcg_gen_addi_tl(temp, r2, con);
@@ -276,7 +276,7 @@ static void gen_offset_ld_2regs(TCGv rh, TCGv rl, TCGv base, int16_t con,
}
static void gen_st_preincr(DisasContext *ctx, TCGv r1, TCGv r2, int16_t off,
- TCGMemOp mop)
+ MemOp mop)
{
TCGv temp = tcg_temp_new();
tcg_gen_addi_tl(temp, r2, off);
@@ -286,7 +286,7 @@ static void gen_st_preincr(DisasContext *ctx, TCGv r1, TCGv r2, int16_t off,
}
static void gen_ld_preincr(DisasContext *ctx, TCGv r1, TCGv r2, int16_t off,
- TCGMemOp mop)
+ MemOp mop)
{
TCGv temp = tcg_temp_new();
tcg_gen_addi_tl(temp, r2, off);
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index 76db1741a7..c65dcf9dd7 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -53,6 +53,20 @@ static bool xtensa_cpu_has_work(CPUState *cs)
#endif
}
+#ifdef CONFIG_USER_ONLY
+static bool abi_call0;
+
+void xtensa_set_abi_call0(void)
+{
+ abi_call0 = true;
+}
+
+bool xtensa_abi_call0(void)
+{
+ return abi_call0;
+}
+#endif
+
/* CPUClass::reset() */
static void xtensa_cpu_reset(CPUState *s)
{
@@ -70,10 +84,12 @@ static void xtensa_cpu_reset(CPUState *s)
XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
env->pending_irq_level = 0;
#else
- env->sregs[PS] =
- (xtensa_option_enabled(env->config,
- XTENSA_OPTION_WINDOWED_REGISTER) ? PS_WOE : 0) |
- PS_UM | (3 << PS_RING_SHIFT);
+ env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT);
+ if (xtensa_option_enabled(env->config,
+ XTENSA_OPTION_WINDOWED_REGISTER) &&
+ !xtensa_abi_call0()) {
+ env->sregs[PS] |= PS_WOE;
+ }
#endif
env->sregs[VECBASE] = env->config->vecbase;
env->sregs[IBREAKENABLE] = 0;
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 0459243e6b..b363ffcf10 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -673,6 +673,9 @@ static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env)
{
return env->system_er;
}
+#else
+void xtensa_set_abi_call0(void);
+bool xtensa_abi_call0(void);
#endif
static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env)
diff --git a/tcg/README b/tcg/README
index 21fcdf737f..bfa2e4ed24 100644
--- a/tcg/README
+++ b/tcg/README
@@ -101,7 +101,7 @@ This can be overridden using the following function modifiers:
canonical locations before calling the helper.
- TCG_CALL_NO_WRITE_GLOBALS means that the helper does not modify any globals.
They will only be saved to their canonical location before calling helpers,
- but they won't be reloaded afterwise.
+ but they won't be reloaded afterwards.
- TCG_CALL_NO_SIDE_EFFECTS means that the call to the function is removed if
the return value is not used.
@@ -512,7 +512,7 @@ Both t0 and t1 may be split into little-endian ordered pairs of registers
if dealing with 64-bit quantities on a 32-bit host.
The memidx selects the qemu tlb index to use (e.g. user or kernel access).
-The flags are the TCGMemOp bits, selecting the sign, width, and endianness
+The flags are the MemOp bits, selecting the sign, width, and endianness
of the memory access.
For a 32-bit host, qemu_ld/st_i64 is guaranteed to only be used with a
diff --git a/tcg/aarch64/tcg-target.inc.c b/tcg/aarch64/tcg-target.inc.c
index 0713448bf5..3f921015d3 100644
--- a/tcg/aarch64/tcg-target.inc.c
+++ b/tcg/aarch64/tcg-target.inc.c
@@ -1423,7 +1423,7 @@ static inline void tcg_out_rev16(TCGContext *s, TCGReg rd, TCGReg rn)
tcg_out_insn(s, 3507, REV16, TCG_TYPE_I32, rd, rn);
}
-static inline void tcg_out_sxt(TCGContext *s, TCGType ext, TCGMemOp s_bits,
+static inline void tcg_out_sxt(TCGContext *s, TCGType ext, MemOp s_bits,
TCGReg rd, TCGReg rn)
{
/* Using ALIASes SXTB, SXTH, SXTW, of SBFM Xd, Xn, #0, #7|15|31 */
@@ -1431,7 +1431,7 @@ static inline void tcg_out_sxt(TCGContext *s, TCGType ext, TCGMemOp s_bits,
tcg_out_sbfm(s, ext, rd, rn, 0, bits);
}
-static inline void tcg_out_uxt(TCGContext *s, TCGMemOp s_bits,
+static inline void tcg_out_uxt(TCGContext *s, MemOp s_bits,
TCGReg rd, TCGReg rn)
{
/* Using ALIASes UXTB, UXTH of UBFM Wd, Wn, #0, #7|15 */
@@ -1580,8 +1580,8 @@ static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target)
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
{
TCGMemOpIdx oi = lb->oi;
- TCGMemOp opc = get_memop(oi);
- TCGMemOp size = opc & MO_SIZE;
+ MemOp opc = get_memop(oi);
+ MemOp size = opc & MO_SIZE;
if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
return false;
@@ -1605,8 +1605,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
{
TCGMemOpIdx oi = lb->oi;
- TCGMemOp opc = get_memop(oi);
- TCGMemOp size = opc & MO_SIZE;
+ MemOp opc = get_memop(oi);
+ MemOp size = opc & MO_SIZE;
if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
return false;
@@ -1649,7 +1649,7 @@ QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 8);
slow path for the failure case, which will be patched later when finalizing
the slow path. Generated code returns the host addend in X1,
clobbers X0,X2,X3,TMP. */
-static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc,
+static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
tcg_insn_unit **label_ptr, int mem_index,
bool is_read)
{
@@ -1709,11 +1709,11 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc,
#endif /* CONFIG_SOFTMMU */
-static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp memop, TCGType ext,
+static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, TCGType ext,
TCGReg data_r, TCGReg addr_r,
TCGType otype, TCGReg off_r)
{
- const TCGMemOp bswap = memop & MO_BSWAP;
+ const MemOp bswap = memop & MO_BSWAP;
switch (memop & MO_SSIZE) {
case MO_UB:
@@ -1765,11 +1765,11 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp memop, TCGType ext,
}
}
-static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp memop,
+static void tcg_out_qemu_st_direct(TCGContext *s, MemOp memop,
TCGReg data_r, TCGReg addr_r,
TCGType otype, TCGReg off_r)
{
- const TCGMemOp bswap = memop & MO_BSWAP;
+ const MemOp bswap = memop & MO_BSWAP;
switch (memop & MO_SIZE) {
case MO_8:
@@ -1804,7 +1804,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp memop,
static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
TCGMemOpIdx oi, TCGType ext)
{
- TCGMemOp memop = get_memop(oi);
+ MemOp memop = get_memop(oi);
const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
#ifdef CONFIG_SOFTMMU
unsigned mem_index = get_mmuidx(oi);
@@ -1829,7 +1829,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
TCGMemOpIdx oi)
{
- TCGMemOp memop = get_memop(oi);
+ MemOp memop = get_memop(oi);
const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
#ifdef CONFIG_SOFTMMU
unsigned mem_index = get_mmuidx(oi);
diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c
index ece88dc2eb..94d80d79d1 100644
--- a/tcg/arm/tcg-target.inc.c
+++ b/tcg/arm/tcg-target.inc.c
@@ -1233,7 +1233,7 @@ QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 4);
containing the addend of the tlb entry. Clobbers R0, R1, R2, TMP. */
static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
- TCGMemOp opc, int mem_index, bool is_load)
+ MemOp opc, int mem_index, bool is_load)
{
int cmp_off = (is_load ? offsetof(CPUTLBEntry, addr_read)
: offsetof(CPUTLBEntry, addr_write));
@@ -1348,7 +1348,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
{
TCGReg argreg, datalo, datahi;
TCGMemOpIdx oi = lb->oi;
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
void *func;
if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
@@ -1412,7 +1412,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
{
TCGReg argreg, datalo, datahi;
TCGMemOpIdx oi = lb->oi;
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
return false;
@@ -1453,11 +1453,11 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
}
#endif /* SOFTMMU */
-static inline void tcg_out_qemu_ld_index(TCGContext *s, TCGMemOp opc,
+static inline void tcg_out_qemu_ld_index(TCGContext *s, MemOp opc,
TCGReg datalo, TCGReg datahi,
TCGReg addrlo, TCGReg addend)
{
- TCGMemOp bswap = opc & MO_BSWAP;
+ MemOp bswap = opc & MO_BSWAP;
switch (opc & MO_SSIZE) {
case MO_UB:
@@ -1514,11 +1514,11 @@ static inline void tcg_out_qemu_ld_index(TCGContext *s, TCGMemOp opc,
}
}
-static inline void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc,
+static inline void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc,
TCGReg datalo, TCGReg datahi,
TCGReg addrlo)
{
- TCGMemOp bswap = opc & MO_BSWAP;
+ MemOp bswap = opc & MO_BSWAP;
switch (opc & MO_SSIZE) {
case MO_UB:
@@ -1577,7 +1577,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
{
TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused));
TCGMemOpIdx oi;
- TCGMemOp opc;
+ MemOp opc;
#ifdef CONFIG_SOFTMMU
int mem_index;
TCGReg addend;
@@ -1614,11 +1614,11 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
#endif
}
-static inline void tcg_out_qemu_st_index(TCGContext *s, int cond, TCGMemOp opc,
+static inline void tcg_out_qemu_st_index(TCGContext *s, int cond, MemOp opc,
TCGReg datalo, TCGReg datahi,
TCGReg addrlo, TCGReg addend)
{
- TCGMemOp bswap = opc & MO_BSWAP;
+ MemOp bswap = opc & MO_BSWAP;
switch (opc & MO_SIZE) {
case MO_8:
@@ -1659,11 +1659,11 @@ static inline void tcg_out_qemu_st_index(TCGContext *s, int cond, TCGMemOp opc,
}
}
-static inline void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc,
+static inline void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc,
TCGReg datalo, TCGReg datahi,
TCGReg addrlo)
{
- TCGMemOp bswap = opc & MO_BSWAP;
+ MemOp bswap = opc & MO_BSWAP;
switch (opc & MO_SIZE) {
case MO_8:
@@ -1708,7 +1708,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
{
TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused));
TCGMemOpIdx oi;
- TCGMemOp opc;
+ MemOp opc;
#ifdef CONFIG_SOFTMMU
int mem_index;
TCGReg addend;
diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c
index 6ddeebf4bc..9d8ed974e0 100644
--- a/tcg/i386/tcg-target.inc.c
+++ b/tcg/i386/tcg-target.inc.c
@@ -1697,7 +1697,7 @@ static void * const qemu_st_helpers[16] = {
First argument register is clobbered. */
static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
- int mem_index, TCGMemOp opc,
+ int mem_index, MemOp opc,
tcg_insn_unit **label_ptr, int which)
{
const TCGReg r0 = TCG_REG_L0;
@@ -1810,7 +1810,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, bool is_64,
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
TCGMemOpIdx oi = l->oi;
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
TCGReg data_reg;
tcg_insn_unit **label_ptr = &l->label_ptr[0];
int rexw = (l->type == TCG_TYPE_I64 ? P_REXW : 0);
@@ -1895,8 +1895,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
TCGMemOpIdx oi = l->oi;
- TCGMemOp opc = get_memop(oi);
- TCGMemOp s_bits = opc & MO_SIZE;
+ MemOp opc = get_memop(oi);
+ MemOp s_bits = opc & MO_SIZE;
tcg_insn_unit **label_ptr = &l->label_ptr[0];
TCGReg retaddr;
@@ -1995,10 +1995,10 @@ static inline int setup_guest_base_seg(void)
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
TCGReg base, int index, intptr_t ofs,
- int seg, bool is64, TCGMemOp memop)
+ int seg, bool is64, MemOp memop)
{
- const TCGMemOp real_bswap = memop & MO_BSWAP;
- TCGMemOp bswap = real_bswap;
+ const MemOp real_bswap = memop & MO_BSWAP;
+ MemOp bswap = real_bswap;
int rexw = is64 * P_REXW;
int movop = OPC_MOVL_GvEv;
@@ -2103,7 +2103,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
TCGReg datalo, datahi, addrlo;
TCGReg addrhi __attribute__((unused));
TCGMemOpIdx oi;
- TCGMemOp opc;
+ MemOp opc;
#if defined(CONFIG_SOFTMMU)
int mem_index;
tcg_insn_unit *label_ptr[2];
@@ -2137,15 +2137,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
TCGReg base, int index, intptr_t ofs,
- int seg, TCGMemOp memop)
+ int seg, MemOp memop)
{
/* ??? Ideally we wouldn't need a scratch register. For user-only,
we could perform the bswap twice to restore the original value
instead of moving to the scratch. But as it is, the L constraint
means that TCG_REG_L0 is definitely free here. */
const TCGReg scratch = TCG_REG_L0;
- const TCGMemOp real_bswap = memop & MO_BSWAP;
- TCGMemOp bswap = real_bswap;
+ const MemOp real_bswap = memop & MO_BSWAP;
+ MemOp bswap = real_bswap;
int movop = OPC_MOVL_EvGv;
if (have_movbe && real_bswap) {
@@ -2221,7 +2221,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
TCGReg datalo, datahi, addrlo;
TCGReg addrhi __attribute__((unused));
TCGMemOpIdx oi;
- TCGMemOp opc;
+ MemOp opc;
#if defined(CONFIG_SOFTMMU)
int mem_index;
tcg_insn_unit *label_ptr[2];
diff --git a/tcg/mips/tcg-target.inc.c b/tcg/mips/tcg-target.inc.c
index 41bff32fb4..5442167045 100644
--- a/tcg/mips/tcg-target.inc.c
+++ b/tcg/mips/tcg-target.inc.c
@@ -1215,7 +1215,7 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl,
TCGReg addrh, TCGMemOpIdx oi,
tcg_insn_unit *label_ptr[2], bool is_load)
{
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
unsigned s_bits = opc & MO_SIZE;
unsigned a_bits = get_alignment_bits(opc);
int mem_index = get_mmuidx(oi);
@@ -1313,7 +1313,7 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
TCGMemOpIdx oi = l->oi;
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
TCGReg v0;
int i;
@@ -1363,8 +1363,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
TCGMemOpIdx oi = l->oi;
- TCGMemOp opc = get_memop(oi);
- TCGMemOp s_bits = opc & MO_SIZE;
+ MemOp opc = get_memop(oi);
+ MemOp s_bits = opc & MO_SIZE;
int i;
/* resolve label address */
@@ -1413,7 +1413,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
#endif
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
- TCGReg base, TCGMemOp opc, bool is_64)
+ TCGReg base, MemOp opc, bool is_64)
{
switch (opc & (MO_SSIZE | MO_BSWAP)) {
case MO_UB:
@@ -1521,7 +1521,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
TCGReg addr_regl, addr_regh __attribute__((unused));
TCGReg data_regl, data_regh;
TCGMemOpIdx oi;
- TCGMemOp opc;
+ MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[2];
#endif
@@ -1558,7 +1558,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
}
static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi,
- TCGReg base, TCGMemOp opc)
+ TCGReg base, MemOp opc)
{
/* Don't clutter the code below with checks to avoid bswapping ZERO. */
if ((lo | hi) == 0) {
@@ -1624,7 +1624,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
TCGReg addr_regl, addr_regh __attribute__((unused));
TCGReg data_regl, data_regh;
TCGMemOpIdx oi;
- TCGMemOp opc;
+ MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[2];
#endif
diff --git a/tcg/optimize.c b/tcg/optimize.c
index cee2a36a60..f7f4e873c9 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -1013,7 +1013,7 @@ void tcg_optimize(TCGContext *s)
CASE_OP_32_64(qemu_ld):
{
TCGMemOpIdx oi = op->args[nb_oargs + nb_iargs];
- TCGMemOp mop = get_memop(oi);
+ MemOp mop = get_memop(oi);
if (!(mop & MO_SIGN)) {
mask = (2ULL << ((8 << (mop & MO_SIZE)) - 1)) - 1;
}
diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c
index 852b8940fb..815edac077 100644
--- a/tcg/ppc/tcg-target.inc.c
+++ b/tcg/ppc/tcg-target.inc.c
@@ -1506,7 +1506,7 @@ QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -32768);
in CR7, loads the addend of the TLB into R3, and returns the register
containing the guest address (zero-extended into R4). Clobbers R0 and R2. */
-static TCGReg tcg_out_tlb_read(TCGContext *s, TCGMemOp opc,
+static TCGReg tcg_out_tlb_read(TCGContext *s, MemOp opc,
TCGReg addrlo, TCGReg addrhi,
int mem_index, bool is_read)
{
@@ -1633,7 +1633,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
{
TCGMemOpIdx oi = lb->oi;
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
TCGReg hi, lo, arg = TCG_REG_R3;
if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
@@ -1680,8 +1680,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
{
TCGMemOpIdx oi = lb->oi;
- TCGMemOp opc = get_memop(oi);
- TCGMemOp s_bits = opc & MO_SIZE;
+ MemOp opc = get_memop(oi);
+ MemOp s_bits = opc & MO_SIZE;
TCGReg hi, lo, arg = TCG_REG_R3;
if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
@@ -1744,7 +1744,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
TCGReg datalo, datahi, addrlo, rbase;
TCGReg addrhi __attribute__((unused));
TCGMemOpIdx oi;
- TCGMemOp opc, s_bits;
+ MemOp opc, s_bits;
#ifdef CONFIG_SOFTMMU
int mem_index;
tcg_insn_unit *label_ptr;
@@ -1819,7 +1819,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
TCGReg datalo, datahi, addrlo, rbase;
TCGReg addrhi __attribute__((unused));
TCGMemOpIdx oi;
- TCGMemOp opc, s_bits;
+ MemOp opc, s_bits;
#ifdef CONFIG_SOFTMMU
int mem_index;
tcg_insn_unit *label_ptr;
diff --git a/tcg/riscv/tcg-target.inc.c b/tcg/riscv/tcg-target.inc.c
index 3e76bf5738..7018509693 100644
--- a/tcg/riscv/tcg-target.inc.c
+++ b/tcg/riscv/tcg-target.inc.c
@@ -970,7 +970,7 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg addrl,
TCGReg addrh, TCGMemOpIdx oi,
tcg_insn_unit **label_ptr, bool is_load)
{
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
unsigned s_bits = opc & MO_SIZE;
unsigned a_bits = get_alignment_bits(opc);
tcg_target_long compare_mask;
@@ -1044,7 +1044,7 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
TCGMemOpIdx oi = l->oi;
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
TCGReg a0 = tcg_target_call_iarg_regs[0];
TCGReg a1 = tcg_target_call_iarg_regs[1];
TCGReg a2 = tcg_target_call_iarg_regs[2];
@@ -1077,8 +1077,8 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
TCGMemOpIdx oi = l->oi;
- TCGMemOp opc = get_memop(oi);
- TCGMemOp s_bits = opc & MO_SIZE;
+ MemOp opc = get_memop(oi);
+ MemOp s_bits = opc & MO_SIZE;
TCGReg a0 = tcg_target_call_iarg_regs[0];
TCGReg a1 = tcg_target_call_iarg_regs[1];
TCGReg a2 = tcg_target_call_iarg_regs[2];
@@ -1121,9 +1121,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
#endif /* CONFIG_SOFTMMU */
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
- TCGReg base, TCGMemOp opc, bool is_64)
+ TCGReg base, MemOp opc, bool is_64)
{
- const TCGMemOp bswap = opc & MO_BSWAP;
+ const MemOp bswap = opc & MO_BSWAP;
/* We don't yet handle byteswapping, assert */
g_assert(!bswap);
@@ -1172,7 +1172,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
TCGReg addr_regl, addr_regh __attribute__((unused));
TCGReg data_regl, data_regh;
TCGMemOpIdx oi;
- TCGMemOp opc;
+ MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[1];
#endif
@@ -1208,9 +1208,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
}
static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi,
- TCGReg base, TCGMemOp opc)
+ TCGReg base, MemOp opc)
{
- const TCGMemOp bswap = opc & MO_BSWAP;
+ const MemOp bswap = opc & MO_BSWAP;
/* We don't yet handle byteswapping, assert */
g_assert(!bswap);
@@ -1243,7 +1243,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
TCGReg addr_regl, addr_regh __attribute__((unused));
TCGReg data_regl, data_regh;
TCGMemOpIdx oi;
- TCGMemOp opc;
+ MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[1];
#endif
diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c
index fe42939d98..8aaa4cebe8 100644
--- a/tcg/s390/tcg-target.inc.c
+++ b/tcg/s390/tcg-target.inc.c
@@ -1430,7 +1430,7 @@ static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
}
}
-static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
+static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg data,
TCGReg base, TCGReg index, int disp)
{
switch (opc & (MO_SSIZE | MO_BSWAP)) {
@@ -1489,7 +1489,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
}
}
-static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
+static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg data,
TCGReg base, TCGReg index, int disp)
{
switch (opc & (MO_SIZE | MO_BSWAP)) {
@@ -1544,7 +1544,7 @@ QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 19));
/* Load and compare a TLB entry, leaving the flags set. Loads the TLB
addend into R2. Returns a register with the santitized guest address. */
-static TCGReg tcg_out_tlb_read(TCGContext* s, TCGReg addr_reg, TCGMemOp opc,
+static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
int mem_index, bool is_ld)
{
unsigned s_bits = opc & MO_SIZE;
@@ -1614,7 +1614,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGReg addr_reg = lb->addrlo_reg;
TCGReg data_reg = lb->datalo_reg;
TCGMemOpIdx oi = lb->oi;
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
(intptr_t)s->code_ptr, 2)) {
@@ -1639,7 +1639,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGReg addr_reg = lb->addrlo_reg;
TCGReg data_reg = lb->datalo_reg;
TCGMemOpIdx oi = lb->oi;
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
(intptr_t)s->code_ptr, 2)) {
@@ -1694,7 +1694,7 @@ static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg,
static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
TCGMemOpIdx oi)
{
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
#ifdef CONFIG_SOFTMMU
unsigned mem_index = get_mmuidx(oi);
tcg_insn_unit *label_ptr;
@@ -1721,7 +1721,7 @@ static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
TCGMemOpIdx oi)
{
- TCGMemOp opc = get_memop(oi);
+ MemOp opc = get_memop(oi);
#ifdef CONFIG_SOFTMMU
unsigned mem_index = get_mmuidx(oi);
tcg_insn_unit *label_ptr;
diff --git a/tcg/sparc/tcg-target.inc.c b/tcg/sparc/tcg-target.inc.c
index 10b1cea63b..d7986cda5c 100644
--- a/tcg/sparc/tcg-target.inc.c
+++ b/tcg/sparc/tcg-target.inc.c
@@ -1081,7 +1081,7 @@ QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 12));
is in the returned register, maybe %o0. The TLB addend is in %o1. */
static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addr, int mem_index,
- TCGMemOp opc, int which)
+ MemOp opc, int which)
{
int fast_off = TLB_MASK_TABLE_OFS(mem_index);
int mask_off = fast_off + offsetof(CPUTLBDescFast, mask);
@@ -1164,7 +1164,7 @@ static const int qemu_st_opc[16] = {
static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
TCGMemOpIdx oi, bool is_64)
{
- TCGMemOp memop = get_memop(oi);
+ MemOp memop = get_memop(oi);
#ifdef CONFIG_SOFTMMU
unsigned memi = get_mmuidx(oi);
TCGReg addrz, param;
@@ -1246,7 +1246,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr,
TCGMemOpIdx oi)
{
- TCGMemOp memop = get_memop(oi);
+ MemOp memop = get_memop(oi);
#ifdef CONFIG_SOFTMMU
unsigned memi = get_mmuidx(oi);
TCGReg addrz, param;
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 587d092238..e87c327fbf 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -2714,7 +2714,7 @@ void tcg_gen_lookup_and_goto_ptr(void)
}
}
-static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st)
+static inline MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st)
{
/* Trigger the asserts within as early as possible. */
(void)get_alignment_bits(op);
@@ -2743,7 +2743,7 @@ static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st)
}
static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr,
- TCGMemOp memop, TCGArg idx)
+ MemOp memop, TCGArg idx)
{
TCGMemOpIdx oi = make_memop_idx(memop, idx);
#if TARGET_LONG_BITS == 32
@@ -2758,7 +2758,7 @@ static void gen_ldst_i32(TCGOpcode opc, TCGv_i32 val, TCGv addr,
}
static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, TCGv addr,
- TCGMemOp memop, TCGArg idx)
+ MemOp memop, TCGArg idx)
{
TCGMemOpIdx oi = make_memop_idx(memop, idx);
#if TARGET_LONG_BITS == 32
@@ -2788,9 +2788,9 @@ static void tcg_gen_req_mo(TCGBar type)
}
}
-void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
+void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)
{
- TCGMemOp orig_memop;
+ MemOp orig_memop;
tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
memop = tcg_canonicalize_memop(memop, 0, 0);
@@ -2825,7 +2825,7 @@ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
}
}
-void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
+void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)
{
TCGv_i32 swap = NULL;
@@ -2858,9 +2858,9 @@ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
}
}
-void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
+void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop)
{
- TCGMemOp orig_memop;
+ MemOp orig_memop;
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
@@ -2911,7 +2911,7 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
}
}
-void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
+void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop)
{
TCGv_i64 swap = NULL;
@@ -2953,7 +2953,7 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
}
}
-static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc)
+static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc)
{
switch (opc & MO_SSIZE) {
case MO_SB:
@@ -2974,7 +2974,7 @@ static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc)
}
}
-static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, TCGMemOp opc)
+static void tcg_gen_ext_i64(TCGv_i64 ret, TCGv_i64 val, MemOp opc)
{
switch (opc & MO_SSIZE) {
case MO_SB:
@@ -3034,7 +3034,7 @@ static void * const table_cmpxchg[16] = {
};
void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv,
- TCGv_i32 newv, TCGArg idx, TCGMemOp memop)
+ TCGv_i32 newv, TCGArg idx, MemOp memop)
{
memop = tcg_canonicalize_memop(memop, 0, 0);
@@ -3078,7 +3078,7 @@ void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv,
}
void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv,
- TCGv_i64 newv, TCGArg idx, TCGMemOp memop)
+ TCGv_i64 newv, TCGArg idx, MemOp memop)
{
memop = tcg_canonicalize_memop(memop, 1, 0);
@@ -3142,7 +3142,7 @@ void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv,
}
static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val,
- TCGArg idx, TCGMemOp memop, bool new_val,
+ TCGArg idx, MemOp memop, bool new_val,
void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
{
TCGv_i32 t1 = tcg_temp_new_i32();
@@ -3160,7 +3160,7 @@ static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val,
}
static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val,
- TCGArg idx, TCGMemOp memop, void * const table[])
+ TCGArg idx, MemOp memop, void * const table[])
{
gen_atomic_op_i32 gen;
@@ -3185,7 +3185,7 @@ static void do_atomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val,
}
static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val,
- TCGArg idx, TCGMemOp memop, bool new_val,
+ TCGArg idx, MemOp memop, bool new_val,
void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64))
{
TCGv_i64 t1 = tcg_temp_new_i64();
@@ -3203,7 +3203,7 @@ static void do_nonatomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val,
}
static void do_atomic_op_i64(TCGv_i64 ret, TCGv addr, TCGv_i64 val,
- TCGArg idx, TCGMemOp memop, void * const table[])
+ TCGArg idx, MemOp memop, void * const table[])
{
memop = tcg_canonicalize_memop(memop, 1, 0);
@@ -3257,7 +3257,7 @@ static void * const table_##NAME[16] = { \
WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_##NAME##q_be) \
}; \
void tcg_gen_atomic_##NAME##_i32 \
- (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, TCGMemOp memop) \
+ (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop) \
{ \
if (tcg_ctx->tb_cflags & CF_PARALLEL) { \
do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME); \
@@ -3267,7 +3267,7 @@ void tcg_gen_atomic_##NAME##_i32 \
} \
} \
void tcg_gen_atomic_##NAME##_i64 \
- (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, TCGMemOp memop) \
+ (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, MemOp memop) \
{ \
if (tcg_ctx->tb_cflags & CF_PARALLEL) { \
do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME); \
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 2d4dd5cd7d..e9cf172762 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -851,10 +851,10 @@ void tcg_gen_lookup_and_goto_ptr(void);
#define tcg_gen_qemu_st_tl tcg_gen_qemu_st_i64
#endif
-void tcg_gen_qemu_ld_i32(TCGv_i32, TCGv, TCGArg, TCGMemOp);
-void tcg_gen_qemu_st_i32(TCGv_i32, TCGv, TCGArg, TCGMemOp);
-void tcg_gen_qemu_ld_i64(TCGv_i64, TCGv, TCGArg, TCGMemOp);
-void tcg_gen_qemu_st_i64(TCGv_i64, TCGv, TCGArg, TCGMemOp);
+void tcg_gen_qemu_ld_i32(TCGv_i32, TCGv, TCGArg, MemOp);
+void tcg_gen_qemu_st_i32(TCGv_i32, TCGv, TCGArg, MemOp);
+void tcg_gen_qemu_ld_i64(TCGv_i64, TCGv, TCGArg, MemOp);
+void tcg_gen_qemu_st_i64(TCGv_i64, TCGv, TCGArg, MemOp);
static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index)
{
@@ -912,46 +912,46 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
}
void tcg_gen_atomic_cmpxchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGv_i32,
- TCGArg, TCGMemOp);
+ TCGArg, MemOp);
void tcg_gen_atomic_cmpxchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGv_i64,
- TCGArg, TCGMemOp);
-
-void tcg_gen_atomic_xchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_xchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-
-void tcg_gen_atomic_fetch_add_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_add_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_and_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_and_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_or_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_or_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_xor_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_xor_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_smin_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_smin_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_umin_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_umin_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_smax_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_smax_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_umax_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_fetch_umax_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-
-void tcg_gen_atomic_add_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_add_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_and_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_and_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_or_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_or_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_xor_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_xor_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_smin_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_smin_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_umin_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_umin_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_smax_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_smax_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
-void tcg_gen_atomic_umax_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, TCGMemOp);
-void tcg_gen_atomic_umax_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, TCGMemOp);
+ TCGArg, MemOp);
+
+void tcg_gen_atomic_xchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_xchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+
+void tcg_gen_atomic_fetch_add_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_add_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_and_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_and_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_or_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_or_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_xor_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_xor_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_smin_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_smin_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_umin_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_umin_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_smax_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_smax_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_umax_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_fetch_umax_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+
+void tcg_gen_atomic_add_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_add_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_and_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_and_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_or_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_or_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_xor_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_xor_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_smin_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_smin_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_umin_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_umin_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_smax_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_smax_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
+void tcg_gen_atomic_umax_fetch_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp);
+void tcg_gen_atomic_umax_fetch_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp);
void tcg_gen_mov_vec(TCGv_vec, TCGv_vec);
void tcg_gen_dup_i32_vec(unsigned vece, TCGv_vec, TCGv_i32);
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 0458eaec57..16b2d0e0ec 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2055,7 +2055,7 @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs)
case INDEX_op_qemu_st_i64:
{
TCGMemOpIdx oi = op->args[k++];
- TCGMemOp op = get_memop(oi);
+ MemOp op = get_memop(oi);
unsigned ix = get_mmuidx(oi);
if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 529acb2ed8..a37181c899 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -26,6 +26,7 @@
#define TCG_H
#include "cpu.h"
+#include "exec/memop.h"
#include "exec/tb-context.h"
#include "qemu/bitops.h"
#include "qemu/queue.h"
@@ -309,103 +310,13 @@ typedef enum TCGType {
#endif
} TCGType;
-/* Constants for qemu_ld and qemu_st for the Memory Operation field. */
-typedef enum TCGMemOp {
- MO_8 = 0,
- MO_16 = 1,
- MO_32 = 2,
- MO_64 = 3,
- MO_SIZE = 3, /* Mask for the above. */
-
- MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */
-
- MO_BSWAP = 8, /* Host reverse endian. */
-#ifdef HOST_WORDS_BIGENDIAN
- MO_LE = MO_BSWAP,
- MO_BE = 0,
-#else
- MO_LE = 0,
- MO_BE = MO_BSWAP,
-#endif
-#ifdef TARGET_WORDS_BIGENDIAN
- MO_TE = MO_BE,
-#else
- MO_TE = MO_LE,
-#endif
-
- /*
- * MO_UNALN accesses are never checked for alignment.
- * MO_ALIGN accesses will result in a call to the CPU's
- * do_unaligned_access hook if the guest address is not aligned.
- * The default depends on whether the target CPU defines
- * TARGET_ALIGNED_ONLY.
- *
- * Some architectures (e.g. ARMv8) need the address which is aligned
- * to a size more than the size of the memory access.
- * Some architectures (e.g. SPARCv9) need an address which is aligned,
- * but less strictly than the natural alignment.
- *
- * MO_ALIGN supposes the alignment size is the size of a memory access.
- *
- * There are three options:
- * - unaligned access permitted (MO_UNALN).
- * - an alignment to the size of an access (MO_ALIGN);
- * - an alignment to a specified size, which may be more or less than
- * the access size (MO_ALIGN_x where 'x' is a size in bytes);
- */
- MO_ASHIFT = 4,
- MO_AMASK = 7 << MO_ASHIFT,
-#ifdef TARGET_ALIGNED_ONLY
- MO_ALIGN = 0,
- MO_UNALN = MO_AMASK,
-#else
- MO_ALIGN = MO_AMASK,
- MO_UNALN = 0,
-#endif
- MO_ALIGN_2 = 1 << MO_ASHIFT,
- MO_ALIGN_4 = 2 << MO_ASHIFT,
- MO_ALIGN_8 = 3 << MO_ASHIFT,
- MO_ALIGN_16 = 4 << MO_ASHIFT,
- MO_ALIGN_32 = 5 << MO_ASHIFT,
- MO_ALIGN_64 = 6 << MO_ASHIFT,
-
- /* Combinations of the above, for ease of use. */
- MO_UB = MO_8,
- MO_UW = MO_16,
- MO_UL = MO_32,
- MO_SB = MO_SIGN | MO_8,
- MO_SW = MO_SIGN | MO_16,
- MO_SL = MO_SIGN | MO_32,
- MO_Q = MO_64,
-
- MO_LEUW = MO_LE | MO_UW,
- MO_LEUL = MO_LE | MO_UL,
- MO_LESW = MO_LE | MO_SW,
- MO_LESL = MO_LE | MO_SL,
- MO_LEQ = MO_LE | MO_Q,
-
- MO_BEUW = MO_BE | MO_UW,
- MO_BEUL = MO_BE | MO_UL,
- MO_BESW = MO_BE | MO_SW,
- MO_BESL = MO_BE | MO_SL,
- MO_BEQ = MO_BE | MO_Q,
-
- MO_TEUW = MO_TE | MO_UW,
- MO_TEUL = MO_TE | MO_UL,
- MO_TESW = MO_TE | MO_SW,
- MO_TESL = MO_TE | MO_SL,
- MO_TEQ = MO_TE | MO_Q,
-
- MO_SSIZE = MO_SIZE | MO_SIGN,
-} TCGMemOp;
-
/**
* get_alignment_bits
- * @memop: TCGMemOp value
+ * @memop: MemOp value
*
* Extract the alignment size from the memop.
*/
-static inline unsigned get_alignment_bits(TCGMemOp memop)
+static inline unsigned get_alignment_bits(MemOp memop)
{
unsigned a = memop & MO_AMASK;
@@ -1186,7 +1097,7 @@ static inline size_t tcg_current_code_size(TCGContext *s)
return tcg_ptr_byte_diff(s->code_ptr, s->code_buf);
}
-/* Combine the TCGMemOp and mmu_idx parameters into a single value. */
+/* Combine the MemOp and mmu_idx parameters into a single value. */
typedef uint32_t TCGMemOpIdx;
/**
@@ -1196,7 +1107,7 @@ typedef uint32_t TCGMemOpIdx;
*
* Encode these values into a single parameter.
*/
-static inline TCGMemOpIdx make_memop_idx(TCGMemOp op, unsigned idx)
+static inline TCGMemOpIdx make_memop_idx(MemOp op, unsigned idx)
{
tcg_debug_assert(idx <= 15);
return (op << 4) | idx;
@@ -1208,7 +1119,7 @@ static inline TCGMemOpIdx make_memop_idx(TCGMemOp op, unsigned idx)
*
* Extract the memory operation from the combined value.
*/
-static inline TCGMemOp get_memop(TCGMemOpIdx oi)
+static inline MemOp get_memop(TCGMemOpIdx oi)
{
return oi >> 4;
}
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 49684fd4f4..b39860a8d0 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -1059,26 +1059,29 @@ BUILD_TCG_TARGET_RULES=$(patsubst %,build-tcg-tests-%, $(TARGET_DIRS))
CLEAN_TCG_TARGET_RULES=$(patsubst %,clean-tcg-tests-%, $(TARGET_DIRS))
RUN_TCG_TARGET_RULES=$(patsubst %,run-tcg-tests-%, $(TARGET_DIRS))
-ifeq ($(HAVE_USER_DOCKER),y)
# Probe for the Docker Builds needed for each build
$(foreach PROBE_TARGET,$(TARGET_DIRS), \
- $(eval -include $(SRC_PATH)/tests/tcg/Makefile.probe) \
- $(if $(DOCKER_PREREQ), \
- $(eval build-tcg-tests-$(PROBE_TARGET): $(DOCKER_PREREQ))))
-endif
+ $(eval -include $(SRC_PATH)/tests/tcg/Makefile.prereqs))
build-tcg-tests-%:
- $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" \
- SKIP_DOCKER_BUILD=1 TARGET_DIR="$*/" guest-tests, \
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \
+ -f $(SRC_PATH)/tests/tcg/Makefile.qemu \
+ SRC_PATH=$(SRC_PATH) \
+ V="$(V)" TARGET="$*" guest-tests, \
"BUILD", "TCG tests for $*")
-run-tcg-tests-%: % build-tcg-tests-%
- $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" \
- SKIP_DOCKER_BUILD=1 TARGET_DIR="$*/" run-guest-tests, \
+run-tcg-tests-%: build-tcg-tests-% %/all
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \
+ -f $(SRC_PATH)/tests/tcg/Makefile.qemu \
+ SRC_PATH=$(SRC_PATH) SPEED="$(SPEED)" \
+ V="$(V)" TARGET="$*" run-guest-tests, \
"RUN", "TCG tests for $*")
clean-tcg-tests-%:
- $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" clean-guest-tests,)
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \
+ -f $(SRC_PATH)/tests/tcg/Makefile.qemu \
+ SRC_PATH=$(SRC_PATH) TARGET="$*" clean-guest-tests, \
+ "CLEAN", "TCG tests for $*")
.PHONY: build-tcg
build-tcg: $(BUILD_TCG_TARGET_RULES)
@@ -1135,7 +1138,7 @@ TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results
AVOCADO_SHOW=app
AVOCADO_TAGS=$(patsubst %-softmmu,-t arch:%, $(filter %-softmmu,$(TARGET_DIRS)))
-ifneq ($(findstring v2,"v$(PYTHON_VERSION)"),v2)
+ifneq ($(PYTHON2),y)
$(TESTS_VENV_DIR): $(TESTS_VENV_REQ)
$(call quiet-command, \
$(PYTHON) -m venv --system-site-packages $@, \
diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py
index aee5d820ed..bd41e0443c 100644
--- a/tests/acceptance/avocado_qemu/__init__.py
+++ b/tests/acceptance/avocado_qemu/__init__.py
@@ -39,6 +39,9 @@ def pick_default_qemu_bin(arch=None):
"""
if arch is None:
arch = os.uname()[4]
+ # qemu binary path does not match arch for powerpc, handle it
+ if 'ppc64le' in arch:
+ arch = 'ppc64'
qemu_bin_relative_path = os.path.join("%s-softmmu" % arch,
"qemu-system-%s" % arch)
if is_readable_executable_file(qemu_bin_relative_path):
diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py
index 32159503e9..8a9a314ab4 100644
--- a/tests/acceptance/boot_linux_console.py
+++ b/tests/acceptance/boot_linux_console.py
@@ -76,8 +76,9 @@ class BootLinuxConsole(Test):
:avocado: tags=arch:x86_64
:avocado: tags=machine:pc
"""
- kernel_url = ('https://download.fedoraproject.org/pub/fedora/linux/'
- 'releases/29/Everything/x86_64/os/images/pxeboot/vmlinuz')
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
+ '/linux/releases/29/Everything/x86_64/os/images/pxeboot'
+ '/vmlinuz')
kernel_hash = '23bebd2680757891cf7adedb033532163a792495'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
@@ -250,8 +251,9 @@ class BootLinuxConsole(Test):
:avocado: tags=arch:aarch64
:avocado: tags=machine:virt
"""
- kernel_url = ('https://download.fedoraproject.org/pub/fedora/linux/'
- 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz')
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
+ '/linux/releases/29/Everything/aarch64/os/images/pxeboot'
+ '/vmlinuz')
kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
@@ -271,8 +273,9 @@ class BootLinuxConsole(Test):
:avocado: tags=arch:arm
:avocado: tags=machine:virt
"""
- kernel_url = ('https://download.fedoraproject.org/pub/fedora/linux/'
- 'releases/29/Everything/armhfp/os/images/pxeboot/vmlinuz')
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
+ '/linux/releases/29/Everything/armhfp/os/images/pxeboot'
+ '/vmlinuz')
kernel_hash = 'e9826d741b4fb04cadba8d4824d1ed3b7fb8b4d4'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
@@ -318,8 +321,9 @@ class BootLinuxConsole(Test):
:avocado: tags=arch:s390x
:avocado: tags=machine:s390_ccw_virtio
"""
- kernel_url = ('https://download.fedoraproject.org/pub/fedora-secondary/'
- 'releases/29/Everything/s390x/os/images/kernel.img')
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive'
+ '/fedora-secondary/releases/29/Everything/s390x/os/images'
+ '/kernel.img')
kernel_hash = 'e8e8439103ef8053418ef062644ffd46a7919313'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
@@ -354,3 +358,23 @@ class BootLinuxConsole(Test):
self.vm.launch()
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.wait_for_console_pattern(console_pattern)
+
+ def test_ppc64_pseries(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:pseries
+ """
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive'
+ '/fedora-secondary/releases/29/Everything/ppc64le/os'
+ '/ppc/ppc64/vmlinuz')
+ kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
+ kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+
+ self.vm.set_machine('pseries')
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
diff --git a/tests/acceptance/linux_initrd.py b/tests/acceptance/linux_initrd.py
index 23be5a63aa..c61d9826a4 100644
--- a/tests/acceptance/linux_initrd.py
+++ b/tests/acceptance/linux_initrd.py
@@ -54,8 +54,9 @@ class LinuxInitrd(Test):
QEMU has supported up to 4 GiB initrd for recent kernel
Expect guest can reach 'Unpacking initramfs...'
"""
- kernel_url = ('https://mirrors.kernel.org/fedora/releases/28/'
- 'Everything/x86_64/os/images/pxeboot/vmlinuz')
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
+ '/linux/releases/28/Everything/x86_64/os/images/pxeboot/'
+ 'vmlinuz')
kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
max_size = 2 * (1024 ** 3) + 1
diff --git a/tests/acceptance/linux_ssh_mips_malta.py b/tests/acceptance/linux_ssh_mips_malta.py
index aafb0c39f6..134f10cac3 100644
--- a/tests/acceptance/linux_ssh_mips_malta.py
+++ b/tests/acceptance/linux_ssh_mips_malta.py
@@ -162,7 +162,7 @@ class LinuxSSH(Test):
self.assertIn(True, ["0dfbe8aa4c20b52e1b8bf3cb6cbdf193" in line
for line in stdout])
- def do_test_mips_malta(self, endianess, kernel_path, uname_m):
+ def check_mips_malta(self, endianess, kernel_path, uname_m):
self.boot_debian_wheezy_image_and_ssh_login(endianess, kernel_path)
stdout, stderr = self.ssh_command('uname -a')
@@ -184,7 +184,7 @@ class LinuxSSH(Test):
kernel_hash = '592e384a4edc16dade52a6cd5c785c637bcbc9ad'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta('be', kernel_path, 'mips')
+ self.check_mips_malta('be', kernel_path, 'mips')
@skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI')
def test_mips_malta32el_kernel3_2_0(self):
@@ -199,7 +199,7 @@ class LinuxSSH(Test):
kernel_hash = 'a66bea5a8adaa2cb3d36a1d4e0ccdb01be8f6c2a'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta('le', kernel_path, 'mips')
+ self.check_mips_malta('le', kernel_path, 'mips')
@skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI')
def test_mips_malta64eb_kernel3_2_0(self):
@@ -213,7 +213,7 @@ class LinuxSSH(Test):
'vmlinux-3.2.0-4-5kc-malta')
kernel_hash = 'db6eea7de35d36c77d8c165b6bcb222e16eb91db'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta('be', kernel_path, 'mips64')
+ self.check_mips_malta('be', kernel_path, 'mips64')
@skipIf(os.getenv('CONTINUOUS_INTEGRATION'), 'Running on Travis-CI')
def test_mips_malta64el_kernel3_2_0(self):
@@ -227,4 +227,4 @@ class LinuxSSH(Test):
'vmlinux-3.2.0-4-5kc-malta')
kernel_hash = '6a7f77245acf231415a0e8b725d91ed2f3487794'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.do_test_mips_malta('le', kernel_path, 'mips64')
+ self.check_mips_malta('le', kernel_path, 'mips64')
diff --git a/tests/acceptance/machine_m68k_nextcube.py b/tests/acceptance/machine_m68k_nextcube.py
new file mode 100644
index 0000000000..e09cab9f20
--- /dev/null
+++ b/tests/acceptance/machine_m68k_nextcube.py
@@ -0,0 +1,121 @@
+# Functional test that boots a VM and run OCR on the framebuffer
+#
+# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+import re
+import time
+import logging
+import distutils.spawn
+
+from avocado_qemu import Test
+from avocado import skipUnless
+from avocado.utils import process
+from avocado.utils.path import find_command, CmdNotFoundError
+
+PIL_AVAILABLE = True
+try:
+ from PIL import Image
+except ImportError:
+ PIL_AVAILABLE = False
+
+
+def tesseract_available(expected_version):
+ try:
+ find_command('tesseract')
+ except CmdNotFoundError:
+ return False
+ res = process.run('tesseract --version')
+ try:
+ version = res.stdout_text.split()[1]
+ except IndexError:
+ version = res.stderr_text.split()[1]
+ return int(version.split('.')[0]) == expected_version
+
+ match = re.match(r'tesseract\s(\d)', res)
+ if match is None:
+ return False
+ # now this is guaranteed to be a digit
+ return int(match.groups()[0]) == expected_version
+
+
+class NextCubeMachine(Test):
+
+ timeout = 15
+
+ def check_bootrom_framebuffer(self, screenshot_path):
+ rom_url = ('http://www.nextcomputers.org/NeXTfiles/Software/ROM_Files/'
+ '68040_Non-Turbo_Chipset/Rev_2.5_v66.BIN')
+ rom_hash = 'b3534796abae238a0111299fc406a9349f7fee24'
+ rom_path = self.fetch_asset(rom_url, asset_hash=rom_hash)
+
+ self.vm.set_machine('next-cube')
+ self.vm.add_args('-bios', rom_path)
+ self.vm.launch()
+
+ self.log.info('VM launched, waiting for display')
+ # TODO: Use avocado.utils.wait.wait_for to catch the
+ # 'displaysurface_create 1120x832' trace-event.
+ time.sleep(2)
+
+ self.vm.command('human-monitor-command',
+ command_line='screendump %s' % screenshot_path)
+
+ @skipUnless(PIL_AVAILABLE, 'Python PIL not installed')
+ def test_bootrom_framebuffer_size(self):
+ """
+ :avocado: tags=arch:m68k
+ :avocado: tags=machine:next_cube
+ :avocado: tags=device:framebuffer
+ """
+ screenshot_path = os.path.join(self.workdir, "dump.png")
+ self.check_bootrom_framebuffer(screenshot_path)
+
+ width, height = Image.open(screenshot_path).size
+ self.assertEqual(width, 1120)
+ self.assertEqual(height, 832)
+
+ @skipUnless(tesseract_available(3), 'tesseract v3 OCR tool not available')
+ def test_bootrom_framebuffer_ocr_with_tesseract_v3(self):
+ """
+ :avocado: tags=arch:m68k
+ :avocado: tags=machine:next_cube
+ :avocado: tags=device:framebuffer
+ """
+ screenshot_path = os.path.join(self.workdir, "dump.png")
+ self.check_bootrom_framebuffer(screenshot_path)
+
+ console_logger = logging.getLogger('console')
+ text = process.run("tesseract %s stdout" % screenshot_path).stdout_text
+ for line in text.split('\n'):
+ if len(line):
+ console_logger.debug(line)
+ self.assertIn('Backplane', text)
+ self.assertIn('Ethernet address', text)
+
+ # Tesseract 4 adds a new OCR engine based on LSTM neural networks. The
+ # new version is faster and more accurate than version 3. The drawback is
+ # that it is still alpha-level software.
+ @skipUnless(tesseract_available(4), 'tesseract v4 OCR tool not available')
+ def test_bootrom_framebuffer_ocr_with_tesseract_v4(self):
+ """
+ :avocado: tags=arch:m68k
+ :avocado: tags=machine:next_cube
+ :avocado: tags=device:framebuffer
+ """
+ screenshot_path = os.path.join(self.workdir, "dump.png")
+ self.check_bootrom_framebuffer(screenshot_path)
+
+ console_logger = logging.getLogger('console')
+ proc = process.run("tesseract --oem 1 %s stdout" % screenshot_path)
+ text = proc.stdout_text
+ for line in text.split('\n'):
+ if len(line):
+ console_logger.debug(line)
+ self.assertIn('Testing the FPU, SCC', text)
+ self.assertIn('System test failed. Error code 51', text)
+ self.assertIn('Boot command', text)
+ self.assertIn('Next>', text)
diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py
index 6115cf6c24..a44c1ae58f 100644
--- a/tests/acceptance/migration.py
+++ b/tests/acceptance/migration.py
@@ -17,9 +17,6 @@ from avocado.utils import wait
class Migration(Test):
- """
- :avocado: enable
- """
timeout = 10
diff --git a/tests/acceptance/pc_cpu_hotplug_props.py b/tests/acceptance/pc_cpu_hotplug_props.py
new file mode 100644
index 0000000000..08b7e632c6
--- /dev/null
+++ b/tests/acceptance/pc_cpu_hotplug_props.py
@@ -0,0 +1,35 @@
+#
+# Ensure CPU die-id can be omitted on -device
+#
+# Copyright (c) 2019 Red Hat Inc
+#
+# Author:
+# Eduardo Habkost <ehabkost@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+#
+
+from avocado_qemu import Test
+
+class OmittedCPUProps(Test):
+ """
+ :avocado: tags=arch:x86_64
+ """
+ def test_no_die_id(self):
+ self.vm.add_args('-nodefaults', '-S')
+ self.vm.add_args('-smp', '1,sockets=2,cores=2,threads=2,maxcpus=8')
+ self.vm.add_args('-cpu', 'qemu64')
+ self.vm.add_args('-device', 'qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id=0')
+ self.vm.launch()
+ self.assertEquals(len(self.vm.command('query-cpus')), 2)
diff --git a/tests/acceptance/vnc.py b/tests/acceptance/vnc.py
index 064ceabcc1..3f40bc2be1 100644
--- a/tests/acceptance/vnc.py
+++ b/tests/acceptance/vnc.py
@@ -34,7 +34,7 @@ class Vnc(Test):
self.assertEqual(set_password_response['error']['desc'],
'Could not set password')
- def test_vnc_change_password_requires_a_password(self):
+ def test_change_password_requires_a_password(self):
self.vm.add_args('-nodefaults', '-S', '-vnc', ':0')
self.vm.launch()
self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled'])
@@ -48,7 +48,7 @@ class Vnc(Test):
self.assertEqual(set_password_response['error']['desc'],
'Could not set password')
- def test_vnc_change_password(self):
+ def test_change_password(self):
self.vm.add_args('-nodefaults', '-S', '-vnc', ':0,password')
self.vm.launch()
self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled'])
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 086811e602..c8d42ceea0 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -200,7 +200,6 @@ static void ahci_shutdown(AHCIQState *ahci)
{
QOSState *qs = ahci->parent;
- assert(!global_qtest);
ahci_clean_mem(ahci);
free_ahci_device(ahci->dev);
g_free(ahci);
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index a356ac3489..9b3d8b0d1b 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -626,7 +626,6 @@ static void test_acpi_one(const char *params, test_data *data)
test_smbios_structs(data);
}
- assert(!global_qtest);
qtest_quit(data->qts);
g_free(args);
}
diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c
index 24852d4c7d..d3a54a0ba5 100644
--- a/tests/boot-serial-test.c
+++ b/tests/boot-serial-test.c
@@ -24,6 +24,17 @@ static const uint8_t kernel_mcf5208[] = {
0x60, 0xfa /* bra.s loop */
};
+static const uint8_t bios_nextcube[] = {
+ 0x06, 0x00, 0x00, 0x00, /* Initial SP */
+ 0x01, 0x00, 0x00, 0x08, /* Initial PC */
+ 0x41, 0xf9, 0x02, 0x11, 0x80, 0x00, /* lea 0x02118000,%a0 */
+ 0x10, 0x3c, 0x00, 0x54, /* move.b #'T',%d0 */
+ 0x11, 0x7c, 0x00, 0x05, 0x00, 0x01, /* move.b #5,1(%a0) Sel TXCTRL */
+ 0x11, 0x7c, 0x00, 0x68, 0x00, 0x01, /* move.b #0x68,1(%a0) Enable TX */
+ 0x11, 0x40, 0x00, 0x03, /* move.b %d0,3(%a0) Print 'T' */
+ 0x60, 0xfa /* bra.s loop */
+};
+
static const uint8_t kernel_pls3adsp1800[] = {
0xb0, 0x00, 0x84, 0x00, /* imm 0x8400 */
0x30, 0x60, 0x00, 0x04, /* addik r3,r0,4 */
@@ -103,7 +114,8 @@ static testdef_t tests[] = {
{ "ppc64", "pseries",
"-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken",
"Open Firmware" },
- { "ppc64", "powernv", "-cpu POWER8", "OPAL" },
+ { "ppc64", "powernv8", "", "OPAL" },
+ { "ppc64", "powernv9", "", "OPAL" },
{ "ppc64", "sam460ex", "-device e1000", "8086 100e" },
{ "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
{ "i386", "pc", "-device sga", "SGABIOS" },
@@ -116,6 +128,7 @@ static testdef_t tests[] = {
{ "sparc64", "sun4u", "", "UltraSPARC" },
{ "s390x", "s390-ccw-virtio", "", "device" },
{ "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
+ { "m68k", "next-cube", "", "TT", sizeof(bios_nextcube), 0, bios_nextcube },
{ "microblaze", "petalogix-s3adsp1800", "", "TT",
sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },
{ "microblazeel", "petalogix-ml605", "", "TT",
diff --git a/tests/check-block.sh b/tests/check-block.sh
index c8b6cec3f6..679aedec50 100755
--- a/tests/check-block.sh
+++ b/tests/check-block.sh
@@ -21,6 +21,11 @@ if grep -q "TARGET_GPROF=y" *-softmmu/config-target.mak 2>/dev/null ; then
exit 0
fi
+if grep -q "CFLAGS.*-fsanitize" config-host.mak 2>/dev/null ; then
+ echo "Sanitizers are enabled ==> Not running the qemu-iotests."
+ exit 0
+fi
+
if [ -z "$(find . -name 'qemu-system-*' -print)" ]; then
echo "No qemu-system binary available ==> Not running the qemu-iotests."
exit 0
diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c
index 3049620854..776407e1b6 100644
--- a/tests/cpu-plug-test.c
+++ b/tests/cpu-plug-test.c
@@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qapi/qmp/qdict.h"
struct PlugTestData {
diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c
index bd176dcf3a..ace3bb28e0 100644
--- a/tests/display-vga-test.c
+++ b/tests/display-vga-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
static void pci_cirrus(void)
{
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index cf535cbd19..50a400b573 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -6,7 +6,8 @@ DOCKER_SUFFIX := .docker
DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles
DOCKER_DEPRECATED_IMAGES := debian
# we don't run tests on intermediate images (used as base by another image)
-DOCKER_PARTIAL_IMAGES := debian debian8 debian9 debian8-mxe debian-ports debian-sid debian-bootstrap
+DOCKER_PARTIAL_IMAGES := debian debian8 debian9 debian10 debian-sid
+DEBIAN_PARTIAL_IMAGES += debian8-mxe debian-9-mxe debian-ports debian-bootstrap
DOCKER_IMAGES := $(filter-out $(DOCKER_DEPRECATED_IMAGES),$(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker)))))
DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES))
# Use a global constant ccache directory to speed up repetitive builds
@@ -71,7 +72,8 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker
$(if $(wildcard $(EXECUTABLE)), \
$(call quiet-command, \
DEB_ARCH=$(DEB_ARCH) \
- DEB_TYPE=$(DEB_TYPE) \
+ DEB_TYPE=$(DEB_TYPE) \
+ $(if $(DEB_URL),DEB_URL=$(DEB_URL),) \
$(DOCKER_SCRIPT) build qemu:debian-$* $< \
$(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \
$(if $(NOUSER),,--add-current-user) \
@@ -86,13 +88,16 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker
endif
# Enforce dependencies for composite images
-docker-image-debian: docker-image-debian9
docker-image-debian9-mxe: docker-image-debian9
+ifeq ($(ARCH),x86_64)
docker-image-debian-amd64: docker-image-debian9
+DOCKER_PARTIAL_IMAGES += debian-amd64-cross
+else
+docker-image-debian-amd64-cross: docker-image-debian10
+DOCKER_PARTIAL_IMAGES += debian-amd64
+endif
docker-image-debian-armel-cross: docker-image-debian9
docker-image-debian-armhf-cross: docker-image-debian9
-docker-image-debian-arm64-cross: docker-image-debian9
-docker-image-debian-buster-arm64-cross: docker-image-debian10
docker-image-debian-mips-cross: docker-image-debian9
docker-image-debian-mipsel-cross: docker-image-debian9
docker-image-debian-mips64el-cross: docker-image-debian9
@@ -101,25 +106,41 @@ docker-image-debian-s390x-cross: docker-image-debian9
docker-image-debian-win32-cross: docker-image-debian9-mxe
docker-image-debian-win64-cross: docker-image-debian9-mxe
-docker-image-debian-alpha-cross: docker-image-debian-sid
-docker-image-debian-hppa-cross: docker-image-debian-sid
-docker-image-debian-m68k-cross: docker-image-debian-sid
-docker-image-debian-sh4-cross: docker-image-debian-sid
-docker-image-debian-sparc64-cross: docker-image-debian-sid
-docker-image-debian-mips64-cross: docker-image-debian-sid
-docker-image-debian-riscv64-cross: docker-image-debian-sid
-docker-image-debian-powerpc-cross: docker-image-debian-sid
-docker-image-debian-ppc64-cross: docker-image-debian-sid
+# For non-x86 hosts not all cross-compilers have been packaged
+ifneq ($(ARCH),x86_64)
+DOCKER_PARTIAL_IMAGES += debian-mips-cross debian-mipsel-cross debian-mips64el-cross
+DOCKER_PARTIAL_IMAGES += debian-ppc64el-cross
+DOCKER_PARTIAL_IMAGES += debian-s390x-cross
+DOCKER_PARTIAL_IMAGES += debian-win32-cross debian-win64-cross
+DOCKER_PARTIAL_IMAGES += fedora travis
+endif
+
+docker-image-debian-alpha-cross: docker-image-debian10
+docker-image-debian-arm64-cross: docker-image-debian10
+docker-image-debian-hppa-cross: docker-image-debian10
+docker-image-debian-m68k-cross: docker-image-debian10
+docker-image-debian-mips64-cross: docker-image-debian10
+docker-image-debian-powerpc-cross: docker-image-debian10
+docker-image-debian-ppc64-cross: docker-image-debian10
+docker-image-debian-riscv64-cross: docker-image-debian10
+docker-image-debian-sh4-cross: docker-image-debian10
+docker-image-debian-sparc64-cross: docker-image-debian10
+
docker-image-travis: NOUSER=1
# Specialist build images, sometimes very limited tools
docker-image-tricore-cross: docker-image-debian9
# These images may be good enough for building tests but not for test builds
-DOCKER_PARTIAL_IMAGES += debian-alpha-cross debian-hppa-cross debian-m68k-cross debian-sh4-cross
-DOCKER_PARTIAL_IMAGES += debian-sparc64-cross debian-mips64-cross debian-riscv64-cross
-DOCKER_PARTIAL_IMAGES += debian-tricore-cross debian-powerpc-cross fedora-i386-cross
-DOCKER_PARTIAL_IMAGES += fedora-cris-cross
+DOCKER_PARTIAL_IMAGES += debian-alpha-cross
+DOCKER_PARTIAL_IMAGES += debian-hppa-cross
+DOCKER_PARTIAL_IMAGES += debian-m68k-cross debian-mips64-cross
+DOCKER_PARTIAL_IMAGES += debian-powerpc-cross debian-ppc64-cross
+DOCKER_PARTIAL_IMAGES += debian-riscv64-cross
+DOCKER_PARTIAL_IMAGES += debian-sh4-cross debian-sparc64-cross
+DOCKER_PARTIAL_IMAGES += debian-tricore-cross
+DOCKER_PARTIAL_IMAGES += debian-xtensa-cross
+DOCKER_PARTIAL_IMAGES += fedora-i386-cross fedora-cris-cross
# Rules for building linux-user powered images
#
@@ -131,6 +152,7 @@ DOCKER_PARTIAL_IMAGES += fedora-cris-cross
# broken so we need a qemu-linux-user for this target
docker-binfmt-image-debian-powerpc-user: DEB_ARCH = powerpc
docker-binfmt-image-debian-powerpc-user: DEB_TYPE = jessie
+docker-binfmt-image-debian-powerpc-user: DEB_URL = http://snapshot.debian.org/archive/debian/20180615T211437Z
docker-binfmt-image-debian-powerpc-user: EXECUTABLE = ${BUILD_DIR}/ppc-linux-user/qemu-ppc
docker-image-debian-powerpc-user-cross: docker-binfmt-image-debian-powerpc-user
DOCKER_USER_IMAGES += debian-powerpc-user
diff --git a/tests/docker/common.rc b/tests/docker/common.rc
index 4011561587..512202b0a1 100755
--- a/tests/docker/common.rc
+++ b/tests/docker/common.rc
@@ -11,6 +11,10 @@
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
+# This might be set by ENV of a docker container... it is always
+# overriden by TARGET_LIST if the user sets it.
+DEF_TARGET_LIST=${DEF_TARGET_LIST:-"x86_64-softmmu,aarch64-softmmu"}
+
requires()
{
for c in $@; do
diff --git a/tests/docker/docker.py b/tests/docker/docker.py
index ac5baab4ca..29613afd48 100755
--- a/tests/docker/docker.py
+++ b/tests/docker/docker.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# Docker controlling module
#
@@ -11,7 +11,6 @@
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
-from __future__ import print_function
import os
import sys
import subprocess
@@ -25,10 +24,7 @@ import tempfile
import re
import signal
from tarfile import TarFile, TarInfo
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
+from io import StringIO
from shutil import copy, rmtree
from pwd import getpwuid
from datetime import datetime, timedelta
@@ -62,11 +58,13 @@ USE_ENGINE = EngineEnum.AUTO
def _text_checksum(text):
"""Calculate a digest string unique to the text content"""
- return hashlib.sha1(text).hexdigest()
+ return hashlib.sha1(text.encode('utf-8')).hexdigest()
+def _read_dockerfile(path):
+ return open(path, 'rt', encoding='utf-8').read()
def _file_checksum(filename):
- return _text_checksum(open(filename, 'rb').read())
+ return _text_checksum(_read_dockerfile(filename))
def _guess_engine_command():
@@ -113,7 +111,7 @@ def _get_so_libs(executable):
libs = []
ldd_re = re.compile(r"(/.*/)(\S*)")
try:
- ldd_output = subprocess.check_output(["ldd", executable])
+ ldd_output = subprocess.check_output(["ldd", executable]).decode('utf-8')
for line in ldd_output.split("\n"):
search = ldd_re.search(line)
if search and len(search.groups()) == 2:
@@ -192,7 +190,7 @@ def _read_qemu_dockerfile(img_name):
df = os.path.join(os.path.dirname(__file__), "dockerfiles",
img_name + ".docker")
- return open(df, "r").read()
+ return _read_dockerfile(df)
def _dockerfile_preprocess(df):
@@ -260,9 +258,16 @@ class Docker(object):
return self._do_kill_instances(True)
def _output(self, cmd, **kwargs):
- return subprocess.check_output(self._command + cmd,
- stderr=subprocess.STDOUT,
- **kwargs)
+ if sys.version_info[1] >= 6:
+ return subprocess.check_output(self._command + cmd,
+ stderr=subprocess.STDOUT,
+ encoding='utf-8',
+ **kwargs)
+ else:
+ return subprocess.check_output(self._command + cmd,
+ stderr=subprocess.STDOUT,
+ **kwargs).decode('utf-8')
+
def inspect_tag(self, tag):
try:
@@ -283,7 +288,9 @@ class Docker(object):
if argv is None:
argv = []
- tmp_df = tempfile.NamedTemporaryFile(dir=docker_dir, suffix=".docker")
+ tmp_df = tempfile.NamedTemporaryFile(mode="w+t",
+ encoding='utf-8',
+ dir=docker_dir, suffix=".docker")
tmp_df.write(dockerfile)
if user:
@@ -317,10 +324,18 @@ class Docker(object):
return False
return checksum == _text_checksum(_dockerfile_preprocess(dockerfile))
- def run(self, cmd, keep, quiet):
+ def run(self, cmd, keep, quiet, as_user=False):
label = uuid.uuid1().hex
if not keep:
self._instances.append(label)
+
+ if as_user:
+ uid = os.getuid()
+ cmd = [ "-u", str(uid) ] + cmd
+ # podman requires a bit more fiddling
+ if self._command[0] == "podman":
+ argv.insert(0, '--userns=keep-id')
+
ret = self._do_check(["run", "--label",
"com.qemu.instance.uuid=" + label] + cmd,
quiet=quiet)
@@ -363,15 +378,8 @@ class RunCommand(SubCommand):
help="Run container using the current user's uid")
def run(self, args, argv):
- if args.run_as_current_user:
- uid = os.getuid()
- argv = [ "-u", str(uid) ] + argv
- docker = Docker()
- if docker._command[0] == "podman":
- argv = [ "--uidmap", "%d:0:1" % uid,
- "--uidmap", "0:1:%d" % uid,
- "--uidmap", "%d:%d:64536" % (uid + 1, uid + 1)] + argv
- return Docker().run(argv, args.keep, quiet=args.quiet)
+ return Docker().run(argv, args.keep, quiet=args.quiet,
+ as_user=args.run_as_current_user)
class BuildCommand(SubCommand):
@@ -396,7 +404,7 @@ class BuildCommand(SubCommand):
help="Dockerfile name")
def run(self, args, argv):
- dockerfile = open(args.dockerfile, "rb").read()
+ dockerfile = _read_dockerfile(args.dockerfile)
tag = args.tag
dkr = Docker()
@@ -442,7 +450,7 @@ class BuildCommand(SubCommand):
cksum += [(filename, _file_checksum(filename))]
argv += ["--build-arg=" + k.lower() + "=" + v
- for k, v in os.environ.iteritems()
+ for k, v in os.environ.items()
if k.lower() in FILTERED_ENV_NAMES]
dkr.build_image(tag, docker_dir, dockerfile,
quiet=args.quiet, user=args.user, argv=argv,
@@ -535,9 +543,9 @@ class ProbeCommand(SubCommand):
try:
docker = Docker()
if docker._command[0] == "docker":
- print("yes")
+ print("docker")
elif docker._command[0] == "sudo":
- print("sudo")
+ print("sudo docker")
elif docker._command[0] == "podman":
print("podman")
except Exception:
@@ -555,8 +563,6 @@ class CcCommand(SubCommand):
help="The docker image in which to run cc")
parser.add_argument("--cc", default="cc",
help="The compiler executable to call")
- parser.add_argument("--user",
- help="The user-id to run under")
parser.add_argument("--source-path", "-s", nargs="*", dest="paths",
help="""Extra paths to (ro) mount into container for
reading sources""")
@@ -570,11 +576,10 @@ class CcCommand(SubCommand):
if args.paths:
for p in args.paths:
cmd += ["-v", "%s:%s:ro,z" % (p, p)]
- if args.user:
- cmd += ["-u", args.user]
cmd += [args.image, args.cc]
cmd += argv
- return Docker().command("run", cmd, args.quiet)
+ return Docker().run(cmd, False, quiet=args.quiet,
+ as_user=True)
class CheckCommand(SubCommand):
@@ -611,7 +616,7 @@ class CheckCommand(SubCommand):
print("Need a dockerfile for tag:%s" % (tag))
return 1
- dockerfile = open(args.dockerfile, "rb").read()
+ dockerfile = _read_dockerfile(args.dockerfile)
if dkr.image_matches_dockerfile(tag, dockerfile):
if not args.quiet:
@@ -650,7 +655,8 @@ def main():
cmd.args(subp)
subp.set_defaults(cmdobj=cmd)
args, argv = parser.parse_known_args()
- USE_ENGINE = args.engine
+ if args.engine:
+ USE_ENGINE = args.engine
return args.cmdobj.run(args, argv)
diff --git a/tests/docker/dockerfiles/debian-alpha-cross.docker b/tests/docker/dockerfiles/debian-alpha-cross.docker
index 23444342f0..74bcabfdb1 100644
--- a/tests/docker/dockerfiles/debian-alpha-cross.docker
+++ b/tests/docker/dockerfiles/debian-alpha-cross.docker
@@ -1,13 +1,12 @@
#
# Docker cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian-sid
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
gcc-alpha-linux-gnu \
- libc6.1-dev-alpha-cross || { echo "Failed to build - see debian-sid.docker notes"; exit 1; }
+ libc6.1-dev-alpha-cross
diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker
new file mode 100644
index 0000000000..5d89041925
--- /dev/null
+++ b/tests/docker/dockerfiles/debian-amd64-cross.docker
@@ -0,0 +1,22 @@
+#
+# Docker x86_64 cross target
+#
+# This docker target is used on non-x86_64 machines which need the
+# x86_64 cross compilers installed.
+#
+FROM qemu:debian10
+MAINTAINER Alex Bennée <alex.bennee@linaro.org>
+
+# Add the foreign architecture we want and install dependencies
+RUN dpkg --add-architecture amd64
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt install -y --no-install-recommends \
+ crossbuild-essential-amd64
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt build-dep -yy -a amd64 --arch-only qemu
+
+# Specify the cross prefix for this image (see tests/docker/common.rc)
+ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-linux-gnu-
+ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user
diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker
index 7c2cc93daf..09ca0a1ba7 100644
--- a/tests/docker/dockerfiles/debian-arm64-cross.docker
+++ b/tests/docker/dockerfiles/debian-arm64-cross.docker
@@ -1,9 +1,9 @@
#
# Docker arm64 cross-compiler target
#
-# This docker target builds on the debian Stretch base image.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian9
+FROM qemu:debian10
# Add the foreign architecture we want and install dependencies
RUN dpkg --add-architecture arm64
@@ -13,10 +13,11 @@ RUN apt update && \
crossbuild-essential-arm64
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
- apt build-dep -yy -a arm64 qemu
+ apt build-dep -yy -a arm64 --arch-only qemu
# Specify the cross prefix for this image (see tests/docker/common.rc)
ENV QEMU_CONFIGURE_OPTS --cross-prefix=aarch64-linux-gnu-
+ENV DEF_TARGET_LIST aarch64-softmmu,aarch64-linux-user
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker
index d866fe5d75..15378f8ea2 100644
--- a/tests/docker/dockerfiles/debian-armel-cross.docker
+++ b/tests/docker/dockerfiles/debian-armel-cross.docker
@@ -11,10 +11,11 @@ RUN dpkg --add-architecture armel && \
apt update && \
apt install -yy crossbuild-essential-armel && \
DEBIAN_FRONTEND=noninteractive eatmydata \
- apt build-dep -yy -a armel qemu
+ apt build-dep -yy -a armel --arch-only qemu
# Specify the cross prefix for this image (see tests/docker/common.rc)
ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabi-
+ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker
index 2b8627673c..4a20af6fe1 100644
--- a/tests/docker/dockerfiles/debian-armhf-cross.docker
+++ b/tests/docker/dockerfiles/debian-armhf-cross.docker
@@ -13,10 +13,11 @@ RUN apt update && \
crossbuild-essential-armhf
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
- apt build-dep -yy -a armhf qemu
+ apt build-dep -yy -a armhf --arch-only qemu
# Specify the cross prefix for this image (see tests/docker/common.rc)
ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf-
+ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/debian-buster-arm64-cross.docker b/tests/docker/dockerfiles/debian-buster-arm64-cross.docker
deleted file mode 100644
index 52787edcc2..0000000000
--- a/tests/docker/dockerfiles/debian-buster-arm64-cross.docker
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Docker arm64 cross-compiler target
-#
-# This docker target builds on the Debian's Buster base image. There
-# are no QEMU pre-requistes so this image can only be used to build
-# test cases.
-#
-FROM qemu:debian10
-
-# Add the foreign architecture we want and install dependencies
-RUN dpkg --add-architecture arm64
-RUN apt update && \
- DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
- DEBIAN_FRONTEND=noninteractive eatmydata \
- apt-get install -y --no-install-recommends \
- crossbuild-essential-arm64
diff --git a/tests/docker/dockerfiles/debian-hppa-cross.docker b/tests/docker/dockerfiles/debian-hppa-cross.docker
index ee6d9a24ce..5c68b2d330 100644
--- a/tests/docker/dockerfiles/debian-hppa-cross.docker
+++ b/tests/docker/dockerfiles/debian-hppa-cross.docker
@@ -1,10 +1,9 @@
#
# Docker cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian-sid
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/debian-m68k-cross.docker b/tests/docker/dockerfiles/debian-m68k-cross.docker
index 4311c9cf86..25edc80e9a 100644
--- a/tests/docker/dockerfiles/debian-m68k-cross.docker
+++ b/tests/docker/dockerfiles/debian-m68k-cross.docker
@@ -1,10 +1,9 @@
#
# Docker cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian-sid
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/debian-mips-cross.docker b/tests/docker/dockerfiles/debian-mips-cross.docker
index 3c4d6f9ec1..08a8e1c29c 100644
--- a/tests/docker/dockerfiles/debian-mips-cross.docker
+++ b/tests/docker/dockerfiles/debian-mips-cross.docker
@@ -1,9 +1,9 @@
#
# Docker mips cross-compiler target
#
-# This docker target builds on the debian Stretch base image.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian9
+FROM qemu:debian10
MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
@@ -16,10 +16,11 @@ RUN apt update && \
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
- apt build-dep -yy -a mips qemu
+ apt build-dep -yy -a mips --arch-only qemu
# Specify the cross prefix for this image (see tests/docker/common.rc)
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips-linux-gnu-
+ENV DEF_TARGET_LIST mips-softmmu,mipsel-linux-user
# Install extra libraries to increase code coverage
RUN apt update && \
diff --git a/tests/docker/dockerfiles/debian-mips64-cross.docker b/tests/docker/dockerfiles/debian-mips64-cross.docker
index bf0073a466..1a79505d69 100644
--- a/tests/docker/dockerfiles/debian-mips64-cross.docker
+++ b/tests/docker/dockerfiles/debian-mips64-cross.docker
@@ -1,10 +1,9 @@
#
# Docker cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian-sid
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker
index 34b0b82895..2fca112405 100644
--- a/tests/docker/dockerfiles/debian-mips64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker
@@ -17,10 +17,11 @@ RUN dpkg --add-architecture mips64el && \
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
- apt build-dep -yy -a mips64el qemu
+ apt build-dep -yy -a mips64el --arch-only qemu
# Specify the cross prefix for this image (see tests/docker/common.rc)
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips64el-linux-gnuabi64-
+ENV DEF_TARGET_LIST mips64el-softmmu,mips64el-linux-user
# Install extra libraries to increase code coverage
RUN apt update && \
diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker
index 88accad269..4abf7832ac 100644
--- a/tests/docker/dockerfiles/debian-mipsel-cross.docker
+++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker
@@ -16,7 +16,7 @@ RUN apt update && \
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
- apt build-dep -yy -a mipsel qemu
+ apt build-dep -yy -a mipsel --arch-only qemu
# Specify the cross prefix for this image (see tests/docker/common.rc)
ENV QEMU_CONFIGURE_OPTS --cross-prefix=mipsel-linux-gnu-
diff --git a/tests/docker/dockerfiles/debian-powerpc-cross.docker b/tests/docker/dockerfiles/debian-powerpc-cross.docker
index 5d08fad7cd..89dd4fbf87 100644
--- a/tests/docker/dockerfiles/debian-powerpc-cross.docker
+++ b/tests/docker/dockerfiles/debian-powerpc-cross.docker
@@ -1,14 +1,12 @@
#
# Docker powerpc cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets. The original
-# Jessie based no longer builds.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian-sid
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
gcc-powerpc-linux-gnu \
- libc6-dev-powerpc-cross || { echo "Failed to build - see debian-sid.docker notes"; exit 1; }
+ libc6-dev-powerpc-cross
diff --git a/tests/docker/dockerfiles/debian-powerpc-user-cross.docker b/tests/docker/dockerfiles/debian-powerpc-user-cross.docker
index 6938a845ee..83749b0abb 100644
--- a/tests/docker/dockerfiles/debian-powerpc-user-cross.docker
+++ b/tests/docker/dockerfiles/debian-powerpc-user-cross.docker
@@ -8,8 +8,14 @@
# debootstrapped qemu:debian-powerpc-user but doesn't need any extra
# magic once it is setup.
#
+# It can be used to build old versions of QEMU, current versions need
+# newer dependencies than Jessie provides.
+#
FROM qemu:debian-powerpc-user
RUN echo man-db man-db/auto-update boolean false | debconf-set-selections
RUN apt-get update && \
- DEBIAN_FRONTEND=noninteractive apt-get build-dep -yy qemu
+ DEBIAN_FRONTEND=noninteractive apt-get build-dep -yy qemu
+
+ENV QEMU_CONFIGURE_OPTS --disable-werror
+ENV DEF_TARGET_LIST powerpc-softmmu,arm-linux-user,aarch64-linux-user
diff --git a/tests/docker/dockerfiles/debian-ppc64-cross.docker b/tests/docker/dockerfiles/debian-ppc64-cross.docker
index e5757fe46e..4bf88ab02d 100644
--- a/tests/docker/dockerfiles/debian-ppc64-cross.docker
+++ b/tests/docker/dockerfiles/debian-ppc64-cross.docker
@@ -1,12 +1,11 @@
#
# Docker ppc64 cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets.
-FROM qemu:debian-sid
+# This docker target builds on the debian Buster base image.
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
gcc-powerpc64-linux-gnu \
- libc6-dev-ppc64-cross || { echo "Failed to build - see debian-sid.docker notes"; exit 1; }
+ libc6-dev-ppc64-cross
diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
index fc056d7bc3..9973df9ff7 100644
--- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
@@ -12,10 +12,11 @@ RUN dpkg --add-architecture ppc64el && \
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
- apt build-dep -yy -a ppc64el qemu
+ apt build-dep -yy -a ppc64el --arch-only qemu
# Specify the cross prefix for this image (see tests/docker/common.rc)
ENV QEMU_CONFIGURE_OPTS --cross-prefix=powerpc64le-linux-gnu-
+ENV DEF_TARGET_LIST ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user
# Install extra libraries to increase code coverage
RUN apt update && \
diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker
index 221697f9d1..5e2d6ddb60 100644
--- a/tests/docker/dockerfiles/debian-riscv64-cross.docker
+++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker
@@ -1,10 +1,9 @@
#
# Docker cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian-sid
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker
index 6732f9ec78..eb73c98855 100644
--- a/tests/docker/dockerfiles/debian-s390x-cross.docker
+++ b/tests/docker/dockerfiles/debian-s390x-cross.docker
@@ -17,10 +17,11 @@ RUN apt update && \
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
- apt build-dep -yy -a s390x qemu
+ apt build-dep -yy -a s390x --arch-only qemu
# Specify the cross prefix for this image (see tests/docker/common.rc)
ENV QEMU_CONFIGURE_OPTS --cross-prefix=s390x-linux-gnu-
+ENV DEF_TARGET_LIST s390x-softmmu,s390x-linux-user
# Install extra libraries to increase code coverage
RUN apt update && \
diff --git a/tests/docker/dockerfiles/debian-sh4-cross.docker b/tests/docker/dockerfiles/debian-sh4-cross.docker
index 29983b2d75..9d7663764e 100644
--- a/tests/docker/dockerfiles/debian-sh4-cross.docker
+++ b/tests/docker/dockerfiles/debian-sh4-cross.docker
@@ -1,10 +1,9 @@
#
# Docker cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian-sid
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/debian-sid.docker b/tests/docker/dockerfiles/debian-sid.docker
index 513459ca7f..2a1bcc33b2 100644
--- a/tests/docker/dockerfiles/debian-sid.docker
+++ b/tests/docker/dockerfiles/debian-sid.docker
@@ -1,25 +1,19 @@
#
# Debian Sid Base
#
-# A number of our guests exist as ports only. We can either use the
-# ports repo or get everything from Sid. However Sid is a rolling
-# distro which may be broken at any particular time. If you are
-# unlucky and try and build your images while gcc is in the process of
-# being uploaded this can fail. Your only recourse is to try again in
-# a few hours when the repos have re-synced. Once built however you
-# won't be affected by repo changes unless the docker recipies are
-# updated and trigger a re-build.
+# Currently we can build all our guests with cross-compilers in the
+# latest Debian release (Buster). However new compilers will first
+# arrive in Sid. However Sid is a rolling distro which may be broken
+# at any particular time. To try and mitigate this we use Debian's
+# snapshot archive which provides a "stable" view of what state Sid
+# was in.
#
# This must be earlier than the snapshot date we are aiming for
-FROM debian:sid-20181011-slim
+FROM debian:sid-20190812-slim
-# Use a snapshot known to work (see http://snapshot.debian.org/#Usage)
-ENV DEBIAN_SNAPSHOT_DATE "20181030"
-RUN sed -i "s%^deb \(https\?://\)deb.debian.org/debian/\? \(.*\)%deb [check-valid-until=no] \1snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT_DATE} \2%" /etc/apt/sources.list
-
-# Use a snapshot known to work (see http://snapshot.debian.org/#Usage)
-ENV DEBIAN_SNAPSHOT_DATE "20181030"
+ # Use a snapshot known to work (see http://snapshot.debian.org/#Usage)
+ENV DEBIAN_SNAPSHOT_DATE "20190820"
RUN sed -i "s%^deb \(https\?://\)deb.debian.org/debian/\? \(.*\)%deb [check-valid-until=no] \1snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT_DATE} \2%" /etc/apt/sources.list
# Duplicate deb line as deb-src
diff --git a/tests/docker/dockerfiles/debian-sparc64-cross.docker b/tests/docker/dockerfiles/debian-sparc64-cross.docker
index 7a2c2ab19c..31fd34f120 100644
--- a/tests/docker/dockerfiles/debian-sparc64-cross.docker
+++ b/tests/docker/dockerfiles/debian-sparc64-cross.docker
@@ -1,10 +1,9 @@
#
# Docker cross-compiler target
#
-# This docker target builds on the debian sid base image which
-# contains cross compilers for Debian "ports" targets.
+# This docker target builds on the debian Buster base image.
#
-FROM qemu:debian-sid
+FROM qemu:debian10
RUN apt update && \
DEBIAN_FRONTEND=noninteractive eatmydata \
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 44bbf0f77a..883f9bcf31 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -56,3 +56,6 @@ RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES
RUN dpkg -l $PACKAGES | sort > /packages.txt
ENV FEATURES clang pyyaml sdl2
+
+# https://bugs.launchpad.net/qemu/+bug/1838763
+ENV QEMU_CONFIGURE_OPTS --disable-libssh
diff --git a/tests/docker/run b/tests/docker/run
index 1014871fec..8edc7026ee 100755
--- a/tests/docker/run
+++ b/tests/docker/run
@@ -62,7 +62,7 @@ echo "* Prepared to run command:"
echo " $CMD"
echo "* Hit Ctrl-D to continue, or type 'exit 1' to abort"
echo
-$SHELL --noprofile --norc
+env bash --noprofile --norc
if "$CMD"; then
exit 0
@@ -72,7 +72,7 @@ elif test -n "$DEBUG"; then
echo "* Hit Ctrl-D to exit"
echo
# Force error after shell exits
- $SHELL --noprofile --norc && exit 1
+ env bash --noprofile --norc && exit 1
else
exit 1
fi
diff --git a/tests/docker/test-build b/tests/docker/test-build
index 22766cfacc..2b2a7832f1 100755
--- a/tests/docker/test-build
+++ b/tests/docker/test-build
@@ -15,7 +15,6 @@
cd "$BUILD_DIR"
-DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu"
TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \
build_qemu
install_qemu
diff --git a/tests/docker/test-mingw b/tests/docker/test-mingw
index fdb1c2c879..c30eb654eb 100755
--- a/tests/docker/test-mingw
+++ b/tests/docker/test-mingw
@@ -16,7 +16,6 @@
requires mingw dtc
cd "$BUILD_DIR"
-DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu"
for prefix in x86_64-w64-mingw32- i686-w64-mingw32-; do
TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \
diff --git a/tests/docker/test-quick b/tests/docker/test-quick
index eee59c55fb..feee44b247 100755
--- a/tests/docker/test-quick
+++ b/tests/docker/test-quick
@@ -15,7 +15,6 @@
cd "$BUILD_DIR"
-DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu"
TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \
build_qemu
check_qemu
diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index 93628c588d..1a232a663a 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -26,7 +26,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu-common.h"
#include "libqos/pci-pc.h"
#include "qemu/sockets.h"
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 31cd3295c1..26b69f7c5c 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qapi/qmp/qdict.h"
#include "qemu-common.h"
diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c
index 69205b58a8..1f57d9684b 100644
--- a/tests/i440fx-test.c
+++ b/tests/i440fx-test.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "libqos/pci.h"
#include "libqos/pci-pc.h"
#include "hw/pci/pci_regs.h"
diff --git a/tests/i82801b11-test.c b/tests/i82801b11-test.c
index a6e31594c9..4345da338b 100644
--- a/tests/i82801b11-test.c
+++ b/tests/i82801b11-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/intel-hda-test.c b/tests/intel-hda-test.c
index b782b2e944..fc25ccc33c 100644
--- a/tests/intel-hda-test.c
+++ b/tests/intel-hda-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#define HDA_ID "hda0"
#define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \
diff --git a/tests/ioh3420-test.c b/tests/ioh3420-test.c
index b54c4b9f11..f6ca43cca7 100644
--- a/tests/ioh3420-test.c
+++ b/tests/ioh3420-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/ipmi-kcs-test.c b/tests/ipmi-kcs-test.c
index a2354c10c7..693a6aacb5 100644
--- a/tests/ipmi-kcs-test.c
+++ b/tests/ipmi-kcs-test.c
@@ -24,8 +24,7 @@
#include "qemu/osdep.h"
-
-#include "libqtest.h"
+#include "libqtest-single.h"
#define IPMI_IRQ 5
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index b76457948b..be9aa92a61 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -100,7 +100,6 @@ static inline void write_mem(IVState *s, uint64_t off,
static void cleanup_vm(IVState *s)
{
- assert(!global_qtest);
g_free(s->dev);
qtest_shutdown(s->qs);
}
@@ -388,7 +387,6 @@ static void test_ivshmem_hotplug(void)
qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1");
- global_qtest = qts; /* TODO: Get rid of global_qtest here */
qtest_qmp_device_add(qts, "ivshmem-plain", "iv1",
"{'addr': %s, 'memdev': 'mb1'}",
stringify(PCI_SLOT_HP));
@@ -397,7 +395,6 @@ static void test_ivshmem_hotplug(void)
}
qtest_quit(qts);
- global_qtest = NULL;
}
static void test_ivshmem_memdev(void)
diff --git a/tests/libqos/e1000e.c b/tests/libqos/e1000e.c
index 1d0592974e..560e7a2bb2 100644
--- a/tests/libqos/e1000e.c
+++ b/tests/libqos/e1000e.c
@@ -85,26 +85,32 @@ static uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg)
void e1000e_tx_ring_push(QE1000E *d, void *descr)
{
+ QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
uint32_t tail = e1000e_macreg_read(d, E1000E_TDT);
uint32_t len = e1000e_macreg_read(d, E1000E_TDLEN) / E1000E_TXD_LEN;
- memwrite(d->tx_ring + tail * E1000E_TXD_LEN, descr, E1000E_TXD_LEN);
+ qtest_memwrite(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000E_TXD_LEN,
+ descr, E1000E_TXD_LEN);
e1000e_macreg_write(d, E1000E_TDT, (tail + 1) % len);
/* Read WB data for the packet transmitted */
- memread(d->tx_ring + tail * E1000E_TXD_LEN, descr, E1000E_TXD_LEN);
+ qtest_memread(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000E_TXD_LEN,
+ descr, E1000E_TXD_LEN);
}
void e1000e_rx_ring_push(QE1000E *d, void *descr)
{
+ QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
uint32_t tail = e1000e_macreg_read(d, E1000E_RDT);
uint32_t len = e1000e_macreg_read(d, E1000E_RDLEN) / E1000E_RXD_LEN;
- memwrite(d->rx_ring + tail * E1000E_RXD_LEN, descr, E1000E_RXD_LEN);
+ qtest_memwrite(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000E_RXD_LEN,
+ descr, E1000E_RXD_LEN);
e1000e_macreg_write(d, E1000E_RDT, (tail + 1) % len);
/* Read WB data for the packet received */
- memread(d->rx_ring + tail * E1000E_RXD_LEN, descr, E1000E_RXD_LEN);
+ qtest_memread(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000E_RXD_LEN,
+ descr, E1000E_RXD_LEN);
}
static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
@@ -123,7 +129,7 @@ void e1000e_wait_isr(QE1000E *d, uint16_t msg_id)
if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) {
return;
}
- clock_step(10000);
+ qtest_clock_step(d_pci->pci_dev.bus->qts, 10000);
} while (g_get_monotonic_time() < end_time);
g_error("Timeout expired");
diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c
index 5f37b51129..d0047876a8 100644
--- a/tests/libqos/virtio-mmio.c
+++ b/tests/libqos/virtio-mmio.c
@@ -101,6 +101,18 @@ static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d)
return false;
}
+static void qvirtio_mmio_wait_config_isr_status(QVirtioDevice *d,
+ gint64 timeout_us)
+{
+ QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+ gint64 start_time = g_get_monotonic_time();
+
+ do {
+ g_assert(g_get_monotonic_time() - start_time <= timeout_us);
+ qtest_clock_step(dev->qts, 100);
+ } while (!qvirtio_mmio_get_config_isr_status(d));
+}
+
static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index)
{
QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
@@ -179,7 +191,7 @@ const QVirtioBus qvirtio_mmio = {
.get_status = qvirtio_mmio_get_status,
.set_status = qvirtio_mmio_set_status,
.get_queue_isr_status = qvirtio_mmio_get_queue_isr_status,
- .get_config_isr_status = qvirtio_mmio_get_config_isr_status,
+ .wait_config_isr_status = qvirtio_mmio_wait_config_isr_status,
.queue_select = qvirtio_mmio_queue_select,
.get_queue_size = qvirtio_mmio_get_queue_size,
.set_queue_address = qvirtio_mmio_set_queue_address,
diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index 3f55c047a0..50499e75ef 100644
--- a/tests/libqos/virtio-pci.c
+++ b/tests/libqos/virtio-pci.c
@@ -175,6 +175,18 @@ static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d)
}
}
+static void qvirtio_pci_wait_config_isr_status(QVirtioDevice *d,
+ gint64 timeout_us)
+{
+ QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
+ gint64 start_time = g_get_monotonic_time();
+
+ do {
+ g_assert(g_get_monotonic_time() - start_time <= timeout_us);
+ qtest_clock_step(dev->pdev->bus->qts, 100);
+ } while (!qvirtio_pci_get_config_isr_status(d));
+}
+
static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index)
{
QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
@@ -257,7 +269,7 @@ const QVirtioBus qvirtio_pci = {
.get_status = qvirtio_pci_get_status,
.set_status = qvirtio_pci_set_status,
.get_queue_isr_status = qvirtio_pci_get_queue_isr_status,
- .get_config_isr_status = qvirtio_pci_get_config_isr_status,
+ .wait_config_isr_status = qvirtio_pci_wait_config_isr_status,
.queue_select = qvirtio_pci_queue_select,
.get_queue_size = qvirtio_pci_get_queue_size,
.set_queue_address = qvirtio_pci_set_queue_address,
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index 91ce06954b..0ae9956fc8 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -82,13 +82,13 @@ void qvirtio_set_driver_ok(QVirtioDevice *d)
VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_ACKNOWLEDGE);
}
-void qvirtio_wait_queue_isr(QVirtioDevice *d,
+void qvirtio_wait_queue_isr(QTestState *qts, QVirtioDevice *d,
QVirtQueue *vq, gint64 timeout_us)
{
gint64 start_time = g_get_monotonic_time();
for (;;) {
- clock_step(100);
+ qtest_clock_step(qts, 100);
if (d->bus->get_queue_isr_status(d, vq)) {
return;
}
@@ -109,8 +109,8 @@ uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d,
gint64 start_time = g_get_monotonic_time();
uint8_t val;
- while ((val = readb(addr)) == 0xff) {
- clock_step(100);
+ while ((val = qtest_readb(qts, addr)) == 0xff) {
+ qtest_clock_step(qts, 100);
g_assert(!d->bus->get_queue_isr_status(d, vq));
g_assert(g_get_monotonic_time() - start_time <= timeout_us);
}
@@ -137,7 +137,7 @@ void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d,
for (;;) {
uint32_t got_desc_idx;
- clock_step(100);
+ qtest_clock_step(qts, 100);
if (d->bus->get_queue_isr_status(d, vq) &&
qvirtqueue_get_buf(qts, vq, &got_desc_idx, len)) {
@@ -151,15 +151,7 @@ void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d,
void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us)
{
- gint64 start_time = g_get_monotonic_time();
-
- for (;;) {
- clock_step(100);
- if (d->bus->get_config_isr_status(d)) {
- return;
- }
- g_assert(g_get_monotonic_time() - start_time <= timeout_us);
- }
+ d->bus->wait_config_isr_status(d, timeout_us);
}
void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq,
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 037176dbd8..2cb2448f46 100644
--- a/tests/libqos/virtio.h
+++ b/tests/libqos/virtio.h
@@ -69,8 +69,8 @@ struct QVirtioBus {
/* Get the queue ISR status of the device */
bool (*get_queue_isr_status)(QVirtioDevice *d, QVirtQueue *vq);
- /* Get the configuration ISR status of the device */
- bool (*get_config_isr_status)(QVirtioDevice *d);
+ /* Wait for the configuration ISR status of the device */
+ void (*wait_config_isr_status)(QVirtioDevice *d, gint64 timeout_us);
/* Select a queue to work on */
void (*queue_select)(QVirtioDevice *d, uint16_t index);
@@ -112,7 +112,7 @@ void qvirtio_set_acknowledge(QVirtioDevice *d);
void qvirtio_set_driver(QVirtioDevice *d);
void qvirtio_set_driver_ok(QVirtioDevice *d);
-void qvirtio_wait_queue_isr(QVirtioDevice *d,
+void qvirtio_wait_queue_isr(QTestState *qts, QVirtioDevice *d,
QVirtQueue *vq, gint64 timeout_us);
uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d,
QVirtQueue *vq,
diff --git a/tests/libqtest-single.h b/tests/libqtest-single.h
new file mode 100644
index 0000000000..6f1bb1331c
--- /dev/null
+++ b/tests/libqtest-single.h
@@ -0,0 +1,315 @@
+/*
+ * QTest - wrappers for test with single QEMU instances
+ *
+ * Copyright IBM, Corp. 2012
+ * Copyright Red Hat, Inc. 2012
+ * Copyright SUSE LINUX Products GmbH 2013
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef LIBQTEST_SINGLE_H
+#define LIBQTEST_SINGLE_H
+
+#include "libqtest.h"
+
+QTestState *global_qtest __attribute__((common, weak));
+
+/**
+ * qtest_start:
+ * @args: other arguments to pass to QEMU
+ *
+ * Start QEMU and assign the resulting #QTestState to a global variable.
+ * The global variable is used by "shortcut" functions documented below.
+ *
+ * Returns: #QTestState instance.
+ */
+static inline QTestState *qtest_start(const char *args)
+{
+ global_qtest = qtest_init(args);
+ return global_qtest;
+}
+
+/**
+ * qtest_end:
+ *
+ * Shut down the QEMU process started by qtest_start().
+ */
+static inline void qtest_end(void)
+{
+ if (!global_qtest) {
+ return;
+ }
+ qtest_quit(global_qtest);
+ global_qtest = NULL;
+}
+
+/**
+ * qmp:
+ * @fmt...: QMP message to send to qemu, formatted like
+ * qobject_from_jsonf_nofail(). See parse_escape() for what's
+ * supported after '%'.
+ *
+ * Sends a QMP message to QEMU and returns the response.
+ */
+GCC_FMT_ATTR(1, 2)
+static inline QDict *qmp(const char *fmt, ...)
+{
+ va_list ap;
+ QDict *response;
+
+ va_start(ap, fmt);
+ response = qtest_vqmp(global_qtest, fmt, ap);
+ va_end(ap);
+ return response;
+}
+
+/**
+ * qmp_eventwait:
+ * @s: #event event to wait for.
+ *
+ * Continuously polls for QMP responses until it receives the desired event.
+ */
+static inline void qmp_eventwait(const char *event)
+{
+ return qtest_qmp_eventwait(global_qtest, event);
+}
+
+/**
+ * get_irq:
+ * @num: Interrupt to observe.
+ *
+ * Returns: The level of the @num interrupt.
+ */
+static inline bool get_irq(int num)
+{
+ return qtest_get_irq(global_qtest, num);
+}
+
+/**
+ * outb:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write an 8-bit value to an I/O port.
+ */
+static inline void outb(uint16_t addr, uint8_t value)
+{
+ qtest_outb(global_qtest, addr, value);
+}
+
+/**
+ * outw:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 16-bit value to an I/O port.
+ */
+static inline void outw(uint16_t addr, uint16_t value)
+{
+ qtest_outw(global_qtest, addr, value);
+}
+
+/**
+ * outl:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 32-bit value to an I/O port.
+ */
+static inline void outl(uint16_t addr, uint32_t value)
+{
+ qtest_outl(global_qtest, addr, value);
+}
+
+/**
+ * inb:
+ * @addr: I/O port to read from.
+ *
+ * Reads an 8-bit value from an I/O port.
+ *
+ * Returns: Value read.
+ */
+static inline uint8_t inb(uint16_t addr)
+{
+ return qtest_inb(global_qtest, addr);
+}
+
+/**
+ * inw:
+ * @addr: I/O port to read from.
+ *
+ * Reads a 16-bit value from an I/O port.
+ *
+ * Returns: Value read.
+ */
+static inline uint16_t inw(uint16_t addr)
+{
+ return qtest_inw(global_qtest, addr);
+}
+
+/**
+ * inl:
+ * @addr: I/O port to read from.
+ *
+ * Reads a 32-bit value from an I/O port.
+ *
+ * Returns: Value read.
+ */
+static inline uint32_t inl(uint16_t addr)
+{
+ return qtest_inl(global_qtest, addr);
+}
+
+/**
+ * writeb:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes an 8-bit value to guest memory.
+ */
+static inline void writeb(uint64_t addr, uint8_t value)
+{
+ qtest_writeb(global_qtest, addr, value);
+}
+
+/**
+ * writew:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 16-bit value to guest memory.
+ */
+static inline void writew(uint64_t addr, uint16_t value)
+{
+ qtest_writew(global_qtest, addr, value);
+}
+
+/**
+ * writel:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 32-bit value to guest memory.
+ */
+static inline void writel(uint64_t addr, uint32_t value)
+{
+ qtest_writel(global_qtest, addr, value);
+}
+
+/**
+ * writeq:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 64-bit value to guest memory.
+ */
+static inline void writeq(uint64_t addr, uint64_t value)
+{
+ qtest_writeq(global_qtest, addr, value);
+}
+
+/**
+ * readb:
+ * @addr: Guest address to read from.
+ *
+ * Reads an 8-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint8_t readb(uint64_t addr)
+{
+ return qtest_readb(global_qtest, addr);
+}
+
+/**
+ * readw:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 16-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint16_t readw(uint64_t addr)
+{
+ return qtest_readw(global_qtest, addr);
+}
+
+/**
+ * readl:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 32-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint32_t readl(uint64_t addr)
+{
+ return qtest_readl(global_qtest, addr);
+}
+
+/**
+ * readq:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 64-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint64_t readq(uint64_t addr)
+{
+ return qtest_readq(global_qtest, addr);
+}
+
+/**
+ * memread:
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer.
+ */
+static inline void memread(uint64_t addr, void *data, size_t size)
+{
+ qtest_memread(global_qtest, addr, data, size);
+}
+
+/**
+ * memwrite:
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory.
+ */
+static inline void memwrite(uint64_t addr, const void *data, size_t size)
+{
+ qtest_memwrite(global_qtest, addr, data, size);
+}
+
+/**
+ * clock_step_next:
+ *
+ * Advance the QEMU_CLOCK_VIRTUAL to the next deadline.
+ *
+ * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
+ */
+static inline int64_t clock_step_next(void)
+{
+ return qtest_clock_step_next(global_qtest);
+}
+
+/**
+ * clock_step:
+ * @step: Number of nanoseconds to advance the clock by.
+ *
+ * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds.
+ *
+ * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
+ */
+static inline int64_t clock_step(int64_t step)
+{
+ return qtest_clock_step(global_qtest, step);
+}
+
+#endif
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 2713b86cf7..0a6b91737e 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -35,8 +35,6 @@
#define SOCKET_TIMEOUT 50
#define SOCKET_MAX_FDS 16
-QTestState *global_qtest;
-
struct QTestState
{
int fd;
@@ -1106,17 +1104,6 @@ void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size)
qtest_rsp(s, 0);
}
-QDict *qmp(const char *fmt, ...)
-{
- va_list ap;
- QDict *response;
-
- va_start(ap, fmt);
- response = qtest_vqmp(global_qtest, fmt, ap);
- va_end(ap);
- return response;
-}
-
void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
{
va_list ap;
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 07ea35867c..c8cffe5d68 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -22,8 +22,6 @@
typedef struct QTestState QTestState;
-extern QTestState *global_qtest;
-
/**
* qtest_initf:
* @fmt...: Format for creating other arguments to pass to QEMU, formatted
@@ -629,45 +627,6 @@ void qtest_add_data_func_full(const char *str, void *data,
void qtest_add_abrt_handler(GHookFunc fn, const void *data);
/**
- * qtest_start:
- * @args: other arguments to pass to QEMU
- *
- * Start QEMU and assign the resulting #QTestState to a global variable.
- * The global variable is used by "shortcut" functions documented below.
- *
- * Returns: #QTestState instance.
- */
-static inline QTestState *qtest_start(const char *args)
-{
- global_qtest = qtest_init(args);
- return global_qtest;
-}
-
-/**
- * qtest_end:
- *
- * Shut down the QEMU process started by qtest_start().
- */
-static inline void qtest_end(void)
-{
- if (!global_qtest) {
- return;
- }
- qtest_quit(global_qtest);
- global_qtest = NULL;
-}
-
-/**
- * qmp:
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail(). See parse_escape() for what's
- * supported after '%'.
- *
- * Sends a QMP message to QEMU and returns the response.
- */
-QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
-
-/**
* qtest_qmp_assert_success:
* @qts: QTestState instance to operate on
* @fmt...: QMP message to send to qemu, formatted like
@@ -680,254 +639,6 @@ QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
GCC_FMT_ATTR(2, 3);
-/*
- * qmp_eventwait:
- * @s: #event event to wait for.
- *
- * Continuously polls for QMP responses until it receives the desired event.
- */
-static inline void qmp_eventwait(const char *event)
-{
- return qtest_qmp_eventwait(global_qtest, event);
-}
-
-/**
- * get_irq:
- * @num: Interrupt to observe.
- *
- * Returns: The level of the @num interrupt.
- */
-static inline bool get_irq(int num)
-{
- return qtest_get_irq(global_qtest, num);
-}
-
-/**
- * outb:
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write an 8-bit value to an I/O port.
- */
-static inline void outb(uint16_t addr, uint8_t value)
-{
- qtest_outb(global_qtest, addr, value);
-}
-
-/**
- * outw:
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write a 16-bit value to an I/O port.
- */
-static inline void outw(uint16_t addr, uint16_t value)
-{
- qtest_outw(global_qtest, addr, value);
-}
-
-/**
- * outl:
- * @addr: I/O port to write to.
- * @value: Value being written.
- *
- * Write a 32-bit value to an I/O port.
- */
-static inline void outl(uint16_t addr, uint32_t value)
-{
- qtest_outl(global_qtest, addr, value);
-}
-
-/**
- * inb:
- * @addr: I/O port to read from.
- *
- * Reads an 8-bit value from an I/O port.
- *
- * Returns: Value read.
- */
-static inline uint8_t inb(uint16_t addr)
-{
- return qtest_inb(global_qtest, addr);
-}
-
-/**
- * inw:
- * @addr: I/O port to read from.
- *
- * Reads a 16-bit value from an I/O port.
- *
- * Returns: Value read.
- */
-static inline uint16_t inw(uint16_t addr)
-{
- return qtest_inw(global_qtest, addr);
-}
-
-/**
- * inl:
- * @addr: I/O port to read from.
- *
- * Reads a 32-bit value from an I/O port.
- *
- * Returns: Value read.
- */
-static inline uint32_t inl(uint16_t addr)
-{
- return qtest_inl(global_qtest, addr);
-}
-
-/**
- * writeb:
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes an 8-bit value to guest memory.
- */
-static inline void writeb(uint64_t addr, uint8_t value)
-{
- qtest_writeb(global_qtest, addr, value);
-}
-
-/**
- * writew:
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 16-bit value to guest memory.
- */
-static inline void writew(uint64_t addr, uint16_t value)
-{
- qtest_writew(global_qtest, addr, value);
-}
-
-/**
- * writel:
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 32-bit value to guest memory.
- */
-static inline void writel(uint64_t addr, uint32_t value)
-{
- qtest_writel(global_qtest, addr, value);
-}
-
-/**
- * writeq:
- * @addr: Guest address to write to.
- * @value: Value being written.
- *
- * Writes a 64-bit value to guest memory.
- */
-static inline void writeq(uint64_t addr, uint64_t value)
-{
- qtest_writeq(global_qtest, addr, value);
-}
-
-/**
- * readb:
- * @addr: Guest address to read from.
- *
- * Reads an 8-bit value from guest memory.
- *
- * Returns: Value read.
- */
-static inline uint8_t readb(uint64_t addr)
-{
- return qtest_readb(global_qtest, addr);
-}
-
-/**
- * readw:
- * @addr: Guest address to read from.
- *
- * Reads a 16-bit value from guest memory.
- *
- * Returns: Value read.
- */
-static inline uint16_t readw(uint64_t addr)
-{
- return qtest_readw(global_qtest, addr);
-}
-
-/**
- * readl:
- * @addr: Guest address to read from.
- *
- * Reads a 32-bit value from guest memory.
- *
- * Returns: Value read.
- */
-static inline uint32_t readl(uint64_t addr)
-{
- return qtest_readl(global_qtest, addr);
-}
-
-/**
- * readq:
- * @addr: Guest address to read from.
- *
- * Reads a 64-bit value from guest memory.
- *
- * Returns: Value read.
- */
-static inline uint64_t readq(uint64_t addr)
-{
- return qtest_readq(global_qtest, addr);
-}
-
-/**
- * memread:
- * @addr: Guest address to read from.
- * @data: Pointer to where memory contents will be stored.
- * @size: Number of bytes to read.
- *
- * Read guest memory into a buffer.
- */
-static inline void memread(uint64_t addr, void *data, size_t size)
-{
- qtest_memread(global_qtest, addr, data, size);
-}
-
-/**
- * memwrite:
- * @addr: Guest address to write to.
- * @data: Pointer to the bytes that will be written to guest memory.
- * @size: Number of bytes to write.
- *
- * Write a buffer to guest memory.
- */
-static inline void memwrite(uint64_t addr, const void *data, size_t size)
-{
- qtest_memwrite(global_qtest, addr, data, size);
-}
-
-/**
- * clock_step_next:
- *
- * Advance the QEMU_CLOCK_VIRTUAL to the next deadline.
- *
- * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
- */
-static inline int64_t clock_step_next(void)
-{
- return qtest_clock_step_next(global_qtest);
-}
-
-/**
- * clock_step:
- * @step: Number of nanoseconds to advance the clock by.
- *
- * Advance the QEMU_CLOCK_VIRTUAL by @step nanoseconds.
- *
- * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
- */
-static inline int64_t clock_step(int64_t step)
-{
- return qtest_clock_step(global_qtest, step);
-}
-
QDict *qmp_fd_receive(int fd);
void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
const char *fmt, va_list ap) GCC_FMT_ATTR(4, 0);
diff --git a/tests/m25p80-test.c b/tests/m25p80-test.c
index 055f7246a8..50c6b79fb3 100644
--- a/tests/m25p80-test.c
+++ b/tests/m25p80-test.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include "qemu/bswap.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
/*
* ASPEED SPI Controller registers
diff --git a/tests/migration-test.c b/tests/migration-test.c
index b87ba99a9e..a9f81cc185 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -490,7 +490,7 @@ static void migrate(QTestState *who, const char *uri, const char *fmt, ...)
g_assert(!qdict_haskey(args, "uri"));
qdict_put_str(args, "uri", uri);
- rsp = qmp("{ 'execute': 'migrate', 'arguments': %p}", args);
+ rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
g_assert(qdict_haskey(rsp, "return"));
qobject_unref(rsp);
@@ -625,7 +625,7 @@ static int test_migrate_start(QTestState **from, QTestState **to,
cmd_dst = tmp;
}
- *from = qtest_start(cmd_src);
+ *from = qtest_init(cmd_src);
g_free(cmd_src);
*to = qtest_init(cmd_dst);
@@ -715,7 +715,7 @@ static void test_deprecated(void)
{
QTestState *from;
- from = qtest_start("-machine none");
+ from = qtest_init("-machine none");
deprecated_set_downtime(from, 0.12345);
deprecated_set_speed(from, 12345);
diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c
index 63d464048d..9fddc7d5f9 100644
--- a/tests/pnv-xscom-test.c
+++ b/tests/pnv-xscom-test.c
@@ -77,9 +77,15 @@ static void test_xscom_cfam_id(QTestState *qts, const PnvChip *chip)
static void test_cfam_id(const void *data)
{
const PnvChip *chip = data;
+ const char *machine = "powernv8";
QTestState *qts;
- qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model);
+ if (chip->chip_type == PNV_CHIP_POWER9) {
+ machine = "powernv9";
+ }
+
+ qts = qtest_initf("-M %s,accel=tcg -cpu %s",
+ machine, chip->cpu_model);
test_xscom_cfam_id(qts, chip);
qtest_quit(qts);
}
@@ -113,8 +119,14 @@ static void test_core(const void *data)
{
const PnvChip *chip = data;
QTestState *qts;
+ const char *machine = "powernv8";
+
+ if (chip->chip_type == PNV_CHIP_POWER9) {
+ machine = "powernv9";
+ }
- qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model);
+ qts = qtest_initf("-M %s,accel=tcg -cpu %s",
+ machine, chip->cpu_model);
test_xscom_core(qts, chip);
qtest_quit(qts);
}
diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002
index fd413bce48..1a0d411df5 100755
--- a/tests/qemu-iotests/002
+++ b/tests/qemu-iotests/002
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto generic
+_unsupported_imgopts "subformat=streamOptimized"
size=128M
diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003
index ccd3a39dfb..33eeade0de 100755
--- a/tests/qemu-iotests/003
+++ b/tests/qemu-iotests/003
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto generic
+_unsupported_imgopts "subformat=streamOptimized"
size=128M
offset=67M
diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
index 9c7681c19b..58442762fe 100755
--- a/tests/qemu-iotests/005
+++ b/tests/qemu-iotests/005
@@ -43,7 +43,8 @@ _supported_fmt generic
_supported_proto generic
_supported_os Linux
_unsupported_imgopts "subformat=twoGbMaxExtentFlat" \
- "subformat=twoGbMaxExtentSparse"
+ "subformat=twoGbMaxExtentSparse" \
+ "subformat=streamOptimized"
# vpc is limited to 127GB, so we can't test it here
if [ "$IMGFMT" = "vpc" ]; then
diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009
index 51b200db1d..4dc7d210f9 100755
--- a/tests/qemu-iotests/009
+++ b/tests/qemu-iotests/009
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto generic
+_unsupported_imgopts "subformat=streamOptimized"
size=6G
diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010
index 48c533f632..df809b3088 100755
--- a/tests/qemu-iotests/010
+++ b/tests/qemu-iotests/010
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto generic
+_unsupported_imgopts "subformat=streamOptimized"
size=6G
diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011
index 56f704b5b9..57b99ae4a9 100755
--- a/tests/qemu-iotests/011
+++ b/tests/qemu-iotests/011
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto generic
+_unsupported_imgopts "subformat=streamOptimized"
size=6G
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
index 79875de454..0a4b854e65 100755
--- a/tests/qemu-iotests/017
+++ b/tests/qemu-iotests/017
@@ -41,7 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow qcow2 vmdk qed
_supported_proto generic
_unsupported_proto vxhs
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
+ "subformat=streamOptimized"
TEST_OFFSETS="0 4294967296"
diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018
index 78169838ba..c69ce09209 100755
--- a/tests/qemu-iotests/018
+++ b/tests/qemu-iotests/018
@@ -41,7 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow qcow2 vmdk qed
_supported_proto file
_supported_os Linux
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
+ "streamOptimized"
TEST_OFFSETS="0 4294967296"
diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019
index a56dd30bed..b4f5234609 100755
--- a/tests/qemu-iotests/019
+++ b/tests/qemu-iotests/019
@@ -47,7 +47,8 @@ _supported_proto file
_supported_os Linux
_unsupported_imgopts "subformat=monolithicFlat" \
"subformat=twoGbMaxExtentFlat" \
- "subformat=twoGbMaxExtentSparse"
+ "subformat=twoGbMaxExtentSparse" \
+ "subformat=streamOptimized"
TEST_OFFSETS="0 4294967296"
CLUSTER_SIZE=65536
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
index 6b0ebb37d2..f41b92f35f 100755
--- a/tests/qemu-iotests/020
+++ b/tests/qemu-iotests/020
@@ -44,7 +44,8 @@ _supported_fmt qcow qcow2 vmdk qed
_supported_proto file
_unsupported_imgopts "subformat=monolithicFlat" \
"subformat=twoGbMaxExtentFlat" \
- "subformat=twoGbMaxExtentSparse"
+ "subformat=twoGbMaxExtentSparse" \
+ "subformat=streamOptimized"
TEST_OFFSETS="0 4294967296"
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index e30243608b..ffb18ab6b5 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -41,8 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
# Currently only qcow2 supports rebasing
_supported_fmt qcow2
_supported_proto file
-_default_cache_mode "writethrough"
-_supported_cache_modes "writethrough" "none"
+_default_cache_mode writethrough
+_supported_cache_modes writethrough none
# The refcount table tests expect a certain minimum width for refcount entries
# (so that the refcount table actually needs to grow); that minimum is 16 bits,
# being the default refcount entry width.
diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027
index 4cb638022a..494be0921f 100755
--- a/tests/qemu-iotests/027
+++ b/tests/qemu-iotests/027
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt vmdk qcow qcow2 qed
_supported_proto generic
+_unsupported_imgopts "subformat=streamOptimized"
size=128M
diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032
index 988a8c5d8f..8337a4d825 100755
--- a/tests/qemu-iotests/032
+++ b/tests/qemu-iotests/032
@@ -42,6 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
# This works for any image format (though unlikely to segfault for raw)
_supported_fmt generic
_supported_proto generic
+_unsupported_imgopts "subformat=streamOptimized"
echo
echo === Prepare image ===
diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
index 362a48c0a0..8b40991d55 100755
--- a/tests/qemu-iotests/033
+++ b/tests/qemu-iotests/033
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto generic
+_unsupported_imgopts "subformat=streamOptimized"
size=128M
diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034
index 324bed28c6..da4cea1571 100755
--- a/tests/qemu-iotests/034
+++ b/tests/qemu-iotests/034
@@ -41,7 +41,8 @@ _supported_proto file
_supported_os Linux
_unsupported_imgopts "subformat=monolithicFlat" \
"subformat=twoGbMaxExtentFlat" \
- "subformat=twoGbMaxExtentSparse"
+ "subformat=twoGbMaxExtentSparse" \
+ "subformat=streamOptimized"
CLUSTER_SIZE=4k
size=128M
diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037
index 4946b9be92..e6517acbd4 100755
--- a/tests/qemu-iotests/037
+++ b/tests/qemu-iotests/037
@@ -40,7 +40,8 @@ _supported_fmt qcow qcow2 vmdk qed
_supported_proto file
_unsupported_imgopts "subformat=monolithicFlat" \
"subformat=twoGbMaxExtentFlat" \
- "subformat=twoGbMaxExtentSparse"
+ "subformat=twoGbMaxExtentSparse" \
+ "subformat=streamOptimized"
CLUSTER_SIZE=4k
size=128M
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index 0d4e963bd4..7c730d94a7 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -42,8 +42,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
-_default_cache_mode "writethrough"
-_supported_cache_modes "writethrough"
+_default_cache_mode writethrough
+_supported_cache_modes writethrough
size=128M
diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052
index 6e2ecbfe21..45a140910d 100755
--- a/tests/qemu-iotests/052
+++ b/tests/qemu-iotests/052
@@ -40,7 +40,7 @@ _supported_fmt generic
_supported_proto file
# Don't do O_DIRECT on tmpfs
-_supported_cache_modes "writeback" "writethrough" "unsafe"
+_supported_cache_modes writeback writethrough unsafe
size=128M
_make_test_img $size
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
index 279aee6815..10bfbaecec 100755
--- a/tests/qemu-iotests/059
+++ b/tests/qemu-iotests/059
@@ -114,11 +114,41 @@ $QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2
echo
echo "=== Testing monolithicFlat with internally generated JSON file name ==="
+
+echo '--- blkdebug ---'
+# Should work, because bdrv_dirname() works fine with blkdebug
IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
-$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" 2>&1 \
- | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \
+ -c info \
+ 2>&1 \
+ | _filter_testdir | _filter_imgfmt | _filter_img_info
_cleanup_test_img
+echo '--- quorum ---'
+# Should not work, because bdrv_dirname() does not work with quorum
+IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
+cp "$TEST_IMG" "$TEST_IMG.orig"
+
+filename="json:{
+ \"driver\": \"$IMGFMT\",
+ \"file\": {
+ \"driver\": \"quorum\",
+ \"children\": [ {
+ \"driver\": \"file\",
+ \"filename\": \"$TEST_IMG\"
+ }, {
+ \"driver\": \"file\",
+ \"filename\": \"$TEST_IMG.orig\"
+ } ],
+ \"vote-threshold\": 1
+ } }"
+
+filename=$(echo "$filename" | tr '\n' ' ' | sed -e 's/\s\+/ /g')
+$QEMU_IMG info "$filename" 2>&1 \
+ | sed -e "s/'json:[^']*'/\$QUORUM_FILE/g" \
+ | _filter_testdir | _filter_imgfmt | _filter_img_info
+
+
echo
echo "=== Testing version 3 ==="
_use_sample_img iotest-version3.vmdk.bz2
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index 4fab42a28c..39bf7e211d 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -13,21 +13,21 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big
=== Testing monolithicFlat creation and opening ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 2 GiB (2147483648 bytes)
=== Testing monolithicFlat with zeroed_grain ===
qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
=== Testing big twoGbMaxExtentFlat ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMaxExtentFlat
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000
image: TEST_DIR/t.vmdk
file format: vmdk
virtual size: 0.977 TiB (1073741824000 bytes)
-disk size: 16 KiB
+disk size: 1.97 MiB
Format specific information:
cid: XXXXXXXX
parent cid: XXXXXXXX
@@ -2038,7 +2038,7 @@ Format specific information:
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Invalid extent line: RW 12582912 VMFS "dummy.IMGFMT" 1
=== Testing truncated sparse ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 subformat=monolithicSparse
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes
=== Converting to streamOptimized from image with small cluster size===
@@ -2049,8 +2049,14 @@ wrote 512/512 bytes at offset 10240
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing monolithicFlat with internally generated JSON file name ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 subformat=monolithicFlat
-qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
+--- blkdebug ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+format name: IMGFMT
+cluster size: 0 bytes
+vm state offset: 0 bytes
+--- quorum ---
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+qemu-img: Could not open $QUORUM_FILE: Cannot use relative paths with VMDK descriptor file $QUORUM_FILE: Cannot generate a base directory for quorum nodes
=== Testing version 3 ===
image: TEST_DIR/iotest-version3.IMGFMT
@@ -2259,7 +2265,7 @@ read 512/512 bytes at offset 64931328
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing 4TB monolithicFlat creation and IO ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104 subformat=monolithicFlat
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 4 TiB (4398046511104 bytes)
@@ -2333,7 +2339,7 @@ read 1024/1024 bytes at offset 966367641600
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing qemu-img map on extents ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=monolithicSparse
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544
wrote 1024/1024 bytes at offset 65024
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 1024/1024 bytes at offset 2147483136
@@ -2344,7 +2350,7 @@ Offset Length Mapped to File
0 0x20000 0x3f0000 TEST_DIR/t.vmdk
0x7fff0000 0x20000 0x410000 TEST_DIR/t.vmdk
0x140000000 0x10000 0x430000 TEST_DIR/t.vmdk
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=twoGbMaxExtentSparse
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544
wrote 1024/1024 bytes at offset 65024
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 1024/1024 bytes at offset 2147483136
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
index fe4892e467..7cf0427af4 100755
--- a/tests/qemu-iotests/063
+++ b/tests/qemu-iotests/063
@@ -43,7 +43,8 @@ _supported_fmt qcow qcow2 vmdk qed raw
_supported_proto file
_unsupported_imgopts "subformat=monolithicFlat" \
"subformat=twoGbMaxExtentFlat" \
- "subformat=twoGbMaxExtentSparse"
+ "subformat=twoGbMaxExtentSparse" \
+ "subformat=streamOptimized"
_make_test_img 4M
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
index 1cca9233d0..fab526666b 100755
--- a/tests/qemu-iotests/071
+++ b/tests/qemu-iotests/071
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
+_require_drivers blkdebug blkverify
do_run_qemu()
{
diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072
index 661b36da2d..f0b73e7e65 100755
--- a/tests/qemu-iotests/072
+++ b/tests/qemu-iotests/072
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt vpc vmdk vhdx vdi qed qcow2 qcow
_supported_proto file
+_unsupported_imgopts "subformat=streamOptimized"
IMG_SIZE=64M
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
index c418bab093..85acdf76d4 100755
--- a/tests/qemu-iotests/081
+++ b/tests/qemu-iotests/081
@@ -41,6 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt raw
_supported_proto file
_supported_os Linux
+_require_drivers quorum
do_run_qemu()
{
@@ -55,9 +56,6 @@ run_qemu()
| _filter_qemu_io | _filter_generated_node_ids
}
-test_quorum=$($QEMU_IMG --help|grep quorum)
-[ "$test_quorum" = "" ] && _supported_fmt quorum
-
quorum="driver=raw,file.driver=quorum,file.vote-threshold=2"
quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
index d62ef18a02..f4b44659ae 100755
--- a/tests/qemu-iotests/091
+++ b/tests/qemu-iotests/091
@@ -46,8 +46,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
-_default_cache_mode "none"
-_supported_cache_modes "writethrough" "none" "writeback"
+_default_cache_mode none
+_supported_cache_modes writethrough none writeback
size=1G
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
index ae02f27afe..c3cf66798a 100755
--- a/tests/qemu-iotests/099
+++ b/tests/qemu-iotests/099
@@ -42,6 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow qcow2 qed vdi vhdx vmdk vpc
_supported_proto file
_supported_os Linux
+_require_drivers blkdebug blkverify
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
"subformat=twoGbMaxExtentSparse"
diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105
index 3346e8cb25..4d55a2d3ef 100755
--- a/tests/qemu-iotests/105
+++ b/tests/qemu-iotests/105
@@ -39,7 +39,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2 vmdk vhdx qed
_supported_proto generic
_unsupported_imgopts "subformat=twoGbMaxExtentFlat" \
- "subformat=twoGbMaxExtentSparse"
+ "subformat=twoGbMaxExtentSparse" \
+ "subformat=streamOptimized"
echo
echo "creating large image"
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
index 2cdc7c8a72..2ef516baf1 100755
--- a/tests/qemu-iotests/110
+++ b/tests/qemu-iotests/110
@@ -40,7 +40,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
# Any format supporting backing files
_supported_fmt qed qcow qcow2 vmdk
_supported_proto file
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
+ "subformat=twoGbMaxExtentSparse"
TEST_IMG_REL=$(basename "$TEST_IMG")
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
index e9b4fbb009..2931a7550f 100755
--- a/tests/qemu-iotests/120
+++ b/tests/qemu-iotests/120
@@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto file
_unsupported_fmt luks
+_require_drivers raw
_make_test_img 64M
diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126
index 9b0dcf9255..b7fce1e59d 100755
--- a/tests/qemu-iotests/126
+++ b/tests/qemu-iotests/126
@@ -33,6 +33,8 @@ status=1 # failure is the default!
# Needs backing file support
_supported_fmt qcow qcow2 qed vmdk
+_unsupported_imgopts "subformat=monolithicFlat" \
+ "subformat=twoGbMaxExtentFlat"
# This is the default protocol (and we want to test the difference between
# colons which separate a protocol prefix from the rest and colons which are
# just part of the filename, so we cannot test protocols which require a prefix)
diff --git a/tests/qemu-iotests/150.out b/tests/qemu-iotests/150.out.qcow2
index 2a54e8dcfa..2a54e8dcfa 100644
--- a/tests/qemu-iotests/150.out
+++ b/tests/qemu-iotests/150.out.qcow2
diff --git a/tests/qemu-iotests/150.out.raw b/tests/qemu-iotests/150.out.raw
new file mode 100644
index 0000000000..3cdc7727a5
--- /dev/null
+++ b/tests/qemu-iotests/150.out.raw
@@ -0,0 +1,12 @@
+QA output created by 150
+
+=== Mapping sparse conversion ===
+
+Offset Length File
+0 0x1000 TEST_DIR/t.IMGFMT
+
+=== Mapping non-sparse conversion ===
+
+Offset Length File
+0 0x100000 TEST_DIR/t.IMGFMT
+*** done
diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162
index 4e5ed74fd5..2d719afbed 100755
--- a/tests/qemu-iotests/162
+++ b/tests/qemu-iotests/162
@@ -39,9 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.filter
_supported_fmt generic
-
-test_ssh=$($QEMU_IMG --help | grep '^Supported formats:.* ssh\( \|$\)')
-[ "$test_ssh" = "" ] && _notrun "ssh support required"
+_require_drivers ssh
echo
echo '=== NBD ==='
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
index 51e62c8276..55db2803ed 100755
--- a/tests/qemu-iotests/175
+++ b/tests/qemu-iotests/175
@@ -37,14 +37,33 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
# the file size. This function hides the resulting difference in the
# stat -c '%b' output.
# Parameter 1: Number of blocks an empty file occupies
-# Parameter 2: Image size in bytes
+# Parameter 2: Minimal number of blocks in an image
+# Parameter 3: Image size in bytes
_filter_blocks()
{
extra_blocks=$1
- img_size=$2
+ min_blocks=$2
+ img_size=$3
- sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \
- -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/"
+ sed -e "s/blocks=$min_blocks\\(\$\\|[^0-9]\\)/min allocation/" \
+ -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/"
+}
+
+# Resize image using block_resize.
+# Parameter 1: image path
+# Parameter 2: new size
+_block_resize()
+{
+ local path=$1
+ local size=$2
+
+ $QEMU -qmp stdio -nographic -nodefaults \
+ -blockdev file,node-name=file,filename=$path,cache.direct=on \
+ <<EOF
+{'execute': 'qmp_capabilities'}
+{'execute': 'block_resize', 'arguments': {'node-name': 'file', 'size': $size}}
+{'execute': 'quit'}
+EOF
}
# get standard environment, filters and checks
@@ -55,21 +74,37 @@ _supported_fmt raw
_supported_proto file
_supported_os Linux
+_default_cache_mode none
+_supported_cache_modes none directsync
+
size=$((1 * 1024 * 1024))
touch "$TEST_DIR/empty"
extra_blocks=$(stat -c '%b' "$TEST_DIR/empty")
+# We always write the first byte; check how many blocks this filesystem
+# allocates to match empty image alloation.
+printf "\0" > "$TEST_DIR/empty"
+min_blocks=$(stat -c '%b' "$TEST_DIR/empty")
+
echo
echo "== creating image with default preallocation =="
_make_test_img $size | _filter_imgfmt
-stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
+stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
for mode in off full falloc; do
echo
echo "== creating image with preallocation $mode =="
IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
- stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
+done
+
+for new_size in 4096 1048576; do
+ echo
+ echo "== resize empty image with block_resize =="
+ _make_test_img 0 | _filter_imgfmt
+ _block_resize $TEST_IMG $new_size >/dev/null
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $new_size
done
# success, all done
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
index 6d9a5ed84e..39c2ee0f62 100644
--- a/tests/qemu-iotests/175.out
+++ b/tests/qemu-iotests/175.out
@@ -2,17 +2,25 @@ QA output created by 175
== creating image with default preallocation ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
-size=1048576, nothing allocated
+size=1048576, min allocation
== creating image with preallocation off ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off
-size=1048576, nothing allocated
+size=1048576, min allocation
== creating image with preallocation full ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full
-size=1048576, everything allocated
+size=1048576, max allocation
== creating image with preallocation falloc ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
-size=1048576, everything allocated
+size=1048576, max allocation
+
+== resize empty image with block_resize ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
+size=4096, min allocation
+
+== resize empty image with block_resize ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
+size=1048576, min allocation
*** done
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
index 55a8dc926f..9e7d8c44df 100644
--- a/tests/qemu-iotests/178.out.qcow2
+++ b/tests/qemu-iotests/178.out.qcow2
@@ -101,7 +101,7 @@ converted image file size in bytes: 196608
== raw input image with data (human) ==
Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
-required size: 393216
+required size: 458752
fully allocated size: 1074135040
wrote 512/512 bytes at offset 512
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -257,7 +257,7 @@ converted image file size in bytes: 196608
Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
{
- "required": 393216,
+ "required": 458752,
"fully-allocated": 1074135040
}
wrote 512/512 bytes at offset 512
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
index cb0c181228..33dd8d2a4f 100755
--- a/tests/qemu-iotests/184
+++ b/tests/qemu-iotests/184
@@ -33,6 +33,7 @@ trap "exit \$status" 0 1 2 3 15
. ./common.filter
_supported_os Linux
+_require_drivers throttle
do_run_qemu()
{
diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186
index 5f6b18c150..3ea0442d44 100755
--- a/tests/qemu-iotests/186
+++ b/tests/qemu-iotests/186
@@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
+_require_drivers null-co
if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then
_notrun "Requires a PC machine"
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
index 383d7d7f61..1d4f6786db 100755
--- a/tests/qemu-iotests/197
+++ b/tests/qemu-iotests/197
@@ -53,6 +53,7 @@ _supported_fmt generic
_supported_proto generic
# LUKS support may be possible, but it complicates things.
_unsupported_fmt luks
+_unsupported_imgopts "subformat=streamOptimized"
echo
echo '=== Copy-on-read ==='
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
index 958c14f5a0..2eb377d682 100755
--- a/tests/qemu-iotests/215
+++ b/tests/qemu-iotests/215
@@ -50,6 +50,7 @@ _supported_fmt generic
_supported_proto generic
# LUKS support may be possible, but it complicates things.
_unsupported_fmt luks
+_unsupported_imgopts "subformat=streamOptimized"
echo
echo '=== Copy-on-read ==='
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
index 9f9dd52bb0..dca024a0c3 100644
--- a/tests/qemu-iotests/221.out
+++ b/tests/qemu-iotests/221.out
@@ -3,14 +3,18 @@ QA output created by 221
=== Check mapping of unaligned raw image ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537
-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
wrote 1/1 bytes at offset 65536
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
*** done
diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out
index d5201b2356..5d00398c11 100644
--- a/tests/qemu-iotests/223.out
+++ b/tests/qemu-iotests/223.out
@@ -40,7 +40,7 @@ exports available: 0
exports available: 2
export: 'n'
size: 4194304
- flags: 0x4ef ( readonly flush fua trim zeroes df cache )
+ flags: 0x58f ( readonly flush fua df multi cache )
min block: 1
opt block: 4096
max block: 33554432
@@ -49,7 +49,7 @@ exports available: 2
qemu:dirty-bitmap:b
export: 'n2'
size: 4194304
- flags: 0x4ed ( flush fua trim zeroes df cache )
+ flags: 0xced ( flush fua trim zeroes df cache fast-zero )
min block: 1
opt block: 4096
max block: 33554432
diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out
index 9b46284ab0..24321efa11 100644
--- a/tests/qemu-iotests/233.out
+++ b/tests/qemu-iotests/233.out
@@ -20,10 +20,10 @@ qemu-nbd: Denied by server for option 5 (starttls)
server reported: TLS not configured
== check plain client to TLS server fails ==
-qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply)
-server reported: Option 0x8 not permitted before TLS
-qemu-nbd: TLS negotiation required before option 8 (structured reply)
-server reported: Option 0x8 not permitted before TLS
+qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 7 (go)
+server reported: Option 0x7 not permitted before TLS
+qemu-nbd: TLS negotiation required before option 3 (list)
+server reported: Option 0x3 not permitted before TLS
== check TLS works ==
image: nbd://127.0.0.1:PORT
@@ -37,7 +37,7 @@ disk size: unavailable
exports available: 1
export: ''
size: 67108864
- flags: 0x4ed ( flush fua trim zeroes df cache )
+ flags: 0xced ( flush fua trim zeroes df cache fast-zero )
min block: 1
opt block: 4096
max block: 33554432
diff --git a/tests/qemu-iotests/251 b/tests/qemu-iotests/251
index 13f85de9cd..7918ba3559 100755
--- a/tests/qemu-iotests/251
+++ b/tests/qemu-iotests/251
@@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt generic
_supported_proto file
_supported_os Linux
+_unsupported_imgopts "subformat=streamOptimized"
if [ "$IMGOPTSSYNTAX" = "true" ]; then
# We use json:{} filenames here, so we cannot work with additional options.
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
index 607c0baa0b..3d08b305d7 100644
--- a/tests/qemu-iotests/253.out
+++ b/tests/qemu-iotests/253.out
@@ -3,12 +3,16 @@ QA output created by 253
=== Check mapping of unaligned raw image ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
wrote 65535/65535 bytes at offset 983040
63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index c24874ff4a..a58232eefb 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -581,13 +581,13 @@ export QEMU_PROG="$(type -p "$QEMU_PROG")"
case "$QEMU_PROG" in
*qemu-system-arm|*qemu-system-aarch64)
- export QEMU_OPTIONS="-nodefaults -machine virt,accel=qtest"
+ export QEMU_OPTIONS="-nodefaults -display none -machine virt,accel=qtest"
;;
*qemu-system-tricore)
- export QEMU_OPTIONS="-nodefaults -machine tricore_testboard,accel=qtest"
+ export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard,accel=qtest"
;;
*)
- export QEMU_OPTIONS="-nodefaults -machine accel=qtest"
+ export QEMU_OPTIONS="-nodefaults -display none -machine accel=qtest"
;;
esac
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 8e9235d6fe..445a1c23e0 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -130,8 +130,8 @@ _filter_img_create()
-e "s# compat6=\\(on\\|off\\)##g" \
-e "s# static=\\(on\\|off\\)##g" \
-e "s# zeroed_grain=\\(on\\|off\\)##g" \
- -e "s# subformat='[^']*'##g" \
- -e "s# adapter_type='[^']*'##g" \
+ -e "s# subformat=[^ ]*##g" \
+ -e "s# adapter_type=[^ ]*##g" \
-e "s# hwversion=[^ ]*##g" \
-e "s# lazy_refcounts=\\(on\\|off\\)##g" \
-e "s# block_size=[0-9]\\+##g" \
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 5502c3da2f..ee20be8920 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -520,5 +520,19 @@ _require_command()
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
}
+# Check that a set of drivers has been whitelisted in the QEMU binary
+#
+_require_drivers()
+{
+ available=$($QEMU -drive format=help | \
+ sed -e '/Supported formats:/!d' -e 's/Supported formats://')
+ for driver
+ do
+ if ! echo "$available" | grep -q " $driver\( \|$\)"; then
+ _notrun "$driver not available"
+ fi
+ done
+}
+
# make sure this script returns success
true
diff --git a/tests/qos-test.c b/tests/qos-test.c
index 3c0071b3b7..fd70d73ea5 100644
--- a/tests/qos-test.c
+++ b/tests/qos-test.c
@@ -18,7 +18,7 @@
#include "qemu/osdep.h"
#include <getopt.h>
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qstring.h"
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 3ae0e29ad7..bd1f7590ed 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -2,4 +2,4 @@
# in the tests/venv Python virtual environment. For more info,
# refer to: https://pip.pypa.io/en/stable/user_guide/#id1
avocado-framework==68.0
-paramiko
+paramiko==2.4.2
diff --git a/tests/rtas-test.c b/tests/rtas-test.c
index ee888676ed..167b42db38 100644
--- a/tests/rtas-test.c
+++ b/tests/rtas-test.c
@@ -14,7 +14,6 @@ static void test_rtas_get_time_of_day(void)
time_t t1, t2;
qs = qtest_spapr_boot("-machine pseries");
- global_qtest = qs->qts;
t1 = time(NULL);
ret = qrtas_get_time_of_day(qs->qts, &qs->alloc, &tm, &ns);
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index 509be707e3..6309b0ef6c 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/timer.h"
#include "hw/timer/mc146818rtc_regs.h"
diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c
index d6d0c24909..4506049264 100644
--- a/tests/rtl8139-test.c
+++ b/tests/rtl8139-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "libqos/pci-pc.h"
#include "qemu/timer.h"
#include "qemu-common.h"
diff --git a/tests/tcg/.gitignore b/tests/tcg/.gitignore
new file mode 100644
index 0000000000..84d7541b28
--- /dev/null
+++ b/tests/tcg/.gitignore
@@ -0,0 +1,5 @@
+# These are build artefacts which only appear when you are doing
+# builds directly in the source tree.
+config-*.mak
+*-softmmu/
+*-linux-user/
diff --git a/tests/tcg/Makefile.include b/tests/tcg/Makefile.include
deleted file mode 100644
index 73b5626fc5..0000000000
--- a/tests/tcg/Makefile.include
+++ /dev/null
@@ -1,88 +0,0 @@
-# -*- Mode: makefile -*-
-#
-# TCG tests (per-target rules)
-#
-# This Makefile fragment is included from the per-target
-# Makefile.target so will be invoked for each linux-user program we
-# build. We have two options for compiling, either using a configured
-# guest compiler or calling one of our docker images to do it for us.
-#
-
-# The per ARCH makefile, if it exists, holds extra information about
-# useful docker images or alternative compiler flags.
-
--include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.include
--include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.include
-
-GUEST_BUILD=
-TCG_MAKE=$(SRC_PATH)/tests/tcg/Makefile
-# Support installed Cross Compilers
-
-ifdef CROSS_CC_GUEST
-
-.PHONY: cross-build-guest-tests
-cross-build-guest-tests:
- $(call quiet-command, \
- (mkdir -p tests && cd tests && \
- $(MAKE) -f $(TCG_MAKE) CC=$(CROSS_CC_GUEST) \
- BUILD_STATIC=$(CROSS_CC_GUEST_STATIC) \
- EXTRA_CFLAGS=$(CROSS_CC_GUEST_CFLAGS)), \
- "BUILD","$(TARGET_NAME) guest-tests with $(CROSS_CC_GUEST)")
-
-GUEST_BUILD=cross-build-guest-tests
-
-endif
-
-# Support building with Docker
-
-ifeq ($(HAVE_USER_DOCKER)$(GUEST_BUILD),y)
-ifneq ($(DOCKER_IMAGE),)
-
-# We also need the Docker make rules to depend on
-include $(SRC_PATH)/tests/docker/Makefile.include
-
-DOCKER_COMPILE_CMD="$(DOCKER_SCRIPT) cc --user $(shell id -u) \
- --cc $(DOCKER_CROSS_COMPILER) \
- -i qemu:$(DOCKER_IMAGE) \
- -s $(SRC_PATH) -- "
-DOCKER_PREREQ=docker-image-$(DOCKER_IMAGE)
-
-.PHONY: docker-build-guest-tests
-docker-build-guest-tests: $(DOCKER_PREREQ)
- $(call quiet-command, \
- (mkdir -p tests && cd tests && \
- $(MAKE) -f $(TCG_MAKE) CC=$(DOCKER_COMPILE_CMD) \
- BUILD_STATIC=y \
- EXTRA_CFLAGS=$(DOCKER_CROSS_COMPILER_CFLAGS)), \
- "BUILD","$(TARGET_NAME) guest-tests with docker qemu:$(DOCKER_IMAGE)")
-
-GUEST_BUILD=docker-build-guest-tests
-
-endif
-endif
-
-# Final targets
-.PHONY: guest-tests
-
-ifneq ($(GUEST_BUILD),)
-guest-tests: $(GUEST_BUILD)
-
-run-guest-tests: guest-tests qemu-$(subst y,system-,$(CONFIG_SOFTMMU))$(TARGET_NAME)
- $(call quiet-command, \
- (cd tests && $(MAKE) -f $(TCG_MAKE) SPEED=$(SPEED) run), \
- "RUN", "tests for $(TARGET_NAME)")
-
-else
-guest-tests:
- $(call quiet-command, /bin/true, "BUILD", \
- "$(TARGET_NAME) guest-tests SKIPPED")
-
-run-guest-tests:
- $(call quiet-command, /bin/true, "RUN", \
- "tests for $(TARGET_NAME) SKIPPED")
-endif
-
-# It doesn't matter if these don't exits
-.PHONY: clean-guest-tests
-clean-guest-tests:
- rm -rf tests || echo "no $(TARGET_NAME) tests to remove"
diff --git a/tests/tcg/Makefile.prereqs b/tests/tcg/Makefile.prereqs
new file mode 100644
index 0000000000..7494b31b95
--- /dev/null
+++ b/tests/tcg/Makefile.prereqs
@@ -0,0 +1,18 @@
+# -*- Mode: makefile -*-
+#
+# TCG Compiler Probe
+#
+# This Makefile fragment is included multiple times in the main make
+# script to probe for available compilers. This is used to build up a
+# selection of required docker targets before we invoke a sub-make for
+# each target.
+
+DOCKER_IMAGE:=
+
+-include $(BUILD_DIR)/tests/tcg/config-$(PROBE_TARGET).mak
+
+ifneq ($(DOCKER_IMAGE),)
+build-tcg-tests-$(PROBE_TARGET): docker-image-$(DOCKER_IMAGE)
+$(BUILD_DIR)/tests/tcg/config_$(PROBE_TARGET).mak: config-host.mak
+config-host.mak: $(SRC_PATH)/tests/tcg/configure.sh
+endif
diff --git a/tests/tcg/Makefile.probe b/tests/tcg/Makefile.probe
deleted file mode 100644
index 9dc654663d..0000000000
--- a/tests/tcg/Makefile.probe
+++ /dev/null
@@ -1,31 +0,0 @@
-# -*- Mode: makefile -*-
-#
-# TCG Compiler Probe
-#
-# This Makefile fragment is included multiple times in the main make
-# script to probe for available compilers. This is used to build up a
-# selection of required docker targets before we invoke a sub-make for
-# each target.
-
-# First we need the target makefile which tells us the target architecture
--include $(BUILD_DIR)/$(PROBE_TARGET)/config-target.mak
-
-# Then we load up the target architecture makefiles which tell us
-# about the compilers
-CROSS_CC_GUEST:=
-DOCKER_IMAGE:=
-DOCKER_PREREQ:=
-
--include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.include
--include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.include
-
-ifndef CROSS_CC_GUEST
-ifneq ($(DOCKER_IMAGE),)
-DOCKER_PREREQ:=docker-image-$(DOCKER_IMAGE)
-endif
-endif
-
-# Clean-up
-# undefine TARGET_NAME
-# undefine TARGET_BASE_ARCH
-# undefine TARGET_ABI_DIR
diff --git a/tests/tcg/Makefile.qemu b/tests/tcg/Makefile.qemu
new file mode 100644
index 0000000000..9c23aeaa2a
--- /dev/null
+++ b/tests/tcg/Makefile.qemu
@@ -0,0 +1,95 @@
+# -*- Mode: makefile -*-
+#
+# TCG tests (per-target rules)
+#
+# This Makefile fragment is included from the build-tcg target, once
+# for each target we build. We have two options for compiling, either
+# using a configured guest compiler or calling one of our docker images
+# to do it for us.
+#
+
+include $(SRC_PATH)/rules.mak
+
+# The configure script fills in extra information about
+# useful docker images or alternative compiler flags.
+
+CROSS_CC_GUEST:=
+DOCKER_IMAGE:=
+-include $(BUILD_DIR)/tests/tcg/config-$(TARGET).mak
+
+GUEST_BUILD=
+TCG_MAKE=../Makefile.target
+
+# We also need the Docker make rules to depend on
+SKIP_DOCKER_BUILD=1
+include $(SRC_PATH)/tests/docker/Makefile.include
+
+# Support installed Cross Compilers
+
+ifdef CROSS_CC_GUEST
+
+.PHONY: cross-build-guest-tests
+cross-build-guest-tests:
+ $(call quiet-command, \
+ (mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \
+ $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC="$(CROSS_CC_GUEST)" \
+ SRC_PATH="$(SRC_PATH)" BUILD_STATIC=$(CROSS_CC_GUEST_STATIC) \
+ EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \
+ "BUILD","$(TARGET) guest-tests with $(CROSS_CC_GUEST)")
+
+GUEST_BUILD=cross-build-guest-tests
+
+endif
+
+# Support building with Docker
+
+ifneq ($(DOCKER_IMAGE),)
+
+DOCKER_COMPILE_CMD="$(DOCKER_SCRIPT) cc \
+ --cc $(DOCKER_CROSS_CC_GUEST) \
+ -i qemu:$(DOCKER_IMAGE) \
+ -s $(SRC_PATH) -- "
+
+.PHONY: docker-build-guest-tests
+docker-build-guest-tests: docker-image-$(DOCKER_IMAGE)
+ $(call quiet-command, \
+ (mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \
+ $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC=$(DOCKER_COMPILE_CMD) \
+ SRC_PATH="$(SRC_PATH)" BUILD_STATIC=y \
+ EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \
+ "BUILD","$(TARGET) guest-tests with docker qemu:$(DOCKER_IMAGE)")
+
+GUEST_BUILD=docker-build-guest-tests
+
+endif
+
+# Final targets
+all:
+ @echo "Do not invoke this Makefile directly"; exit 1
+
+.PHONY: guest-tests
+
+ifneq ($(GUEST_BUILD),)
+guest-tests: $(GUEST_BUILD)
+
+run-guest-tests: guest-tests
+ $(call quiet-command, \
+ (cd tests/tcg/$(TARGET) && \
+ $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" \
+ SRC_PATH="$(SRC_PATH)" SPEED=$(SPEED) run), \
+ "RUN", "tests for $(TARGET_NAME)")
+
+else
+guest-tests:
+ $(call quiet-command, /bin/true, "BUILD", \
+ "$(TARGET) guest-tests SKIPPED")
+
+run-guest-tests:
+ $(call quiet-command, /bin/true, "RUN", \
+ "tests for $(TARGET) SKIPPED")
+endif
+
+# It doesn't matter if these don't exits
+.PHONY: clean-guest-tests
+clean-guest-tests:
+ rm -rf tests/tcg/$(TARGET)
diff --git a/tests/tcg/Makefile b/tests/tcg/Makefile.target
index 9f56768624..8808beaf74 100644
--- a/tests/tcg/Makefile
+++ b/tests/tcg/Makefile.target
@@ -29,8 +29,9 @@
# We also expect to be in the tests build dir for the FOO-(linux-user|softmmu).
#
+all:
-include ../../config-host.mak
--include ../config-target.mak
+-include ../config-$(TARGET).mak
# for including , in command strings
COMMA := ,
@@ -62,12 +63,6 @@ CFLAGS=
QEMU_CFLAGS=
LDFLAGS=
-# The QEMU for this TARGET
-ifdef CONFIG_USER_ONLY
-QEMU=../qemu-$(TARGET_NAME)
-else
-QEMU=../qemu-system-$(TARGET_NAME)
-endif
QEMU_OPTS=
@@ -82,10 +77,7 @@ ifdef CONFIG_USER_ONLY
# The order we include is important. We include multiarch, base arch
# and finally arch if it's not the same as base arch.
-include $(SRC_PATH)/tests/tcg/multiarch/Makefile.target
--include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.target
-ifneq ($(TARGET_BASE_ARCH),$(TARGET_NAME))
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target
-endif
# Add the common build options
CFLAGS+=-Wall -O0 -g -fno-strict-aliasing
@@ -101,10 +93,7 @@ else
# are expected to provide their own build recipes.
-include $(SRC_PATH)/tests/tcg/minilib/Makefile.target
-include $(SRC_PATH)/tests/tcg/multiarch/system/Makefile.softmmu-target
--include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.softmmu-target
-ifneq ($(TARGET_BASE_ARCH),$(TARGET_NAME))
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.softmmu-target
-endif
endif
diff --git a/tests/tcg/aarch64/Makefile.include b/tests/tcg/aarch64/Makefile.include
deleted file mode 100644
index 5d4e4c6f99..0000000000
--- a/tests/tcg/aarch64/Makefile.include
+++ /dev/null
@@ -1,8 +0,0 @@
-# Makefile.include for AArch64 targets
-#
-# We don't have any bigendian build tools so we only use this for AArch64
-
-ifeq ($(TARGET_NAME),aarch64)
-DOCKER_IMAGE=debian-buster-arm64-cross
-DOCKER_CROSS_COMPILER=aarch64-linux-gnu-gcc
-endif
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index 2e560e4d08..4c4aaf61dd 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -22,11 +22,11 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
- $(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
- $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
memory: CFLAGS+=-DCHECK_UNALIGNED=1
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 31ba9cfcaa..e763dd9da3 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -2,12 +2,14 @@
#
# AArch64 specific tweaks
+ARM_SRC=$(SRC_PATH)/tests/tcg/arm
+VPATH += $(ARM_SRC)
+
AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64
VPATH += $(AARCH64_SRC)
-# we don't build any of the ARM tests
-AARCH64_TESTS=$(filter-out $(ARM_TESTS), $(TESTS))
-AARCH64_TESTS+=fcvt
+# we don't build any other ARM test
+AARCH64_TESTS=fcvt
fcvt: LDFLAGS+=-lm
@@ -16,6 +18,6 @@ run-fcvt: fcvt
$(call diff-out,$<,$(AARCH64_SRC)/fcvt.ref)
AARCH64_TESTS += pauth-1 pauth-2
-run-pauth-%: QEMU += -cpu max
+run-pauth-%: QEMU_OPTS += -cpu max
-TESTS:=$(AARCH64_TESTS)
+TESTS += $(AARCH64_TESTS)
diff --git a/tests/tcg/alpha/Makefile.include b/tests/tcg/alpha/Makefile.include
deleted file mode 100644
index c7dc48eadb..0000000000
--- a/tests/tcg/alpha/Makefile.include
+++ /dev/null
@@ -1,2 +0,0 @@
-DOCKER_IMAGE=debian-alpha-cross
-DOCKER_CROSS_COMPILER=alpha-linux-gnu-gcc
diff --git a/tests/tcg/alpha/Makefile.softmmu-target b/tests/tcg/alpha/Makefile.softmmu-target
index 3c0f34cc69..09193a62d6 100644
--- a/tests/tcg/alpha/Makefile.softmmu-target
+++ b/tests/tcg/alpha/Makefile.softmmu-target
@@ -22,11 +22,11 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
- $(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
- $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
memory: CFLAGS+=-DCHECK_UNALIGNED=0
diff --git a/tests/tcg/arm/Makefile.include b/tests/tcg/arm/Makefile.include
deleted file mode 100644
index 8e7eac008f..0000000000
--- a/tests/tcg/arm/Makefile.include
+++ /dev/null
@@ -1,8 +0,0 @@
-# Makefile.include for all ARM targets
-#
-# We don't have any bigendian build tools so we only use this for armhf
-
-ifeq ($(TARGET_NAME),arm)
-DOCKER_IMAGE=debian-armhf-cross
-DOCKER_CROSS_COMPILER=arm-linux-gnueabihf-gcc
-endif
diff --git a/tests/tcg/arm/Makefile.softmmu-target b/tests/tcg/arm/Makefile.softmmu-target
index 49d48d8a1c..231e9a57b4 100644
--- a/tests/tcg/arm/Makefile.softmmu-target
+++ b/tests/tcg/arm/Makefile.softmmu-target
@@ -3,8 +3,6 @@
# ARM SoftMMU tests - included from tests/tcg/Makefile
#
-ifeq ($(TARGET_ABI_DIR),arm)
-
ARM_SRC=$(SRC_PATH)/tests/tcg/arm
# Set search path for all sources
@@ -18,12 +16,10 @@ CFLAGS+=-Wl,--build-id=none -x assembler-with-cpp
LDFLAGS+=-nostdlib -N -static
%: %.S %.ld
- $(CC) $(CFLAGS) $(ASFLAGS) $< -o $@ $(LDFLAGS) -T $(ARM_SRC)/$@.ld
+ $(CC) $(CFLAGS) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) -T $(ARM_SRC)/$@.ld
# Specific Test Rules
test-armv6m-undef: EXTRA_CFLAGS+=-mcpu=cortex-m0
run-test-armv6m-undef: QEMU_OPTS+=-semihosting -M microbit -kernel
-
-endif
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
new file mode 100755
index 0000000000..6c4a471aea
--- /dev/null
+++ b/tests/tcg/configure.sh
@@ -0,0 +1,234 @@
+#! /bin/sh
+
+if test -z "$source_path"; then
+ echo Do not invoke this script directly. It is called
+ echo automatically by configure.
+ exit 1
+fi
+
+write_c_skeleton() {
+ cat > $TMPC <<EOF
+int main(void) { return 0; }
+EOF
+}
+
+has() {
+ command -v "$1" >/dev/null 2>&1
+}
+
+do_compiler() {
+ # Run the compiler, capturing its output to the log. First argument
+ # is compiler binary to execute.
+ local compiler="$1"
+ shift
+ if test -n "$BASH_VERSION"; then eval '
+ echo >>config.log "
+funcs: ${FUNCNAME[*]}
+lines: ${BASH_LINENO[*]}"
+ '; fi
+ echo $compiler "$@" >> config.log
+ $compiler "$@" >> config.log 2>&1 || return $?
+}
+
+
+TMPDIR1="config-temp"
+TMPC="${TMPDIR1}/qemu-conf.c"
+TMPE="${TMPDIR1}/qemu-conf.exe"
+
+container="no"
+if has "docker" || has "podman"; then
+ container=$($python $source_path/tests/docker/docker.py probe)
+fi
+
+# cross compilers defaults, can be overridden with --cross-cc-ARCH
+: ${cross_cc_aarch64="aarch64-linux-gnu-gcc"}
+: ${cross_cc_aarch64_be="$cross_cc_aarch64"}
+: ${cross_cc_cflags_aarch64_be="-mbig-endian"}
+: ${cross_cc_arm="arm-linux-gnueabihf-gcc"}
+: ${cross_cc_cflags_armeb="-mbig-endian"}
+: ${cross_cc_i386="i386-pc-linux-gnu-gcc"}
+: ${cross_cc_cflags_i386="-m32"}
+: ${cross_cc_x86_64="x86_64-pc-linux-gnu-gcc"}
+: ${cross_cc_cflags_x86_64="-m64"}
+: ${cross_cc_ppc="powerpc-linux-gnu-gcc"}
+: ${cross_cc_cflags_ppc="-m32"}
+: ${cross_cc_ppc64="powerpc-linux-gnu-gcc"}
+: ${cross_cc_cflags_ppc64="-m64"}
+: ${cross_cc_ppc64le="powerpc64le-linux-gnu-gcc"}
+: ${cross_cc_cflags_s390x="-m64"}
+: ${cross_cc_cflags_sparc="-m32 -mv8plus -mcpu=ultrasparc"}
+: ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"}
+
+for target in $target_list; do
+ arch=${target%%-*}
+ case $arch in
+ arm|armeb)
+ arches=arm
+ ;;
+ aarch64|aarch64_be)
+ arches="aarch64 arm"
+ ;;
+ mips*)
+ arches=mips
+ ;;
+ ppc*)
+ arches=ppc
+ ;;
+ sh4|sh4eb)
+ arches=sh4
+ ;;
+ x86_64)
+ arches="x86_64 i386"
+ ;;
+ xtensa|xtensaeb)
+ arches=xtensa
+ ;;
+ alpha|cris|hppa|i386|lm32|m68k|openrisc|riscv64|s390x|sh4|sparc64)
+ arches=$target
+ ;;
+ *)
+ continue
+ ;;
+ esac
+
+ container_image=
+ case $target in
+ aarch64-*)
+ # We don't have any bigendian build tools so we only use this for AArch64
+ container_image=debian-arm64-cross
+ container_cross_cc=aarch64-linux-gnu-gcc
+ ;;
+ alpha-*)
+ container_image=debian-alpha-cross
+ container_cross_cc=alpha-linux-gnu-gcc
+ ;;
+ arm-*)
+ # We don't have any bigendian build tools so we only use this for ARM
+ container_image=debian-armhf-cross
+ container_cross_cc=arm-linux-gnueabihf-gcc
+ ;;
+ cris-*)
+ container_image=fedora-cris-cross
+ container_cross_cc=cris-linux-gnu-gcc
+ ;;
+ hppa-*)
+ container_image=debian-hppa-cross
+ container_cross_cc=hppa-linux-gnu-gcc
+ ;;
+ i386-*)
+ container_image=fedora-i386-cross
+ container_cross_cc=gcc
+ ;;
+ m68k-*)
+ container_image=debian-m68k-cross
+ container_cross_cc=m68k-linux-gnu-gcc
+ ;;
+ mips64el-*)
+ container_image=debian-mips64el-cross
+ container_cross_cc=mips64el-linux-gnuabi64-gcc
+ ;;
+ mips64-*)
+ container_image=debian-mips64-cross
+ container_cross_cc=mips64-linux-gnuabi64-gcc
+ ;;
+ mipsel-*)
+ container_image=debian-mipsel-cross
+ container_cross_cc=mipsel-linux-gnu-gcc
+ ;;
+ mips-*)
+ container_image=debian-mips-cross
+ container_cross_cc=mips-linux-gnu-gcc
+ ;;
+ ppc-*|ppc64abi32-*)
+ container_image=debian-powerpc-cross
+ container_cross_cc=powerpc-linux-gnu-gcc
+ ;;
+ ppc64-*)
+ container_image=debian-ppc64-cross
+ container_cross_cc=powerpc64-linux-gnu-gcc
+ ;;
+ ppc64le-*)
+ container_image=debian-ppc64el-cross
+ container_cross_cc=powerpc64le-linux-gnu-gcc
+ ;;
+ riscv64-*)
+ container_image=debian-riscv64-cross
+ container_cross_cc=riscv64-linux-gnu-gcc
+ ;;
+ s390x-*)
+ container_image=debian-s390x-cross
+ container_cross_cc=s390x-linux-gnu-gcc
+ ;;
+ sh4-*)
+ container_image=debian-sh4-cross
+ container_cross_cc=sh4-linux-gnu-gcc
+ ;;
+ sparc64-*)
+ container_image=debian-sparc64-cross
+ container_cross_cc=sparc64-linux-gnu-gcc
+ ;;
+ xtensa*-softmmu)
+ container_image=debian-xtensa-cross
+
+ # default to the dc232b cpu
+ container_cross_cc=/opt/2018.02/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc
+ ;;
+ esac
+
+ config_target_mak=tests/tcg/config-$target.mak
+
+ echo "# Automatically generated by configure - do not modify" > $config_target_mak
+ echo "TARGET_NAME=$arch" >> $config_target_mak
+ case $target in
+ *-linux-user | *-bsd-user)
+ echo "CONFIG_USER_ONLY=y" >> $config_target_mak
+ echo "QEMU=\$(BUILD_DIR)/$target/qemu-$arch" >> $config_target_mak
+ ;;
+ *-softmmu)
+ echo "CONFIG_SOFTMMU=y" >> $config_target_mak
+ echo "QEMU=\$(BUILD_DIR)/$target/qemu-system-$arch" >> $config_target_mak
+ ;;
+ esac
+
+ eval "target_compiler_cflags=\${cross_cc_cflags_$arch}"
+ echo "CROSS_CC_GUEST_CFLAGS=$target_compiler_cflags" >> $config_target_mak
+
+ got_cross_cc=no
+ for i in $arch $arches; do
+ if eval test "x\${cross_cc_$i+yes}" != xyes; then
+ continue
+ fi
+
+ eval "target_compiler=\${cross_cc_$i}"
+ if ! has $target_compiler; then
+ continue
+ fi
+ write_c_skeleton
+ if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC -static ; then
+ # For host systems we might get away with building without -static
+ if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC ; then
+ continue
+ fi
+ echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak
+ else
+ echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak
+ fi
+ echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak
+ enabled_cross_compilers="$enabled_cross_compilers $target_compiler"
+ got_cross_cc=yes
+ break
+ done
+
+ if test $got_cross_cc = no && test "$container" != no && test -n "$container_image"; then
+ echo "DOCKER_IMAGE=$container_image" >> $config_target_mak
+ echo "DOCKER_CROSS_CC_GUEST=$container_cross_cc" >> $config_target_mak
+ fi
+done
+
+# report container support state
+echo "cross containers $container"
+
+if test -n "$enabled_cross_compilers"; then
+ echo
+ echo "NOTE: guest cross-compilers enabled:$enabled_cross_compilers"
+fi
diff --git a/tests/tcg/cris/Makefile.include b/tests/tcg/cris/Makefile.include
deleted file mode 100644
index 1c037824bf..0000000000
--- a/tests/tcg/cris/Makefile.include
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile.include for all CRIS targets
-#
-
-DOCKER_IMAGE=fedora-cris-cross
-DOCKER_CROSS_COMPILER=cris-linux-gnu-gcc
diff --git a/tests/tcg/hppa/Makefile.include b/tests/tcg/hppa/Makefile.include
deleted file mode 100644
index da2353430e..0000000000
--- a/tests/tcg/hppa/Makefile.include
+++ /dev/null
@@ -1,2 +0,0 @@
-DOCKER_IMAGE=debian-hppa-cross
-DOCKER_CROSS_COMPILER=hppa-linux-gnu-gcc
diff --git a/tests/tcg/i386/Makefile.include b/tests/tcg/i386/Makefile.include
deleted file mode 100644
index be1c3008dd..0000000000
--- a/tests/tcg/i386/Makefile.include
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile.include for all i386
-#
-# There is enough brokeness in x86_64 compilers that we don't default
-# to using the x86_64 system compiler for i386 binaries.
-#
-
-DOCKER_IMAGE=fedora-i386-cross
-DOCKER_CROSS_COMPILER=gcc
diff --git a/tests/tcg/i386/Makefile.softmmu-target b/tests/tcg/i386/Makefile.softmmu-target
index 0a4364868c..1c8790eecd 100644
--- a/tests/tcg/i386/Makefile.softmmu-target
+++ b/tests/tcg/i386/Makefile.softmmu-target
@@ -12,17 +12,9 @@ X64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/x86_64/system
# These objects provide the basic boot code and helper functions for all tests
CRT_OBJS=boot.o
-ifeq ($(TARGET_X86_64), y)
-CRT_PATH=$(X64_SYSTEM_SRC)
-CFLAGS=-march=x86-64
-LINK_SCRIPT=$(X64_SYSTEM_SRC)/kernel.ld
-LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_x86_64
-else
CRT_PATH=$(I386_SYSTEM_SRC)
-CFLAGS+=-m32
LINK_SCRIPT=$(I386_SYSTEM_SRC)/kernel.ld
LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_i386
-endif
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
@@ -32,11 +24,11 @@ TESTS+=$(MULTIARCH_TESTS)
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
- $(CC) $(CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
- $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
memory: CFLAGS+=-DCHECK_UNALIGNED=1
diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target
index d0eb7023e5..08c5736a4d 100644
--- a/tests/tcg/i386/Makefile.target
+++ b/tests/tcg/i386/Makefile.target
@@ -6,14 +6,11 @@ I386_SRC=$(SRC_PATH)/tests/tcg/i386
VPATH += $(I386_SRC)
I386_SRCS=$(notdir $(wildcard $(I386_SRC)/*.c))
-I386_TESTS=$(I386_SRCS:.c=)
-I386_ONLY_TESTS=$(filter-out test-i386-ssse3, $(I386_TESTS))
+ALL_X86_TESTS=$(I386_SRCS:.c=)
+I386_TESTS:=$(filter-out test-i386-ssse3, $(ALL_X86_TESTS))
+X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS))
# Update TESTS
-TESTS+=$(I386_ONLY_TESTS)
-
-ifneq ($(TARGET_NAME),x86_64)
-CFLAGS+=-m32
-endif
+TESTS=$(MULTIARCH_TESTS) $(I386_TESTS)
#
# hello-i386 is a barebones app
@@ -26,7 +23,7 @@ hello-i386: LDFLAGS+=-nostdlib
#
test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S test-i386.h test-i386-shift.h test-i386-muldiv.h
- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
+ $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ \
$(<D)/test-i386.c $(<D)/test-i386-code16.S $(<D)/test-i386-vm86.S -lm
ifeq ($(SPEED), slow)
diff --git a/tests/tcg/m68k/Makefile.include b/tests/tcg/m68k/Makefile.include
deleted file mode 100644
index cd7c6bf50d..0000000000
--- a/tests/tcg/m68k/Makefile.include
+++ /dev/null
@@ -1,2 +0,0 @@
-DOCKER_IMAGE=debian-m68k-cross
-DOCKER_CROSS_COMPILER=m68k-linux-gnu-gcc
diff --git a/tests/tcg/minilib/Makefile.target b/tests/tcg/minilib/Makefile.target
index 3ed8077d0f..c821d2806a 100644
--- a/tests/tcg/minilib/Makefile.target
+++ b/tests/tcg/minilib/Makefile.target
@@ -18,4 +18,4 @@ MINILIB_INC=-isystem $(SYSTEM_MINILIB_SRC)
.PRECIOUS: $(MINILIB_OBJS)
%.o: $(SYSTEM_MINILIB_SRC)/%.c
- $(CC) $(CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
diff --git a/tests/tcg/mips/Makefile.include b/tests/tcg/mips/Makefile.include
deleted file mode 100644
index 4a14fc078d..0000000000
--- a/tests/tcg/mips/Makefile.include
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Makefile.include for all MIPs targets
-#
-# As Debian doesn't support mip64 in big endian mode the only way to
-# build BE is to pass a working cross compiler to ./configure
-#
-
-ifeq ($(TARGET_NAME),mips64el)
-DOCKER_IMAGE=debian-mips64el-cross
-DOCKER_CROSS_COMPILER=mips64el-linux-gnuabi64-gcc
-else ifeq ($(TARGET_NAME),mips64)
-DOCKER_IMAGE=debian-mips64-cross
-DOCKER_CROSS_COMPILER=mips64-linux-gnuabi64-gcc
-else ifeq ($(TARGET_NAME),mipsel)
-DOCKER_IMAGE=debian-mipsel-cross
-DOCKER_CROSS_COMPILER=mipsel-linux-gnu-gcc
-else ifeq ($(TARGET_NAME),mips)
-DOCKER_IMAGE=debian-mips-cross
-DOCKER_CROSS_COMPILER=mips-linux-gnu-gcc
-endif
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index b77084c146..6b1e30e2fe 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -12,8 +12,13 @@ VPATH += $(MULTIARCH_SRC)
MULTIARCH_SRCS =$(notdir $(wildcard $(MULTIARCH_SRC)/*.c))
MULTIARCH_TESTS =$(MULTIARCH_SRCS:.c=)
+# FIXME: ppc64abi32 linux-test seems to have issues but the other basic tests work
+ifeq ($(TARGET_NAME),ppc64abi32)
+BROKEN_TESTS = linux-test
+endif
+
# Update TESTS
-TESTS +=$(MULTIARCH_TESTS)
+TESTS += $(filter-out $(BROKEN_TESTS), $(MULTIARCH_TESTS))
#
# The following are any additional rules needed to build things
diff --git a/tests/tcg/ppc/Makefile.include b/tests/tcg/ppc/Makefile.include
deleted file mode 100644
index ae01fb8fad..0000000000
--- a/tests/tcg/ppc/Makefile.include
+++ /dev/null
@@ -1,10 +0,0 @@
-ifeq ($(TARGET_NAME),ppc)
-DOCKER_IMAGE=debian-powerpc-cross
-DOCKER_CROSS_COMPILER=powerpc-linux-gnu-gcc
-else ifeq ($(TARGET_NAME),ppc64)
-DOCKER_IMAGE=debian-ppc64-cross
-DOCKER_CROSS_COMPILER=powerpc64-linux-gnu-gcc
-else ifeq ($(TARGET_NAME),ppc64le)
-DOCKER_IMAGE=debian-ppc64el-cross
-DOCKER_CROSS_COMPILER=powerpc64le-linux-gnu-gcc
-endif
diff --git a/tests/tcg/riscv/Makefile.include b/tests/tcg/riscv/Makefile.include
deleted file mode 100644
index d92ac6c89f..0000000000
--- a/tests/tcg/riscv/Makefile.include
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile.include for all RISCV targets
-#
-# Debian only really cares about 64 bit going forward
-#
-
-ifeq ($(TARGET_NAME),riscv64)
-DOCKER_IMAGE=debian-riscv64-cross
-DOCKER_CROSS_COMPILER=riscv64-linux-gnu-gcc
-endif
diff --git a/tests/tcg/s390x/Makefile.include b/tests/tcg/s390x/Makefile.include
deleted file mode 100644
index 1f58115d96..0000000000
--- a/tests/tcg/s390x/Makefile.include
+++ /dev/null
@@ -1,2 +0,0 @@
-DOCKER_IMAGE=debian-s390x-cross
-DOCKER_CROSS_COMPILER=s390x-linux-gnu-gcc
diff --git a/tests/tcg/sh4/Makefile.include b/tests/tcg/sh4/Makefile.include
deleted file mode 100644
index ad21594d9d..0000000000
--- a/tests/tcg/sh4/Makefile.include
+++ /dev/null
@@ -1,4 +0,0 @@
-ifneq ($(TARGET_NAME), sh4eb)
-DOCKER_IMAGE=debian-sh4-cross
-DOCKER_CROSS_COMPILER=sh4-linux-gnu-gcc
-endif
diff --git a/tests/tcg/sparc64/Makefile.include b/tests/tcg/sparc64/Makefile.include
deleted file mode 100644
index 95fc8dee9f..0000000000
--- a/tests/tcg/sparc64/Makefile.include
+++ /dev/null
@@ -1,2 +0,0 @@
-DOCKER_IMAGE=debian-sparc64-cross
-DOCKER_CROSS_COMPILER=sparc64-linux-gnu-gcc
diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target
new file mode 100644
index 0000000000..df252e761c
--- /dev/null
+++ b/tests/tcg/x86_64/Makefile.softmmu-target
@@ -0,0 +1,36 @@
+#
+# x86 system tests
+#
+# This currently builds only for i386. The common C code is built
+# with standard compiler flags however so we can support both by
+# adding additional boot files for x86_64.
+#
+
+I386_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/i386/system
+X64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/x86_64/system
+
+# These objects provide the basic boot code and helper functions for all tests
+CRT_OBJS=boot.o
+
+CRT_PATH=$(X64_SYSTEM_SRC)
+LINK_SCRIPT=$(X64_SYSTEM_SRC)/kernel.ld
+LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_x86_64
+CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
+LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
+
+TESTS+=$(MULTIARCH_TESTS)
+
+# building head blobs
+.PRECIOUS: $(CRT_OBJS)
+
+%.o: $(CRT_PATH)/%.S
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+
+# Build and link the tests
+%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+
+memory: CFLAGS+=-DCHECK_UNALIGNED=1
+
+# Running
+QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel
diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
index 74f170b9ed..20bf96202a 100644
--- a/tests/tcg/x86_64/Makefile.target
+++ b/tests/tcg/x86_64/Makefile.target
@@ -6,9 +6,10 @@
# $(SRC)/tests/tcg/i386/
#
-X86_64_TESTS=$(filter-out $(I386_ONLY_TESTS), $(TESTS))
-X86_64_TESTS+=test-x86_64
-TESTS:=$(X86_64_TESTS)
+include $(SRC_PATH)/tests/tcg/i386/Makefile.target
+
+TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
+QEMU_OPTS += -cpu max
test-x86_64: LDFLAGS+=-lm -lc
test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h
diff --git a/tests/tcg/xtensa/Makefile.include b/tests/tcg/xtensa/Makefile.include
deleted file mode 100644
index 423c00a5d3..0000000000
--- a/tests/tcg/xtensa/Makefile.include
+++ /dev/null
@@ -1,11 +0,0 @@
-# Makefile.include for xtensa targets
-#
-# The compilers can only be used for building system tests
-
-ifeq ($(CONFIG_SOFTMMU),y)
-DOCKER_IMAGE=debian-xtensa-cross
-
-# default to the dc232b cpu
-DOCKER_CROSS_COMPILER=/opt/2018.02/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-gcc
-DOCKER_CROSS_LINKER=/opt/2018.02/xtensa-dc232b-elf/bin/xtensa-dc232b-elf-ld
-endif
diff --git a/tests/tcg/xtensa/Makefile.softmmu-target b/tests/tcg/xtensa/Makefile.softmmu-target
index 8212d96b81..9530cac2ad 100644
--- a/tests/tcg/xtensa/Makefile.softmmu-target
+++ b/tests/tcg/xtensa/Makefile.softmmu-target
@@ -34,9 +34,9 @@ $(XTENSA_USABLE_TESTS): linker.ld macros.inc $(CRT) Makefile.softmmu-target
# special rule for common blobs
%.o: %.S
- $(CC) $(XTENSA_INC) $($*_ASFLAGS) $(ASFLAGS) -c $< -o $@
+ $(CC) $(XTENSA_INC) $($*_ASFLAGS) $(ASFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
%: %.S
- $(CC) $(XTENSA_INC) $(ASFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT)
+ $(CC) $(XTENSA_INC) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT)
endif
diff --git a/tests/test-arm-mptimer.c b/tests/test-arm-mptimer.c
index 156a39f50d..7a56d56da9 100644
--- a/tests/test-arm-mptimer.c
+++ b/tests/test-arm-mptimer.c
@@ -9,7 +9,7 @@
#include "qemu/osdep.h"
#include "qemu/timer.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#define TIMER_BLOCK_SCALE(s) ((((s) & 0xff) + 1) * 10)
diff --git a/tests/test-char.c b/tests/test-char.c
index b56e43c1eb..f3ebdffd87 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -667,7 +667,7 @@ char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass,
char *optstr;
g_assert(!reconnect);
if (is_listen) {
- qio_channel_socket_listen_sync(ioc, addr, &error_abort);
+ qio_channel_socket_listen_sync(ioc, addr, 1, &error_abort);
} else {
qio_channel_socket_connect_sync(ioc, addr, &error_abort);
}
@@ -892,7 +892,7 @@ static void char_socket_client_test(gconstpointer opaque)
*/
ioc = qio_channel_socket_new();
g_assert_nonnull(ioc);
- qio_channel_socket_listen_sync(ioc, config->addr, &error_abort);
+ qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort);
addr = qio_channel_socket_get_local_address(ioc, &error_abort);
g_assert_nonnull(addr);
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index d172f3070f..d43083a766 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -57,7 +57,7 @@ static void test_io_channel_setup_sync(SocketAddress *listen_addr,
QIOChannelSocket *lioc;
lioc = qio_channel_socket_new();
- qio_channel_socket_listen_sync(lioc, listen_addr, &error_abort);
+ qio_channel_socket_listen_sync(lioc, listen_addr, 1, &error_abort);
if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
SocketAddress *laddr = qio_channel_socket_get_local_address(
@@ -113,7 +113,7 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr,
lioc = qio_channel_socket_new();
qio_channel_socket_listen_async(
- lioc, listen_addr,
+ lioc, listen_addr, 1,
test_io_channel_complete, &data, NULL, NULL);
g_main_loop_run(data.loop);
diff --git a/tests/test-netfilter.c b/tests/test-netfilter.c
index e47075dd06..22927ee6ab 100644
--- a/tests/test-netfilter.c
+++ b/tests/test-netfilter.c
@@ -9,7 +9,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qapi/qmp/qdict.h"
/* add a netfilter to a netdev and then remove it */
diff --git a/tests/test-util-filemonitor.c b/tests/test-util-filemonitor.c
index 46e781c022..301cd2db61 100644
--- a/tests/test-util-filemonitor.c
+++ b/tests/test-util-filemonitor.c
@@ -45,6 +45,11 @@ typedef struct {
const char *filedst;
int64_t *watchid;
int eventid;
+ /*
+ * Only valid with OP_EVENT - this event might be
+ * swapped with the next OP_EVENT
+ */
+ bool swapnext;
} QFileMonitorTestOp;
typedef struct {
@@ -98,6 +103,10 @@ qemu_file_monitor_test_handler(int64_t id,
QFileMonitorTestData *data = opaque;
QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1);
+ if (debug) {
+ g_printerr("Queue event id %" PRIx64 " event %d file %s\n",
+ id, event, filename);
+ }
rec->id = id;
rec->event = event;
rec->filename = g_strdup(filename);
@@ -125,7 +134,8 @@ qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec)
* to wait for the event to be queued for us.
*/
static QFileMonitorTestRecord *
-qemu_file_monitor_test_next_record(QFileMonitorTestData *data)
+qemu_file_monitor_test_next_record(QFileMonitorTestData *data,
+ QFileMonitorTestRecord *pushback)
{
GTimer *timer = g_timer_new();
QFileMonitorTestRecord *record = NULL;
@@ -139,9 +149,15 @@ qemu_file_monitor_test_next_record(QFileMonitorTestData *data)
}
if (data->records) {
record = data->records->data;
- tmp = data->records;
- data->records = g_list_remove_link(data->records, tmp);
- g_list_free(tmp);
+ if (pushback) {
+ data->records->data = pushback;
+ } else {
+ tmp = data->records;
+ data->records = g_list_remove_link(data->records, tmp);
+ g_list_free(tmp);
+ }
+ } else if (pushback) {
+ qemu_file_monitor_test_record_free(pushback);
}
qemu_mutex_unlock(&data->lock);
@@ -158,13 +174,15 @@ static bool
qemu_file_monitor_test_expect(QFileMonitorTestData *data,
int64_t id,
QFileMonitorEvent event,
- const char *filename)
+ const char *filename,
+ bool swapnext)
{
QFileMonitorTestRecord *rec;
bool ret = false;
- rec = qemu_file_monitor_test_next_record(data);
+ rec = qemu_file_monitor_test_next_record(data, NULL);
+ retry:
if (!rec) {
g_printerr("Missing event watch id %" PRIx64 " event %d file %s\n",
id, event, filename);
@@ -172,6 +190,11 @@ qemu_file_monitor_test_expect(QFileMonitorTestData *data,
}
if (id != rec->id) {
+ if (swapnext) {
+ rec = qemu_file_monitor_test_next_record(data, rec);
+ swapnext = false;
+ goto retry;
+ }
g_printerr("Expected watch id %" PRIx64 " but got %" PRIx64 "\n",
id, rec->id);
goto cleanup;
@@ -347,7 +370,8 @@ test_file_monitor_events(void)
.filesrc = "fish", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
.filesrc = "", .watchid = &watch4,
- .eventid = QFILE_MONITOR_EVENT_IGNORED },
+ .eventid = QFILE_MONITOR_EVENT_IGNORED,
+ .swapnext = true },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
.filesrc = "fish", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_DELETED },
@@ -493,8 +517,9 @@ test_file_monitor_events(void)
g_printerr("Event id=%" PRIx64 " event=%d file=%s\n",
*op->watchid, op->eventid, op->filesrc);
}
- if (!qemu_file_monitor_test_expect(
- &data, *op->watchid, op->eventid, op->filesrc))
+ if (!qemu_file_monitor_test_expect(&data, *op->watchid,
+ op->eventid, op->filesrc,
+ op->swapnext))
goto cleanup;
break;
case QFILE_MONITOR_TEST_OP_CREATE:
diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c
index e2a3a8a093..8ce55efe70 100644
--- a/tests/test-util-sockets.c
+++ b/tests/test-util-sockets.c
@@ -93,7 +93,7 @@ static void test_socket_fd_pass_name_good(void)
g_assert_cmpint(fd, !=, mon_fd);
close(fd);
- fd = socket_listen(&addr, &error_abort);
+ fd = socket_listen(&addr, 1, &error_abort);
g_assert_cmpint(fd, !=, -1);
g_assert_cmpint(fd, !=, mon_fd);
close(fd);
@@ -124,7 +124,7 @@ static void test_socket_fd_pass_name_bad(void)
g_assert_cmpint(fd, ==, -1);
error_free_or_abort(&err);
- fd = socket_listen(&addr, &err);
+ fd = socket_listen(&addr, 1, &err);
g_assert_cmpint(fd, ==, -1);
error_free_or_abort(&err);
@@ -151,7 +151,7 @@ static void test_socket_fd_pass_name_nomon(void)
g_assert_cmpint(fd, ==, -1);
error_free_or_abort(&err);
- fd = socket_listen(&addr, &err);
+ fd = socket_listen(&addr, 1, &err);
g_assert_cmpint(fd, ==, -1);
error_free_or_abort(&err);
@@ -174,7 +174,7 @@ static void test_socket_fd_pass_num_good(void)
fd = socket_connect(&addr, &error_abort);
g_assert_cmpint(fd, ==, sfd);
- fd = socket_listen(&addr, &error_abort);
+ fd = socket_listen(&addr, 1, &error_abort);
g_assert_cmpint(fd, ==, sfd);
g_free(addr.u.fd.str);
@@ -197,7 +197,7 @@ static void test_socket_fd_pass_num_bad(void)
g_assert_cmpint(fd, ==, -1);
error_free_or_abort(&err);
- fd = socket_listen(&addr, &err);
+ fd = socket_listen(&addr, 1, &err);
g_assert_cmpint(fd, ==, -1);
error_free_or_abort(&err);
@@ -220,7 +220,7 @@ static void test_socket_fd_pass_num_nocli(void)
g_assert_cmpint(fd, ==, -1);
error_free_or_abort(&err);
- fd = socket_listen(&addr, &err);
+ fd = socket_listen(&addr, 1, &err);
g_assert_cmpint(fd, ==, -1);
error_free_or_abort(&err);
diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c
index e75b959950..772287bdb4 100644
--- a/tests/test-x86-cpuid-compat.c
+++ b/tests/test-x86-cpuid-compat.c
@@ -4,7 +4,7 @@
#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qbool.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
static char *get_cpu0_qom_path(void)
{
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
index f599309a4a..f930a96b83 100644
--- a/tests/tmp105-test.c
+++ b/tests/tmp105-test.c
@@ -9,7 +9,7 @@
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "libqos/qgraph.h"
#include "libqos/i2c.h"
#include "qapi/qmp/qdict.h"
diff --git a/tests/tpm-crb-test.c b/tests/tpm-crb-test.c
index a139caa51d..632fb7fbd8 100644
--- a/tests/tpm-crb-test.c
+++ b/tests/tpm-crb-test.c
@@ -15,7 +15,7 @@
#include "hw/acpi/tpm.h"
#include "io/channel-socket.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/module.h"
#include "tpm-emu.h"
diff --git a/tests/tpm-emu.c b/tests/tpm-emu.c
index 125e697181..c43ac4aef8 100644
--- a/tests/tpm-emu.c
+++ b/tests/tpm-emu.c
@@ -76,7 +76,7 @@ void *tpm_emu_ctrl_thread(void *data)
QIOChannelSocket *lioc = qio_channel_socket_new();
QIOChannel *ioc;
- qio_channel_socket_listen_sync(lioc, s->addr, &error_abort);
+ qio_channel_socket_listen_sync(lioc, s->addr, 1, &error_abort);
g_mutex_lock(&s->data_mutex);
s->data_cond_signal = true;
diff --git a/tests/tpm-tests.c b/tests/tpm-tests.c
index e640777aa9..6e45a0ba85 100644
--- a/tests/tpm-tests.c
+++ b/tests/tpm-tests.c
@@ -15,7 +15,7 @@
#include "qemu/osdep.h"
#include <glib/gstdio.h>
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "tpm-tests.h"
static bool
diff --git a/tests/tpm-tis-test.c b/tests/tpm-tis-test.c
index 92a7e95aad..dcf30e05b7 100644
--- a/tests/tpm-tis-test.c
+++ b/tests/tpm-tis-test.c
@@ -17,7 +17,7 @@
#include "hw/acpi/tpm.h"
#include "io/channel-socket.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/module.h"
#include "tpm-emu.h"
diff --git a/tests/usb-hcd-ohci-test.c b/tests/usb-hcd-ohci-test.c
index 0cd73b7363..19d760f3fb 100644
--- a/tests/usb-hcd-ohci-test.c
+++ b/tests/usb-hcd-ohci-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/module.h"
#include "libqos/usb.h"
#include "libqos/qgraph.h"
diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
index 2eef8e3d1c..7a117b64d9 100644
--- a/tests/usb-hcd-uhci-test.c
+++ b/tests/usb-hcd-uhci-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "libqos/libqos.h"
#include "libqos/usb.h"
#include "libqos/libqos-pc.h"
diff --git a/tests/usb-hcd-xhci-test.c b/tests/usb-hcd-xhci-test.c
index 01845371f9..10ef9d2a91 100644
--- a/tests/usb-hcd-xhci-test.c
+++ b/tests/usb-hcd-xhci-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "libqos/usb.h"
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 6ae8a23688..91ea373ba5 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -10,7 +10,7 @@
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qemu/config-file.h"
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index 30e6cf3e63..e7b58e3a0c 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/module.h"
#include "hw/9pfs/9p.h"
#include "hw/9pfs/9p-synth.h"
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 982ff1538c..ed13167392 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -9,7 +9,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/bswap.h"
#include "qemu/module.h"
#include "standard-headers/linux/virtio_blk.h"
@@ -737,6 +737,7 @@ static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
int n_size = TEST_IMAGE_SIZE / 2;
uint64_t capacity;
QVirtQueue *vq;
+ QTestState *qts = global_qtest;
vq = qvirtqueue_setup(dev, t_alloc, 0);
@@ -746,7 +747,7 @@ static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
" 'arguments': { 'device': 'drive0', "
" 'size': %d } }", n_size);
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+ qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
capacity = qvirtio_config_readq(dev, 0);
g_assert_cmpint(capacity, ==, n_size / 512);
diff --git a/tests/virtio-ccw-test.c b/tests/virtio-ccw-test.c
index 9f445ef4ad..d05236407b 100644
--- a/tests/virtio-ccw-test.c
+++ b/tests/virtio-ccw-test.c
@@ -14,7 +14,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "libqos/virtio.h"
static void virtio_balloon_nop(void)
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index 840875aaae..a08e2ffe12 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -9,7 +9,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/iov.h"
#include "qemu/module.h"
#include "qapi/qmp/qdict.h"
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index 09348765d7..7c8f9b27f8 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -9,7 +9,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/module.h"
#include "scsi/constants.h"
#include "libqos/libqos-pc.h"
diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c
index e584ad76e8..2541034822 100644
--- a/tests/virtio-serial-test.c
+++ b/tests/virtio-serial-test.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
+#include "libqtest-single.h"
#include "qemu/module.h"
#include "libqos/virtio-serial.h"
diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include
index 3560716092..fea348e845 100644
--- a/tests/vm/Makefile.include
+++ b/tests/vm/Makefile.include
@@ -80,6 +80,7 @@ vm-boot-serial-%: $(IMAGES_DIR)/%.img
vm-boot-ssh-%: $(IMAGES_DIR)/%.img
$(call quiet-command, \
$(SRC_PATH)/tests/vm/$* \
+ $(if $(J),--jobs $(J)) \
--image "$<" \
--interactive \
false, \
diff --git a/tests/vm/fedora b/tests/vm/fedora
index e8fa5bf0d2..7fec1479fb 100755
--- a/tests/vm/fedora
+++ b/tests/vm/fedora
@@ -23,7 +23,7 @@ class FedoraVM(basevm.BaseVM):
name = "fedora"
arch = "x86_64"
- base = "http://dl.fedoraproject.org/pub/fedora/linux/releases/30/"
+ base = "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/30/"
link = base + "Server/x86_64/iso/Fedora-Server-netinst-x86_64-30-1.2.iso"
repo = base + "Server/x86_64/os/"
full = base + "Everything/x86_64/os/"
diff --git a/trace/mem-internal.h b/trace/mem-internal.h
index f6efaf6d6b..3444fbc596 100644
--- a/trace/mem-internal.h
+++ b/trace/mem-internal.h
@@ -16,7 +16,7 @@
#define TRACE_MEM_ST (1ULL << 5) /* store (y/n) */
static inline uint8_t trace_mem_build_info(
- int size_shift, bool sign_extend, TCGMemOp endianness, bool store)
+ int size_shift, bool sign_extend, MemOp endianness, bool store)
{
uint8_t res;
@@ -33,7 +33,7 @@ static inline uint8_t trace_mem_build_info(
return res;
}
-static inline uint8_t trace_mem_get_info(TCGMemOp op, bool store)
+static inline uint8_t trace_mem_get_info(MemOp op, bool store)
{
return trace_mem_build_info(op & MO_SIZE, !!(op & MO_SIGN),
op & MO_BSWAP, store);
diff --git a/trace/mem.h b/trace/mem.h
index 2b58196e53..8cf213d85b 100644
--- a/trace/mem.h
+++ b/trace/mem.h
@@ -18,7 +18,7 @@
*
* Return a value for the 'info' argument in guest memory access traces.
*/
-static uint8_t trace_mem_get_info(TCGMemOp op, bool store);
+static uint8_t trace_mem_get_info(MemOp op, bool store);
/**
* trace_mem_build_info:
@@ -26,7 +26,7 @@ static uint8_t trace_mem_get_info(TCGMemOp op, bool store);
* Return a value for the 'info' argument in guest memory access traces.
*/
static uint8_t trace_mem_build_info(int size_shift, bool sign_extend,
- TCGMemOp endianness, bool store);
+ MemOp endianness, bool store);
#include "trace/mem-internal.h"
diff --git a/ui/vnc.c b/ui/vnc.c
index 649ce93cd2..bd16746022 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3765,7 +3765,7 @@ static int vnc_display_listen(VncDisplay *vd,
qio_net_listener_set_name(vd->listener, "vnc-listen");
for (i = 0; i < nsaddr; i++) {
if (qio_net_listener_open_sync(vd->listener,
- saddr[i],
+ saddr[i], 1,
errp) < 0) {
return -1;
}
@@ -3780,7 +3780,7 @@ static int vnc_display_listen(VncDisplay *vd,
qio_net_listener_set_name(vd->wslistener, "vnc-ws-listen");
for (i = 0; i < nwsaddr; i++) {
if (qio_net_listener_open_sync(vd->wslistener,
- wsaddr[i],
+ wsaddr[i], 1,
errp) < 0) {
return -1;
}
diff --git a/util/memfd.c b/util/memfd.c
index 00334e5b21..4a3c07e0be 100644
--- a/util/memfd.c
+++ b/util/memfd.c
@@ -35,7 +35,7 @@
#include <sys/syscall.h>
#include <asm/unistd.h>
-static int memfd_create(const char *name, unsigned int flags)
+int memfd_create(const char *name, unsigned int flags)
{
#ifdef __NR_memfd_create
return syscall(__NR_memfd_create, name, flags);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index e3a1666578..98ff3a1cce 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -31,6 +31,7 @@
#include "qapi/qobject-input-visitor.h"
#include "qapi/qobject-output-visitor.h"
#include "qemu/cutils.h"
+#include "trace.h"
#ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
@@ -207,6 +208,7 @@ static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e)
static int inet_listen_saddr(InetSocketAddress *saddr,
int port_offset,
+ int num,
Error **errp)
{
struct addrinfo ai,*res,*e;
@@ -309,7 +311,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
goto listen_failed;
}
} else {
- if (!listen(slisten, 1)) {
+ if (!listen(slisten, num)) {
goto listen_ok;
}
if (errno != EADDRINUSE) {
@@ -774,6 +776,7 @@ static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp)
}
static int vsock_listen_saddr(VsockSocketAddress *vaddr,
+ int num,
Error **errp)
{
struct sockaddr_vm svm;
@@ -795,7 +798,7 @@ static int vsock_listen_saddr(VsockSocketAddress *vaddr,
return -1;
}
- if (listen(slisten, 1) != 0) {
+ if (listen(slisten, num) != 0) {
error_setg_errno(errp, errno, "Failed to listen on socket");
closesocket(slisten);
return -1;
@@ -836,6 +839,7 @@ static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp)
}
static int vsock_listen_saddr(VsockSocketAddress *vaddr,
+ int num,
Error **errp)
{
vsock_unsupported(errp);
@@ -853,6 +857,7 @@ static int vsock_parse(VsockSocketAddress *addr, const char *str,
#ifndef _WIN32
static int unix_listen_saddr(UnixSocketAddress *saddr,
+ int num,
Error **errp)
{
struct sockaddr_un un;
@@ -914,7 +919,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
error_setg_errno(errp, errno, "Failed to bind socket to %s", path);
goto err;
}
- if (listen(sock, 1) < 0) {
+ if (listen(sock, num) < 0) {
error_setg_errno(errp, errno, "Failed to listen on socket");
goto err;
}
@@ -981,6 +986,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
#else
static int unix_listen_saddr(UnixSocketAddress *saddr,
+ int num,
Error **errp)
{
error_setg(errp, "unix sockets are not available on windows");
@@ -1004,7 +1010,7 @@ int unix_listen(const char *str, Error **errp)
saddr = g_new0(UnixSocketAddress, 1);
saddr->path = g_strdup(str);
- sock = unix_listen_saddr(saddr, errp);
+ sock = unix_listen_saddr(saddr, 1, errp);
qapi_free_UnixSocketAddress(saddr);
return sock;
}
@@ -1061,9 +1067,13 @@ fail:
return NULL;
}
-static int socket_get_fd(const char *fdstr, Error **errp)
+static int socket_get_fd(const char *fdstr, int num, Error **errp)
{
int fd;
+ if (num != 1) {
+ error_setg_errno(errp, EINVAL, "socket_get_fd: too many connections");
+ return -1;
+ }
if (cur_mon) {
fd = monitor_get_fd(cur_mon, fdstr, errp);
if (fd < 0) {
@@ -1099,7 +1109,7 @@ int socket_connect(SocketAddress *addr, Error **errp)
break;
case SOCKET_ADDRESS_TYPE_FD:
- fd = socket_get_fd(addr->u.fd.str, errp);
+ fd = socket_get_fd(addr->u.fd.str, 1, errp);
break;
case SOCKET_ADDRESS_TYPE_VSOCK:
@@ -1112,25 +1122,26 @@ int socket_connect(SocketAddress *addr, Error **errp)
return fd;
}
-int socket_listen(SocketAddress *addr, Error **errp)
+int socket_listen(SocketAddress *addr, int num, Error **errp)
{
int fd;
+ trace_socket_listen(num);
switch (addr->type) {
case SOCKET_ADDRESS_TYPE_INET:
- fd = inet_listen_saddr(&addr->u.inet, 0, errp);
+ fd = inet_listen_saddr(&addr->u.inet, 0, num, errp);
break;
case SOCKET_ADDRESS_TYPE_UNIX:
- fd = unix_listen_saddr(&addr->u.q_unix, errp);
+ fd = unix_listen_saddr(&addr->u.q_unix, num, errp);
break;
case SOCKET_ADDRESS_TYPE_FD:
- fd = socket_get_fd(addr->u.fd.str, errp);
+ fd = socket_get_fd(addr->u.fd.str, num, errp);
break;
case SOCKET_ADDRESS_TYPE_VSOCK:
- fd = vsock_listen_saddr(&addr->u.vsock, errp);
+ fd = vsock_listen_saddr(&addr->u.vsock, num, errp);
break;
default:
diff --git a/util/trace-events b/util/trace-events
index 9dbd237dad..83b6639018 100644
--- a/util/trace-events
+++ b/util/trace-events
@@ -64,6 +64,9 @@ lockcnt_futex_wait(const void *lockcnt, int val) "lockcnt %p waiting on %d"
lockcnt_futex_wait_resume(const void *lockcnt, int new) "lockcnt %p after wait: %d"
lockcnt_futex_wake(const void *lockcnt) "lockcnt %p waking up one waiter"
+# qemu-sockets.c
+socket_listen(int num) "backlog: %d"
+
# qemu-thread-common.h
qemu_mutex_lock(void *mutex, const char *file, const int line) "waiting on mutex %p (%s:%d)"
qemu_mutex_locked(void *mutex, const char *file, const int line) "taken mutex %p (%s:%d)"