summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.d/edk2.yml (renamed from .gitlab-ci-edk2.yml)0
-rw-r--r--.gitlab-ci.d/opensbi.yml (renamed from .gitlab-ci-opensbi.yml)0
-rw-r--r--.gitlab-ci.yml67
-rw-r--r--.mailmap3
-rw-r--r--.travis.yml8
-rw-r--r--MAINTAINERS41
-rw-r--r--accel/tcg/tcg-runtime-gvec.c144
-rw-r--r--accel/tcg/tcg-runtime.h15
-rw-r--r--accel/tcg/user-exec.c43
-rw-r--r--backends/hostmem.c6
-rw-r--r--block/crypto.c2
-rw-r--r--block/dirty-bitmap.c13
-rw-r--r--block/io.c193
-rw-r--r--block/io_uring.c11
-rw-r--r--block/qcow2-bitmap.c36
-rw-r--r--block/qcow2.c14
-rw-r--r--block/qcow2.h2
-rw-r--r--block/raw-format.c2
-rw-r--r--chardev/char-socket.c5
-rwxr-xr-xconfigure4
-rw-r--r--cpus-common.c10
-rw-r--r--default-configs/mips64el-softmmu.mak2
-rw-r--r--default-configs/riscv32-softmmu.mak1
-rw-r--r--default-configs/riscv64-softmmu.mak11
-rw-r--r--docs/system/arm/aspeed.rst85
-rw-r--r--docs/system/deprecated.rst103
-rw-r--r--docs/system/s390x/3270.rst32
-rw-r--r--docs/system/s390x/css.rst86
-rw-r--r--docs/system/s390x/vfio-ccw.rst77
-rw-r--r--docs/system/target-arm.rst1
-rw-r--r--docs/system/target-mips.rst2
-rw-r--r--docs/system/target-s390x.rst3
-rw-r--r--docs/tools/qemu-img.rst13
-rw-r--r--exec.c2
-rw-r--r--hmp-commands.hx16
-rw-r--r--hw/adc/stm32f2xx_adc.c4
-rw-r--r--hw/arm/bcm2835_peripherals.c38
-rw-r--r--hw/arm/pxa2xx.c66
-rw-r--r--hw/arm/sabrelite.c7
-rw-r--r--hw/block/Makefile.objs2
-rw-r--r--hw/block/nvme.c6
-rw-r--r--hw/display/ati.c10
-rw-r--r--hw/display/cg3.c14
-rw-r--r--hw/display/cirrus_vga.c119
-rw-r--r--hw/display/dpcd.c20
-rw-r--r--hw/display/exynos4210_fimd.c46
-rw-r--r--hw/display/omap_dss.c2
-rw-r--r--hw/display/pxa2xx_lcd.c26
-rw-r--r--hw/display/sm501.c311
-rw-r--r--hw/display/trace-events10
-rw-r--r--hw/display/vmware_vga.c18
-rw-r--r--hw/display/xlnx_dp.c14
-rw-r--r--hw/input/pxa2xx_keypad.c10
-rw-r--r--hw/isa/vt82c686.c2
-rw-r--r--hw/m68k/mcf5206.c14
-rw-r--r--hw/m68k/mcf5208.c16
-rw-r--r--hw/m68k/mcf_intc.c10
-rw-r--r--hw/mem/nvdimm.c1
-rw-r--r--hw/mips/Kconfig3
-rw-r--r--hw/mips/Makefile.objs10
-rw-r--r--hw/mips/boston.c17
-rw-r--r--hw/mips/fuloong2e.c (renamed from hw/mips/mips_fulong2e.c)47
-rw-r--r--hw/mips/jazz.c (renamed from hw/mips/mips_jazz.c)0
-rw-r--r--hw/mips/malta.c (renamed from hw/mips/mips_malta.c)29
-rw-r--r--hw/mips/mips_int.c11
-rw-r--r--hw/mips/mipssim.c (renamed from hw/mips/mips_mipssim.c)0
-rw-r--r--hw/mips/r4k.c (renamed from hw/mips/mips_r4k.c)0
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/bcm2835_mphi.c191
-rw-r--r--hw/net/mcf_fec.c9
-rw-r--r--hw/nvram/mac_nvram.c17
-rw-r--r--hw/nvram/trace-events4
-rw-r--r--hw/pci-bridge/dec.c10
-rw-r--r--hw/pci-host/Kconfig5
-rw-r--r--hw/pci-host/Makefile.objs2
-rw-r--r--hw/pci-host/bonito.c87
-rw-r--r--hw/ppc/pnv.c26
-rw-r--r--hw/ppc/spapr.c3
-rw-r--r--hw/ppc/spapr_cpu_core.c1
-rw-r--r--hw/riscv/Kconfig5
-rw-r--r--hw/riscv/Makefile.objs1
-rw-r--r--hw/riscv/boot.c45
-rw-r--r--hw/riscv/opentitan.c184
-rw-r--r--hw/riscv/sifive_e.c41
-rw-r--r--hw/riscv/sifive_u.c24
-rw-r--r--hw/riscv/spike.c217
-rw-r--r--hw/riscv/virt.c20
-rw-r--r--hw/s390x/pv.c2
-rw-r--r--hw/s390x/s390-virtio-ccw.c2
-rw-r--r--hw/sd/pxa2xx_mmci.c4
-rw-r--r--hw/sd/sd.c4
-rw-r--r--hw/ssi/imx_spi.c4
-rw-r--r--hw/usb/Kconfig5
-rw-r--r--hw/usb/Makefile.objs1
-rw-r--r--hw/usb/dev-mtp.c9
-rw-r--r--hw/usb/dev-storage.c15
-rw-r--r--hw/usb/hcd-dwc2.c1417
-rw-r--r--hw/usb/hcd-dwc2.h190
-rw-r--r--hw/usb/trace-events50
-rw-r--r--hw/usb/xen-usb.c19
-rw-r--r--hw/vfio/ccw.c13
-rw-r--r--hw/vfio/pci-quirks.c4
-rw-r--r--include/block/dirty-bitmap.h1
-rw-r--r--include/exec/memory.h15
-rw-r--r--include/exec/ram_addr.h4
-rw-r--r--include/hw/arm/bcm2835_peripherals.h5
-rw-r--r--include/hw/display/edid.h1
-rw-r--r--include/hw/misc/bcm2835_mphi.h44
-rw-r--r--include/hw/ppc/spapr.h1
-rw-r--r--include/hw/registerfields.h40
-rw-r--r--include/hw/riscv/boot.h1
-rw-r--r--include/hw/riscv/opentitan.h68
-rw-r--r--include/hw/riscv/sifive_e.h4
-rw-r--r--include/hw/riscv/spike.h6
-rw-r--r--include/hw/s390x/pv.h4
-rw-r--r--include/hw/usb/dwc2-regs.h899
-rw-r--r--include/migration/vmstate.h1
-rw-r--r--include/monitor/hmp.h1
-rw-r--r--include/sysemu/sysemu.h2
-rw-r--r--include/tcg/tcg-op-gvec.h12
-rw-r--r--include/tcg/tcg-op.h5
-rw-r--r--include/tcg/tcg-opc.h4
-rw-r--r--include/tcg/tcg.h3
-rw-r--r--linux-user/elfload.c2
-rw-r--r--linux-user/ppc/cpu_loop.c1
-rw-r--r--linux-user/syscall.c19
-rw-r--r--memory.c12
-rw-r--r--migration/block-dirty-bitmap.c130
-rw-r--r--migration/colo.c39
-rw-r--r--migration/migration.c4
-rw-r--r--migration/migration.h4
-rw-r--r--migration/ram.c5
-rw-r--r--migration/ram.h1
-rw-r--r--migration/rdma.c12
-rw-r--r--python/qemu/.flake82
-rw-r--r--python/qemu/accel.py9
-rw-r--r--python/qemu/machine.py44
-rw-r--r--python/qemu/pylintrc58
-rw-r--r--python/qemu/qmp.py29
-rw-r--r--python/qemu/qtest.py83
-rw-r--r--qapi/block-core.json16
-rw-r--r--qemu-img-cmds.hx4
-rw-r--r--qemu-img.c107
-rw-r--r--qemu-nbd.c7
-rw-r--r--qom/qom-hmp-cmds.c34
-rwxr-xr-xscripts/analyze-migration.py5
-rwxr-xr-xscripts/decodetree.py25
-rwxr-xr-xscripts/kvm/vmxcap7
-rw-r--r--scripts/modules/module_block.py29
-rw-r--r--scripts/qemu-gdb.py4
-rw-r--r--scripts/qemugdb/__init__.py3
-rw-r--r--scripts/qemugdb/aio.py3
-rw-r--r--scripts/qemugdb/coroutine.py3
-rw-r--r--scripts/qemugdb/mtree.py4
-rw-r--r--scripts/qemugdb/tcg.py1
-rw-r--r--scripts/qemugdb/timers.py1
-rwxr-xr-xscripts/qmp/qmp4
-rwxr-xr-xscripts/qmp/qmp-shell3
-rwxr-xr-xscripts/qmp/qom-fuse4
-rwxr-xr-xscripts/qmp/qom-get6
-rwxr-xr-xscripts/qmp/qom-list6
-rwxr-xr-xscripts/qmp/qom-set6
-rwxr-xr-xscripts/qmp/qom-tree6
-rw-r--r--scsi/qemu-pr-helper.c4
-rw-r--r--softmmu/vl.c2
-rw-r--r--target/arm/crypto_helper.c271
-rw-r--r--target/arm/helper.c2
-rw-r--r--target/arm/helper.h53
-rw-r--r--target/arm/neon-dp.decode214
-rw-r--r--target/arm/translate-a64.c198
-rw-r--r--target/arm/translate-a64.h3
-rw-r--r--target/arm/translate-neon.inc.c794
-rw-r--r--target/arm/translate.c539
-rw-r--r--target/arm/vec_helper.c12
-rw-r--r--target/arm/vec_internal.h33
-rw-r--r--target/i386/cpu.c27
-rw-r--r--target/m68k/fpu_helper.c5
-rw-r--r--target/m68k/helper.h1
-rw-r--r--target/m68k/translate.c17
-rw-r--r--target/mips/cpu-param.h5
-rw-r--r--target/mips/kvm.c212
-rw-r--r--target/mips/machine.c6
-rw-r--r--target/ppc/cpu.h28
-rw-r--r--target/ppc/excp_helper.c130
-rw-r--r--target/ppc/helper.h5
-rw-r--r--target/ppc/int_helper.c17
-rw-r--r--target/ppc/mmu-radix64.c53
-rw-r--r--target/ppc/mmu-radix64.h4
-rw-r--r--target/ppc/translate.c53
-rw-r--r--target/ppc/translate/vmx-impl.inc.c8
-rw-r--r--target/ppc/translate_init.inc.c3
-rw-r--r--target/riscv/cpu.c45
-rw-r--r--target/riscv/cpu.h9
-rw-r--r--target/riscv/cpu_helper.c82
-rw-r--r--target/riscv/csr.c138
-rw-r--r--target/riscv/insn_trans/trans_privileged.inc.c18
-rw-r--r--target/riscv/monitor.c5
-rw-r--r--target/riscv/op_helper.c17
-rw-r--r--target/s390x/cpu_models.c2
-rw-r--r--target/s390x/helper.c5
-rw-r--r--target/s390x/helper.h4
-rw-r--r--target/s390x/insn-data.def4
-rw-r--r--target/s390x/internal.h16
-rw-r--r--target/s390x/kvm.c4
-rw-r--r--target/s390x/translate_vx.inc.c66
-rw-r--r--target/s390x/vec_int_helper.c31
-rw-r--r--target/tricore/Makefile.objs2
-rw-r--r--target/tricore/cpu.c18
-rw-r--r--target/tricore/cpu.h2
-rw-r--r--target/tricore/gdbstub.c139
-rw-r--r--target/tricore/helper.c13
-rw-r--r--target/tricore/translate.c79
-rw-r--r--tcg/README7
-rw-r--r--tcg/aarch64/tcg-target.h3
-rw-r--r--tcg/aarch64/tcg-target.inc.c53
-rw-r--r--tcg/aarch64/tcg-target.opc.h1
-rw-r--r--tcg/i386/tcg-target.h3
-rw-r--r--tcg/i386/tcg-target.inc.c116
-rw-r--r--tcg/ppc/tcg-target.h3
-rw-r--r--tcg/ppc/tcg-target.inc.c23
-rw-r--r--tcg/ppc/tcg-target.opc.h1
-rw-r--r--tcg/tcg-op-gvec.c212
-rw-r--r--tcg/tcg-op-vec.c62
-rw-r--r--tcg/tcg.c85
-rw-r--r--tests/Makefile.include46
-rw-r--r--tests/acceptance/avocado_qemu/__init__.py13
-rw-r--r--tests/acceptance/boot_linux.py49
-rw-r--r--tests/acceptance/boot_linux_console.py56
-rw-r--r--tests/acceptance/migration.py4
-rw-r--r--tests/docker/Makefile.include4
-rwxr-xr-xtests/docker/docker.py5
-rw-r--r--tests/docker/dockerfiles/debian-arm64-test-cross.docker13
-rw-r--r--tests/docker/dockerfiles/debian11.docker18
-rwxr-xr-xtests/migration/guestperf-batch.py2
-rwxr-xr-xtests/migration/guestperf-plot.py2
-rwxr-xr-xtests/migration/guestperf.py2
-rw-r--r--tests/qemu-iotests/178.out.qcow218
-rw-r--r--tests/qemu-iotests/178.out.raw2
-rwxr-xr-xtests/qemu-iotests/19047
-rw-r--r--tests/qemu-iotests/190.out27
-rwxr-xr-xtests/qemu-iotests/19414
-rw-r--r--tests/qemu-iotests/194.out6
-rwxr-xr-xtests/qemu-iotests/291112
-rw-r--r--tests/qemu-iotests/291.out80
-rw-r--r--tests/qemu-iotests/group1
-rwxr-xr-xtests/qemu-iotests/nbd-fault-injector.py5
-rw-r--r--tests/qtest/endianness-test.c2
-rw-r--r--tests/qtest/fuzz/fork_fuzz.ld5
-rw-r--r--tests/qtest/fuzz/fuzz.c15
-rw-r--r--tests/qtest/fuzz/i440fx_fuzz.c3
-rw-r--r--tests/qtest/fuzz/virtio_net_fuzz.c2
-rw-r--r--tests/qtest/fuzz/virtio_scsi_fuzz.c2
-rw-r--r--tests/qtest/machine-none-test.c4
-rw-r--r--tests/qtest/migration-test.c4
-rw-r--r--tests/qtest/test-hmp.c1
-rw-r--r--tests/tcg/aarch64/Makefile.softmmu-target2
-rwxr-xr-xtests/tcg/configure.sh4
-rw-r--r--tests/tcg/multiarch/Makefile.target2
-rw-r--r--tests/tcg/multiarch/gdbstub/sha1.py4
-rw-r--r--tests/tcg/multiarch/threadcount.c64
-rw-r--r--tests/vm/Makefile.include6
-rw-r--r--tests/vm/basevm.py54
-rw-r--r--tools/virtiofsd/passthrough_ll.c175
263 files changed, 8288 insertions, 2985 deletions
diff --git a/.gitlab-ci-edk2.yml b/.gitlab-ci.d/edk2.yml
index 088ba4b43a..088ba4b43a 100644
--- a/.gitlab-ci-edk2.yml
+++ b/.gitlab-ci.d/edk2.yml
diff --git a/.gitlab-ci-opensbi.yml b/.gitlab-ci.d/opensbi.yml
index dd051c0124..dd051c0124 100644
--- a/.gitlab-ci-opensbi.yml
+++ b/.gitlab-ci.d/opensbi.yml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b889fb96b6..349c77aa58 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,12 +1,24 @@
include:
- - local: '/.gitlab-ci-edk2.yml'
- - local: '/.gitlab-ci-opensbi.yml'
+ - local: '/.gitlab-ci.d/edk2.yml'
+ - local: '/.gitlab-ci.d/opensbi.yml'
-before_script:
- - apt-get update -qq
- - apt-get install -y -qq flex bison libglib2.0-dev libpixman-1-dev genisoimage
+.update_apt_template: &before_script_apt
+ before_script:
+ - apt-get update -qq
+ - apt-get install -y -qq git gcc libglib2.0-dev libpixman-1-dev make
+ genisoimage
+ - JOBS=$(expr $(nproc) + 1)
+
+.update_dnf_template: &before_script_dnf
+ before_script:
+ - dnf update -y
+ - dnf install -y bzip2 diffutils gcc git genisoimage findutils glib2-devel
+ make python3 perl-podlators perl-Test-Harness pixman-devel zlib-devel
+ - JOBS=$(expr $(nproc) + 1)
build-system1:
+ image: ubuntu:19.10
+ <<: *before_script_apt
script:
- apt-get install -y -qq libgtk-3-dev libvte-dev nettle-dev libcacard-dev
libusb-dev libvde-dev libspice-protocol-dev libgl1-mesa-dev libvdeplug-dev
@@ -15,23 +27,27 @@ build-system1:
- ../configure --enable-werror --target-list="aarch64-softmmu alpha-softmmu
cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu
mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu"
- - make -j2
- - make -j2 check
+ - make -j"$JOBS"
+ - make -j"$JOBS" check
build-system2:
+ image: fedora:latest
+ <<: *before_script_dnf
script:
- - apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev
- libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev
- libzstd-dev
+ - yum install -y SDL2-devel libgcrypt-devel brlapi-devel libaio-devel
+ libfdt-devel lzo-devel librdmacm-devel libibverbs-devel libibumad-devel
+ libzstd-devel
- mkdir build
- cd build
- ../configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu
microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu
sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu"
- - make -j2
- - make -j2 check
+ - make -j"$JOBS"
+ - make -j"$JOBS" check
build-disabled:
+ image: fedora:latest
+ <<: *before_script_dnf
script:
- mkdir build
- cd build
@@ -42,16 +58,18 @@ build-disabled:
--disable-qom-cast-debug --disable-spice --disable-vhost-vsock
--disable-vhost-net --disable-vhost-crypto --disable-vhost-user
--target-list="i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user"
- - make -j2
- - make -j2 check-qtest SPEED=slow
+ - make -j"$JOBS"
+ - make -j"$JOBS" check-qtest SPEED=slow
build-tcg-disabled:
+ image: centos:8
+ <<: *before_script_dnf
script:
- - apt-get install -y -qq clang libgtk-3-dev libusb-dev
+ - dnf install -y clang gtk3-devel libusbx-devel libgcrypt-devel
- mkdir build
- cd build
- ../configure --cc=clang --enable-werror --disable-tcg --audio-drv-list=""
- - make -j2
+ - make -j"$JOBS"
- make check-unit
- make check-qapi-schema
- cd tests/qemu-iotests/
@@ -64,34 +82,39 @@ build-tcg-disabled:
260 261 262 263 264 270 272 273 277 279
build-user:
+ <<: *before_script_apt
script:
- mkdir build
- cd build
- ../configure --enable-werror --disable-system --disable-guest-agent
--disable-capstone --disable-slirp --disable-fdt
- - make -j2
+ - make -j"$JOBS"
- make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user
build-clang:
+ image: fedora:latest
+ <<: *before_script_dnf
script:
- - apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-ng-dev
- xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev
+ - yum install -y clang SDL2-devel libattr-devel libcap-ng-devel xfsprogs-devel
+ libiscsi-devel libnfs-devel libseccomp-devel gnutls-devel librbd-devel
- mkdir build
- cd build
- ../configure --cc=clang --cxx=clang++ --enable-werror
--target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu
ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user"
- - make -j2
- - make -j2 check
+ - make -j"$JOBS"
+ - make -j"$JOBS" check
build-tci:
+ image: centos:8
+ <<: *before_script_dnf
script:
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
- mkdir build
- cd build
- ../configure --enable-tcg-interpreter
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)"
- - make -j2
+ - make -j"$JOBS"
- make run-tcg-tests-x86_64-softmmu
- make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
- for tg in $TARGETS ; do
diff --git a/.mailmap b/.mailmap
index 6412067bde..e3628c7a66 100644
--- a/.mailmap
+++ b/.mailmap
@@ -42,7 +42,8 @@ Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@mips.com>
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@imgtec.com>
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <amarkovic@wavecomp.com>
-Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com> <arikalo@wavecomp.com>
+Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <arikalo@wavecomp.com>
+Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <aleksandar.rikalo@rt-rk.com>
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
Leif Lindholm <leif@nuviainc.com> <leif.lindholm@linaro.org>
diff --git a/.travis.yml b/.travis.yml
index 1ec8a7b465..564be50a3c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -205,14 +205,15 @@ jobs:
# Test with Clang for compile portability (Travis uses clang-5.0)
- name: "Clang (user)"
env:
- - CONFIG="--disable-system"
+ - CONFIG="--disable-system --host-cc=clang --cxx=clang++"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
compiler: clang
- name: "Clang (main-softmmu)"
env:
- - CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS} "
+ - CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS}
+ --host-cc=clang --cxx=clang++"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-sanitize"
compiler: clang
before_script:
@@ -222,7 +223,8 @@ jobs:
- name: "Clang (other-softmmu)"
env:
- - CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
+ - CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}
+ --host-cc=clang --cxx=clang++"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
compiler: clang
diff --git a/MAINTAINERS b/MAINTAINERS
index 3690f313c3..6e7890ce82 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -85,6 +85,7 @@ Architecture support
--------------------
S390 general architecture support
M: Cornelia Huck <cohuck@redhat.com>
+M: Thomas Huth <thuth@redhat.com>
S: Supported
F: default-configs/s390x-softmmu.mak
F: gdb-xml/s390*.xml
@@ -213,7 +214,7 @@ F: disas/microblaze.c
MIPS TCG CPUs
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aurelien Jarno <aurelien@aurel32.net>
-R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
+R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
F: target/mips/
F: default-configs/*mips*
@@ -1048,9 +1049,9 @@ MIPS Machines
-------------
Jazz
M: Hervé Poussineau <hpoussin@reactos.org>
-R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
+R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
-F: hw/mips/mips_jazz.c
+F: hw/mips/jazz.c
F: hw/display/jazz_led.c
F: hw/dma/rc4030.c
@@ -1061,7 +1062,7 @@ R: Aurelien Jarno <aurelien@aurel32.net>
S: Maintained
F: hw/isa/piix4.c
F: hw/acpi/piix4.c
-F: hw/mips/mips_malta.c
+F: hw/mips/malta.c
F: hw/mips/gt64xxx_pci.c
F: include/hw/southbridge/piix.h
F: tests/acceptance/linux_ssh_mips_malta.py
@@ -1069,30 +1070,32 @@ F: tests/acceptance/machine_mips_malta.py
Mipssim
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
-R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
+R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Odd Fixes
-F: hw/mips/mips_mipssim.c
+F: hw/mips/mipssim.c
F: hw/net/mipsnet.c
R4000
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aurelien Jarno <aurelien@aurel32.net>
-R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
+R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Obsolete
-F: hw/mips/mips_r4k.c
+F: hw/mips/r4k.c
-Fulong 2E
+Fuloong 2E
+M: Huacai Chen <chenhc@lemote.com>
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
+R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Odd Fixes
-F: hw/mips/mips_fulong2e.c
+F: hw/mips/fuloong2e.c
F: hw/isa/vt82c686.c
F: hw/pci-host/bonito.c
F: include/hw/isa/vt82c686.h
Boston
M: Paul Burton <pburton@wavecomp.com>
-R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
+R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
F: hw/core/loader-fit.c
F: hw/mips/boston.c
@@ -1236,6 +1239,15 @@ F: pc-bios/canyonlands.dt[sb]
F: pc-bios/u-boot-sam460ex-20100605.bin
F: roms/u-boot-sam460ex
+RISC-V Machines
+---------------
+OpenTitan
+M: Alistair Francis <Alistair.Francis@wdc.com>
+L: qemu-riscv@nongnu.org
+S: Supported
+F: hw/riscv/opentitan.c
+F: include/hw/riscv/opentitan.h
+
SH4 Machines
------------
R2D
@@ -2540,7 +2552,7 @@ F: roms/edk2
F: roms/edk2-*
F: tests/data/uefi-boot-images/
F: tests/uefi-test-tools/
-F: .gitlab-ci-edk2.yml
+F: .gitlab-ci.d/edk2.yml
F: .gitlab-ci.d/edk2/
Usermode Emulation
@@ -2606,7 +2618,7 @@ F: disas/i386.c
MIPS TCG target
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aurelien Jarno <aurelien@aurel32.net>
-R: Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com>
+R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
F: tcg/mips/
@@ -2899,6 +2911,9 @@ W: https://cirrus-ci.com/github/qemu/qemu
GitLab Continuous Integration
M: Thomas Huth <thuth@redhat.com>
+M: Philippe Mathieu-Daudé <philmd@redhat.com>
+M: Alex Bennée <alex.bennee@linaro.org>
+R: Wainer dos Santos Moschetta <wainersm@redhat.com>
S: Maintained
F: .gitlab-ci.yml
diff --git a/accel/tcg/tcg-runtime-gvec.c b/accel/tcg/tcg-runtime-gvec.c
index ca449702e6..521da4a813 100644
--- a/accel/tcg/tcg-runtime-gvec.c
+++ b/accel/tcg/tcg-runtime-gvec.c
@@ -716,6 +716,54 @@ void HELPER(gvec_sar64i)(void *d, void *a, uint32_t desc)
clear_high(d, oprsz, desc);
}
+void HELPER(gvec_rotl8i)(void *d, void *a, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ int shift = simd_data(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = rol8(*(uint8_t *)(a + i), shift);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotl16i)(void *d, void *a, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ int shift = simd_data(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = rol16(*(uint16_t *)(a + i), shift);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotl32i)(void *d, void *a, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ int shift = simd_data(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = rol32(*(uint32_t *)(a + i), shift);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotl64i)(void *d, void *a, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ int shift = simd_data(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = rol64(*(uint64_t *)(a + i), shift);
+ }
+ clear_high(d, oprsz, desc);
+}
+
void HELPER(gvec_shl8v)(void *d, void *a, void *b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
@@ -860,6 +908,102 @@ void HELPER(gvec_sar64v)(void *d, void *a, void *b, uint32_t desc)
clear_high(d, oprsz, desc);
}
+void HELPER(gvec_rotl8v)(void *d, void *a, void *b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ uint8_t sh = *(uint8_t *)(b + i) & 7;
+ *(uint8_t *)(d + i) = rol8(*(uint8_t *)(a + i), sh);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotl16v)(void *d, void *a, void *b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ uint8_t sh = *(uint16_t *)(b + i) & 15;
+ *(uint16_t *)(d + i) = rol16(*(uint16_t *)(a + i), sh);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotl32v)(void *d, void *a, void *b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ uint8_t sh = *(uint32_t *)(b + i) & 31;
+ *(uint32_t *)(d + i) = rol32(*(uint32_t *)(a + i), sh);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotl64v)(void *d, void *a, void *b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ uint8_t sh = *(uint64_t *)(b + i) & 63;
+ *(uint64_t *)(d + i) = rol64(*(uint64_t *)(a + i), sh);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotr8v)(void *d, void *a, void *b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ uint8_t sh = *(uint8_t *)(b + i) & 7;
+ *(uint8_t *)(d + i) = ror8(*(uint8_t *)(a + i), sh);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotr16v)(void *d, void *a, void *b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ uint8_t sh = *(uint16_t *)(b + i) & 15;
+ *(uint16_t *)(d + i) = ror16(*(uint16_t *)(a + i), sh);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotr32v)(void *d, void *a, void *b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ uint8_t sh = *(uint32_t *)(b + i) & 31;
+ *(uint32_t *)(d + i) = ror32(*(uint32_t *)(a + i), sh);
+ }
+ clear_high(d, oprsz, desc);
+}
+
+void HELPER(gvec_rotr64v)(void *d, void *a, void *b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ uint8_t sh = *(uint64_t *)(b + i) & 63;
+ *(uint64_t *)(d + i) = ror64(*(uint64_t *)(a + i), sh);
+ }
+ clear_high(d, oprsz, desc);
+}
+
#define DO_CMP1(NAME, TYPE, OP) \
void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \
{ \
diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h
index 4fa61b49b4..4eda24e63a 100644
--- a/accel/tcg/tcg-runtime.h
+++ b/accel/tcg/tcg-runtime.h
@@ -259,6 +259,11 @@ DEF_HELPER_FLAGS_3(gvec_sar16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_sar32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_sar64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(gvec_rotl8i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(gvec_rotl16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(gvec_rotl32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(gvec_rotl64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+
DEF_HELPER_FLAGS_4(gvec_shl8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shl16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shl32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@@ -274,6 +279,16 @@ DEF_HELPER_FLAGS_4(gvec_sar16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_sar32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_sar64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_rotl8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_rotl16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_rotl32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_rotl64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+
+DEF_HELPER_FLAGS_4(gvec_rotr8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_rotr16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_rotr32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(gvec_rotr64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+
DEF_HELPER_FLAGS_4(gvec_eq8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_eq16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_eq32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 52359949df..d8b027f8c1 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -517,6 +517,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
#if defined(__NetBSD__)
#include <ucontext.h>
+#include <sys/siginfo.h>
#endif
int cpu_signal_handler(int host_signum, void *pinfo,
@@ -525,10 +526,12 @@ int cpu_signal_handler(int host_signum, void *pinfo,
siginfo_t *info = pinfo;
#if defined(__NetBSD__)
ucontext_t *uc = puc;
+ siginfo_t *si = pinfo;
#else
ucontext_t *uc = puc;
#endif
unsigned long pc;
+ uint32_t fsr;
int is_write;
#if defined(__NetBSD__)
@@ -539,15 +542,48 @@ int cpu_signal_handler(int host_signum, void *pinfo,
pc = uc->uc_mcontext.arm_pc;
#endif
- /* error_code is the FSR value, in which bit 11 is WnR (assuming a v6 or
- * later processor; on v5 we will always report this as a read).
+#ifdef __NetBSD__
+ fsr = si->si_trap;
+#else
+ fsr = uc->uc_mcontext.error_code;
+#endif
+ /*
+ * In the FSR, bit 11 is WnR, assuming a v6 or
+ * later processor. On v5 we will always report
+ * this as a read, which will fail later.
*/
- is_write = extract32(uc->uc_mcontext.error_code, 11, 1);
+ is_write = extract32(fsr, 11, 1);
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}
#elif defined(__aarch64__)
+#if defined(__NetBSD__)
+
+#include <ucontext.h>
+#include <sys/siginfo.h>
+
+int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
+{
+ ucontext_t *uc = puc;
+ siginfo_t *si = pinfo;
+ unsigned long pc;
+ int is_write;
+ uint32_t esr;
+
+ pc = uc->uc_mcontext.__gregs[_REG_PC];
+ esr = si->si_trap;
+
+ /*
+ * siginfo_t::si_trap is the ESR value, for data aborts ESR.EC
+ * is 0b10010x: then bit 6 is the WnR bit
+ */
+ is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
+ return handle_cpu_signal(pc, si, is_write, &uc->uc_sigmask);
+}
+
+#else
+
#ifndef ESR_MAGIC
/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
#define ESR_MAGIC 0x45535201
@@ -610,6 +646,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
}
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}
+#endif
#elif defined(__s390__)
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 4ee4354898..61e3255f5c 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -383,8 +383,10 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
assert(sizeof(backend->host_nodes) >=
BITS_TO_LONGS(MAX_NODES + 1) * sizeof(unsigned long));
assert(maxnode <= MAX_NODES);
- if (mbind(ptr, sz, backend->policy,
- maxnode ? backend->host_nodes : NULL, maxnode + 1, flags)) {
+
+ if (maxnode &&
+ mbind(ptr, sz, backend->policy, backend->host_nodes, maxnode + 1,
+ flags)) {
if (backend->policy != MPOL_DEFAULT || errno != ENOSYS) {
error_setg_errno(errp, errno,
"cannot bind memory to host NUMA nodes");
diff --git a/block/crypto.c b/block/crypto.c
index b216e12c31..973b57b3eb 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -552,7 +552,7 @@ static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts,
* Unallocated blocks are still encrypted so allocation status makes no
* difference to the file size.
*/
- info = g_new(BlockMeasureInfo, 1);
+ info = g_new0(BlockMeasureInfo, 1);
info->fully_allocated = luks_payload_size + size;
info->required = luks_payload_size + size;
return info;
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index f9bfc77985..c01319b188 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -818,6 +818,19 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
return false;
}
+bool bdrv_has_named_bitmaps(BlockDriverState *bs)
+{
+ BdrvDirtyBitmap *bm;
+
+ QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
+ if (bdrv_dirty_bitmap_name(bm)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap, bool persistent)
{
diff --git a/block/io.c b/block/io.c
index 121ce17a49..df8f2a98d4 100644
--- a/block/io.c
+++ b/block/io.c
@@ -35,8 +35,6 @@
#include "qemu/main-loop.h"
#include "sysemu/replay.h"
-#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
-
/* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
#define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
@@ -891,29 +889,63 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
return 0;
}
+typedef int coroutine_fn BdrvRequestEntry(void *opaque);
+typedef struct BdrvRunCo {
+ BdrvRequestEntry *entry;
+ void *opaque;
+ int ret;
+ bool done;
+ Coroutine *co; /* Coroutine, running bdrv_run_co_entry, for debugging */
+} BdrvRunCo;
+
+static void coroutine_fn bdrv_run_co_entry(void *opaque)
+{
+ BdrvRunCo *arg = opaque;
+
+ arg->ret = arg->entry(arg->opaque);
+ arg->done = true;
+ aio_wait_kick();
+}
+
+static int bdrv_run_co(BlockDriverState *bs, BdrvRequestEntry *entry,
+ void *opaque)
+{
+ if (qemu_in_coroutine()) {
+ /* Fast-path if already in coroutine context */
+ return entry(opaque);
+ } else {
+ BdrvRunCo s = { .entry = entry, .opaque = opaque };
+
+ s.co = qemu_coroutine_create(bdrv_run_co_entry, &s);
+ bdrv_coroutine_enter(bs, s.co);
+
+ BDRV_POLL_WHILE(bs, !s.done);
+
+ return s.ret;
+ }
+}
+
typedef struct RwCo {
BdrvChild *child;
int64_t offset;
QEMUIOVector *qiov;
bool is_write;
- int ret;
BdrvRequestFlags flags;
} RwCo;
-static void coroutine_fn bdrv_rw_co_entry(void *opaque)
+static int coroutine_fn bdrv_rw_co_entry(void *opaque)
{
RwCo *rwco = opaque;
if (!rwco->is_write) {
- rwco->ret = bdrv_co_preadv(rwco->child, rwco->offset,
- rwco->qiov->size, rwco->qiov,
- rwco->flags);
+ return bdrv_co_preadv(rwco->child, rwco->offset,
+ rwco->qiov->size, rwco->qiov,
+ rwco->flags);
} else {
- rwco->ret = bdrv_co_pwritev(rwco->child, rwco->offset,
- rwco->qiov->size, rwco->qiov,
- rwco->flags);
+ return bdrv_co_pwritev(rwco->child, rwco->offset,
+ rwco->qiov->size, rwco->qiov,
+ rwco->flags);
}
- aio_wait_kick();
}
/*
@@ -923,25 +955,15 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
QEMUIOVector *qiov, bool is_write,
BdrvRequestFlags flags)
{
- Coroutine *co;
RwCo rwco = {
.child = child,
.offset = offset,
.qiov = qiov,
.is_write = is_write,
- .ret = NOT_DONE,
.flags = flags,
};
- if (qemu_in_coroutine()) {
- /* Fast-path if already in coroutine context */
- bdrv_rw_co_entry(&rwco);
- } else {
- co = qemu_coroutine_create(bdrv_rw_co_entry, &rwco);
- bdrv_coroutine_enter(child->bs, co);
- BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE);
- }
- return rwco.ret;
+ return bdrv_run_co(child->bs, bdrv_rw_co_entry, &rwco);
}
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
@@ -2229,8 +2251,6 @@ typedef struct BdrvCoBlockStatusData {
int64_t *pnum;
int64_t *map;
BlockDriverState **file;
- int ret;
- bool done;
} BdrvCoBlockStatusData;
int coroutine_fn bdrv_co_block_status_from_file(BlockDriverState *bs,
@@ -2484,16 +2504,14 @@ static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
}
/* Coroutine wrapper for bdrv_block_status_above() */
-static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
+static int coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
{
BdrvCoBlockStatusData *data = opaque;
- data->ret = bdrv_co_block_status_above(data->bs, data->base,
- data->want_zero,
- data->offset, data->bytes,
- data->pnum, data->map, data->file);
- data->done = true;
- aio_wait_kick();
+ return bdrv_co_block_status_above(data->bs, data->base,
+ data->want_zero,
+ data->offset, data->bytes,
+ data->pnum, data->map, data->file);
}
/*
@@ -2508,7 +2526,6 @@ static int bdrv_common_block_status_above(BlockDriverState *bs,
int64_t *map,
BlockDriverState **file)
{
- Coroutine *co;
BdrvCoBlockStatusData data = {
.bs = bs,
.base = base,
@@ -2518,18 +2535,9 @@ static int bdrv_common_block_status_above(BlockDriverState *bs,
.pnum = pnum,
.map = map,
.file = file,
- .done = false,
};
- if (qemu_in_coroutine()) {
- /* Fast-path if already in coroutine context */
- bdrv_block_status_above_co_entry(&data);
- } else {
- co = qemu_coroutine_create(bdrv_block_status_above_co_entry, &data);
- bdrv_coroutine_enter(bs, co);
- BDRV_POLL_WHILE(bs, !data.done);
- }
- return data.ret;
+ return bdrv_run_co(bs, bdrv_block_status_above_co_entry, &data);
}
int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
@@ -2630,7 +2638,6 @@ typedef struct BdrvVmstateCo {
QEMUIOVector *qiov;
int64_t pos;
bool is_read;
- int ret;
} BdrvVmstateCo;
static int coroutine_fn
@@ -2658,33 +2665,25 @@ bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
return ret;
}
-static void coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque)
+static int coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque)
{
BdrvVmstateCo *co = opaque;
- co->ret = bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read);
- aio_wait_kick();
+
+ return bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read);
}
static inline int
bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
bool is_read)
{
- if (qemu_in_coroutine()) {
- return bdrv_co_rw_vmstate(bs, qiov, pos, is_read);
- } else {
- BdrvVmstateCo data = {
- .bs = bs,
- .qiov = qiov,
- .pos = pos,
- .is_read = is_read,
- .ret = -EINPROGRESS,
- };
- Coroutine *co = qemu_coroutine_create(bdrv_co_rw_vmstate_entry, &data);
+ BdrvVmstateCo data = {
+ .bs = bs,
+ .qiov = qiov,
+ .pos = pos,
+ .is_read = is_read,
+ };
- bdrv_coroutine_enter(bs, co);
- BDRV_POLL_WHILE(bs, data.ret == -EINPROGRESS);
- return data.ret;
- }
+ return bdrv_run_co(bs, bdrv_co_rw_vmstate_entry, &data);
}
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
@@ -2762,18 +2761,9 @@ void bdrv_aio_cancel_async(BlockAIOCB *acb)
/**************************************************************/
/* Coroutine block device emulation */
-typedef struct FlushCo {
- BlockDriverState *bs;
- int ret;
-} FlushCo;
-
-
-static void coroutine_fn bdrv_flush_co_entry(void *opaque)
+static int coroutine_fn bdrv_flush_co_entry(void *opaque)
{
- FlushCo *rwco = opaque;
-
- rwco->ret = bdrv_co_flush(rwco->bs);
- aio_wait_kick();
+ return bdrv_co_flush(opaque);
}
int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
@@ -2890,36 +2880,20 @@ early_exit:
int bdrv_flush(BlockDriverState *bs)
{
- Coroutine *co;
- FlushCo flush_co = {
- .bs = bs,
- .ret = NOT_DONE,
- };
-
- if (qemu_in_coroutine()) {
- /* Fast-path if already in coroutine context */
- bdrv_flush_co_entry(&flush_co);
- } else {
- co = qemu_coroutine_create(bdrv_flush_co_entry, &flush_co);
- bdrv_coroutine_enter(bs, co);
- BDRV_POLL_WHILE(bs, flush_co.ret == NOT_DONE);
- }
-
- return flush_co.ret;
+ return bdrv_run_co(bs, bdrv_flush_co_entry, bs);
}
typedef struct DiscardCo {
BdrvChild *child;
int64_t offset;
int64_t bytes;
- int ret;
} DiscardCo;
-static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
+
+static int coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
{
DiscardCo *rwco = opaque;
- rwco->ret = bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes);
- aio_wait_kick();
+ return bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes);
}
int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
@@ -3038,24 +3012,13 @@ out:
int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
{
- Coroutine *co;
DiscardCo rwco = {
.child = child,
.offset = offset,
.bytes = bytes,
- .ret = NOT_DONE,
};
- if (qemu_in_coroutine()) {
- /* Fast-path if already in coroutine context */
- bdrv_pdiscard_co_entry(&rwco);
- } else {
- co = qemu_coroutine_create(bdrv_pdiscard_co_entry, &rwco);
- bdrv_coroutine_enter(child->bs, co);
- BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE);
- }
-
- return rwco.ret;
+ return bdrv_run_co(child->bs, bdrv_pdiscard_co_entry, &rwco);
}
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
@@ -3463,21 +3426,19 @@ typedef struct TruncateCo {
PreallocMode prealloc;
BdrvRequestFlags flags;
Error **errp;
- int ret;
} TruncateCo;
-static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
+static int coroutine_fn bdrv_truncate_co_entry(void *opaque)
{
TruncateCo *tco = opaque;
- tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
- tco->prealloc, tco->flags, tco->errp);
- aio_wait_kick();
+
+ return bdrv_co_truncate(tco->child, tco->offset, tco->exact,
+ tco->prealloc, tco->flags, tco->errp);
}
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{
- Coroutine *co;
TruncateCo tco = {
.child = child,
.offset = offset,
@@ -3485,17 +3446,7 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
.prealloc = prealloc,
.flags = flags,
.errp = errp,
- .ret = NOT_DONE,
};
- if (qemu_in_coroutine()) {
- /* Fast-path if already in coroutine context */
- bdrv_truncate_co_entry(&tco);
- } else {
- co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco);
- bdrv_coroutine_enter(child->bs, co);
- BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE);
- }
-
- return tco.ret;
+ return bdrv_run_co(child->bs, bdrv_truncate_co_entry, &tco);
}
diff --git a/block/io_uring.c b/block/io_uring.c
index a3142ca989..037af09471 100644
--- a/block/io_uring.c
+++ b/block/io_uring.c
@@ -231,7 +231,7 @@ static int ioq_submit(LuringState *s)
trace_luring_io_uring_submit(s, ret);
/* Prevent infinite loop if submission is refused */
if (ret <= 0) {
- if (ret == -EAGAIN) {
+ if (ret == -EAGAIN || ret == -EINTR) {
continue;
}
break;
@@ -277,13 +277,10 @@ static void qemu_luring_completion_cb(void *opaque)
static bool qemu_luring_poll_cb(void *opaque)
{
LuringState *s = opaque;
- struct io_uring_cqe *cqes;
- if (io_uring_peek_cqe(&s->ring, &cqes) == 0) {
- if (cqes) {
- luring_process_completions_and_submit(s);
- return true;
- }
+ if (io_uring_cq_ready(&s->ring)) {
+ luring_process_completions_and_submit(s);
+ return true;
}
return false;
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 1cf6d2ab77..7bf12502da 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -1755,3 +1755,39 @@ bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs)
return s->qcow_version >= 3;
}
+
+/*
+ * Compute the space required for bitmaps in @bs.
+ *
+ * The computation is based as if copying to a new image with the
+ * given @cluster_size, which may differ from the cluster size in @bs.
+ */
+uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs,
+ uint32_t cluster_size)
+{
+ uint64_t bitmaps_size = 0;
+ BdrvDirtyBitmap *bm;
+ size_t bitmap_dir_size = 0;
+
+ FOR_EACH_DIRTY_BITMAP(bs, bm) {
+ if (bdrv_dirty_bitmap_get_persistence(bm)) {
+ const char *name = bdrv_dirty_bitmap_name(bm);
+ uint32_t granularity = bdrv_dirty_bitmap_granularity(bm);
+ uint64_t bmbytes =
+ get_bitmap_bytes_needed(bdrv_dirty_bitmap_size(bm),
+ granularity);
+ uint64_t bmclusters = DIV_ROUND_UP(bmbytes, cluster_size);
+
+ /* Assume the entire bitmap is allocated */
+ bitmaps_size += bmclusters * cluster_size;
+ /* Also reserve space for the bitmap table entries */
+ bitmaps_size += ROUND_UP(bmclusters * sizeof(uint64_t),
+ cluster_size);
+ /* And space for contribution to bitmap directory size */
+ bitmap_dir_size += calc_dir_entry_size(strlen(name), 0);
+ }
+ }
+ bitmaps_size += ROUND_UP(bitmap_dir_size, cluster_size);
+
+ return bitmaps_size;
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index dfab8d2f6c..0cd2e6757e 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -4953,16 +4953,24 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
required = virtual_size;
}
- info = g_new(BlockMeasureInfo, 1);
+ info = g_new0(BlockMeasureInfo, 1);
info->fully_allocated =
qcow2_calc_prealloc_size(virtual_size, cluster_size,
ctz32(refcount_bits)) + luks_payload_size;
- /* Remove data clusters that are not required. This overestimates the
+ /*
+ * Remove data clusters that are not required. This overestimates the
* required size because metadata needed for the fully allocated file is
- * still counted.
+ * still counted. Show bitmaps only if both source and destination
+ * would support them.
*/
info->required = info->fully_allocated - virtual_size + required;
+ info->has_bitmaps = version >= 3 && in_bs &&
+ bdrv_supports_persistent_dirty_bitmap(in_bs);
+ if (info->has_bitmaps) {
+ info->bitmaps = qcow2_get_persistent_dirty_bitmap_size(in_bs,
+ cluster_size);
+ }
return info;
err:
diff --git a/block/qcow2.h b/block/qcow2.h
index 402e8acb1c..7ce2c23bdb 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -783,6 +783,8 @@ int qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
const char *name,
Error **errp);
bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs);
+uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs,
+ uint32_t cluster_size);
ssize_t coroutine_fn
qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
diff --git a/block/raw-format.c b/block/raw-format.c
index 018441bddf..233d019ca3 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -359,7 +359,7 @@ static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_bs,
BDRV_SECTOR_SIZE);
}
- info = g_new(BlockMeasureInfo, 1);
+ info = g_new0(BlockMeasureInfo, 1);
info->required = required;
/* Unallocated sectors count towards the file size in raw images */
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index e77699db48..db253d4024 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -138,8 +138,9 @@ static void check_report_connect_error(Chardev *chr,
SocketChardev *s = SOCKET_CHARDEV(chr);
if (!s->connect_err_reported) {
- error_report("Unable to connect character device %s: %s",
- chr->label, error_get_pretty(err));
+ error_reportf_err(err,
+ "Unable to connect character device %s: ",
+ chr->label);
s->connect_err_reported = true;
}
qemu_chr_socket_restart_timer(chr);
diff --git a/configure b/configure
index fccc56bd4d..597e909b53 100755
--- a/configure
+++ b/configure
@@ -198,7 +198,7 @@ supported_kvm_target() {
arm:arm | aarch64:aarch64 | \
i386:i386 | i386:x86_64 | i386:x32 | \
x86_64:i386 | x86_64:x86_64 | x86_64:x32 | \
- mips:mips | mipsel:mips | \
+ mips:mips | mipsel:mips | mips64:mips | mips64el:mips | \
ppc:ppc | ppc64:ppc | ppc:ppc64 | ppc64:ppc64 | ppc64:ppc64le | \
s390x:s390x)
return 0
@@ -941,7 +941,7 @@ done
# Check for ancillary tools used in testing
genisoimage=
-for binary in genisoimage
+for binary in genisoimage mkisofs
do
if has $binary
then
diff --git a/cpus-common.c b/cpus-common.c
index 55d5df8923..70a9d12981 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -61,13 +61,15 @@ static bool cpu_index_auto_assigned;
static int cpu_get_free_index(void)
{
CPUState *some_cpu;
- int cpu_index = 0;
+ int max_cpu_index = 0;
cpu_index_auto_assigned = true;
CPU_FOREACH(some_cpu) {
- cpu_index++;
+ if (some_cpu->cpu_index >= max_cpu_index) {
+ max_cpu_index = some_cpu->cpu_index + 1;
+ }
}
- return cpu_index;
+ return max_cpu_index;
}
void cpu_list_add(CPUState *cpu)
@@ -90,8 +92,6 @@ void cpu_list_remove(CPUState *cpu)
return;
}
- assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus)));
-
QTAILQ_REMOVE_RCU(&cpus, cpu, node);
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
}
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 8b0c9b1e15..9f8a3ef156 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -2,7 +2,7 @@
include mips-softmmu-common.mak
CONFIG_IDE_VIA=y
-CONFIG_FULONG=y
+CONFIG_FULOONG=y
CONFIG_ATI_VGA=y
CONFIG_RTL8139_PCI=y
CONFIG_JAZZ=y
diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
index 1ae077ed87..94a236c9c2 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -10,3 +10,4 @@ CONFIG_SPIKE=y
CONFIG_SIFIVE_E=y
CONFIG_SIFIVE_U=y
CONFIG_RISCV_VIRT=y
+CONFIG_OPENTITAN=y
diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
index 235c6f473f..aaf6d735bb 100644
--- a/default-configs/riscv64-softmmu.mak
+++ b/default-configs/riscv64-softmmu.mak
@@ -1,3 +1,12 @@
# Default configuration for riscv64-softmmu
-include riscv32-softmmu.mak
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_PCI_DEVICES=n
+
+# Boards:
+#
+CONFIG_SPIKE=y
+CONFIG_SIFIVE_E=y
+CONFIG_SIFIVE_U=y
+CONFIG_RISCV_VIRT=y
diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
new file mode 100644
index 0000000000..45f891eb3c
--- /dev/null
+++ b/docs/system/arm/aspeed.rst
@@ -0,0 +1,85 @@
+Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``)
+==================================================================
+
+The QEMU Aspeed machines model BMCs of various OpenPOWER systems and
+Aspeed evaluation boards. They are based on different releases of the
+Aspeed SoC : the AST2400 integrating an ARM926EJ-S CPU (400MHz), the
+AST2500 with an ARM1176JZS CPU (800MHz) and more recently the AST2600
+with dual cores ARM Cortex A7 CPUs (1.2GHz).
+
+The SoC comes with RAM, Gigabit ethernet, USB, SD/MMC, USB, SPI, I2C,
+etc.
+
+AST2400 SoC based machines :
+
+- ``palmetto-bmc`` OpenPOWER Palmetto POWER8 BMC
+
+AST2500 SoC based machines :
+
+- ``ast2500-evb`` Aspeed AST2500 Evaluation board
+- ``romulus-bmc`` OpenPOWER Romulus POWER9 BMC
+- ``witherspoon-bmc`` OpenPOWER Witherspoon POWER9 BMC
+- ``sonorapass-bmc`` OCP SonoraPass BMC
+- ``swift-bmc`` OpenPOWER Swift BMC POWER9
+
+AST2600 SoC based machines :
+
+- ``ast2600-evb`` Aspeed AST2600 Evaluation board (Cortex A7)
+- ``tacoma-bmc`` OpenPOWER Witherspoon POWER9 AST2600 BMC
+
+Supported devices
+-----------------
+
+ * SMP (for the AST2600 Cortex-A7)
+ * Interrupt Controller (VIC)
+ * Timer Controller
+ * RTC Controller
+ * I2C Controller
+ * System Control Unit (SCU)
+ * SRAM mapping
+ * X-DMA Controller (basic interface)
+ * Static Memory Controller (SMC or FMC) - Only SPI Flash support
+ * SPI Memory Controller
+ * USB 2.0 Controller
+ * SD/MMC storage controllers
+ * SDRAM controller (dummy interface for basic settings and training)
+ * Watchdog Controller
+ * GPIO Controller (Master only)
+ * UART
+ * Ethernet controllers
+
+
+Missing devices
+---------------
+
+ * Coprocessor support
+ * ADC (out of tree implementation)
+ * PWM and Fan Controller
+ * LPC Bus Controller
+ * Slave GPIO Controller
+ * Super I/O Controller
+ * Hash/Crypto Engine
+ * PCI-Express 1 Controller
+ * Graphic Display Controller
+ * PECI Controller
+ * MCTP Controller
+ * Mailbox Controller
+ * Virtual UART
+ * eSPI Controller
+ * I3C Controller
+
+Boot options
+------------
+
+The Aspeed machines can be started using the -kernel option to load a
+Linux kernel or from a firmare image which can be downloaded from the
+OpenPOWER jenkins :
+
+ https://openpower.xyz/
+
+The image should be attached as an MTD drive. Run :
+
+.. code-block:: bash
+
+ $ qemu-system-arm -M romulus-bmc -nic user \
+ -drive file=flash-romulus,format=raw,if=mtd -nographic
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index 3142fac386..544ece0a45 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -138,25 +138,23 @@ the backing storage specified with ``-mem-path`` can actually provide
the guest RAM configured with ``-m`` and QEMU will fail to start up if
RAM allocation is unsuccessful.
-RISC-V ``-bios`` (since 4.1)
+RISC-V ``-bios`` (since 5.1)
''''''''''''''''''''''''''''
QEMU 4.1 introduced support for the -bios option in QEMU for RISC-V for the
-RISC-V virt machine and sifive_u machine.
-
-QEMU 4.1 has no changes to the default behaviour to avoid breakages. This
-default will change in a future QEMU release, so please prepare now. All users
-of the virt or sifive_u machine must change their command line usage.
-
-QEMU 4.1 has three options, please migrate to one of these three:
- 1. ``-bios none`` - This is the current default behavior if no -bios option
- is included. QEMU will not automatically load any firmware. It is up
+RISC-V virt machine and sifive_u machine. QEMU 4.1 had no changes to the
+default behaviour to avoid breakages.
+
+QEMU 5.1 changes the default behaviour from ``-bios none`` to ``-bios default``.
+
+QEMU 5.1 has three options:
+ 1. ``-bios default`` - This is the current default behavior if no -bios option
+ is included. This option will load the default OpenSBI firmware automatically.
+ The firmware is included with the QEMU release and no user interaction is
+ required. All a user needs to do is specify the kernel they want to boot
+ with the -kernel option
+ 2. ``-bios none`` - QEMU will not automatically load any firmware. It is up
to the user to load all the images they need.
- 2. ``-bios default`` - In a future QEMU release this will become the default
- behaviour if no -bios option is specified. This option will load the
- default OpenSBI firmware automatically. The firmware is included with
- the QEMU release and no user interaction is required. All a user needs
- to do is specify the kernel they want to boot with the -kernel option
3. ``-bios <file>`` - Tells QEMU to load the specified file as the firmwrae.
``-tb-size`` option (since 5.0)
@@ -301,34 +299,9 @@ The ``acl_show``, ``acl_reset``, ``acl_policy``, ``acl_add``, and
``acl_remove`` commands are deprecated with no replacement. Authorization
for VNC should be performed using the pluggable QAuthZ objects.
-Guest Emulator ISAs
--------------------
-
-RISC-V ISA privledge specification version 1.09.1 (since 4.1)
-'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-The RISC-V ISA privledge specification version 1.09.1 has been deprecated.
-QEMU supports both the newer version 1.10.0 and the ratified version 1.11.0, these
-should be used instead of the 1.09.1 version.
-
System emulator CPUS
--------------------
-RISC-V ISA CPUs (since 4.1)
-'''''''''''''''''''''''''''
-
-The RISC-V cpus with the ISA version in the CPU name have been depcreated. The
-four CPUs are: ``rv32gcsu-v1.9.1``, ``rv32gcsu-v1.10.0``, ``rv64gcsu-v1.9.1`` and
-``rv64gcsu-v1.10.0``. Instead the version can be specified via the CPU ``priv_spec``
-option when using the ``rv32`` or ``rv64`` CPUs.
-
-RISC-V ISA CPUs (since 4.1)
-'''''''''''''''''''''''''''
-
-The RISC-V no MMU cpus have been depcreated. The two CPUs: ``rv32imacu-nommu`` and
-``rv64imacu-nommu`` should no longer be used. Instead the MMU status can be specified
-via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
-
``compat`` property of server class POWER CPUs (since 5.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
@@ -368,19 +341,17 @@ mips ``r4k`` platform (since 5.0)
This machine type is very old and unmaintained. Users should use the ``malta``
machine type instead.
+mips ``fulong2e`` machine (since 5.1)
+'''''''''''''''''''''''''''''''''''''
+
+This machine has been renamed ``fuloong2e``.
+
``pc-1.0``, ``pc-1.1``, ``pc-1.2`` and ``pc-1.3`` (since 5.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
These machine types are very old and likely can not be used for live migration
from old QEMU versions anymore. A newer machine type should be used instead.
-``spike_v1.9.1`` and ``spike_v1.10`` (since 4.1)
-''''''''''''''''''''''''''''''''''''''''''''''''
-
-The version specific Spike machines have been deprecated in favour of the
-generic ``spike`` machine. If you need to specify an older version of the RISC-V
-spec you can use the ``-cpu rv64gcsu,priv_spec=v1.9.1`` command line argument.
-
Device options
--------------
@@ -488,6 +459,44 @@ The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0
The ``[hub_id name]`` parameter tuple of the 'hostfwd_add' and
'hostfwd_remove' HMP commands has been replaced by ``netdev_id``.
+Guest Emulator ISAs
+-------------------
+
+RISC-V ISA privledge specification version 1.09.1 (removed in 5.1)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The RISC-V ISA privledge specification version 1.09.1 has been removed.
+QEMU supports both the newer version 1.10.0 and the ratified version 1.11.0, these
+should be used instead of the 1.09.1 version.
+
+System emulator CPUS
+--------------------
+
+RISC-V ISA Specific CPUs (removed in 5.1)
+'''''''''''''''''''''''''''''''''''''''''
+
+The RISC-V cpus with the ISA version in the CPU name have been removed. The
+four CPUs are: ``rv32gcsu-v1.9.1``, ``rv32gcsu-v1.10.0``, ``rv64gcsu-v1.9.1`` and
+``rv64gcsu-v1.10.0``. Instead the version can be specified via the CPU ``priv_spec``
+option when using the ``rv32`` or ``rv64`` CPUs.
+
+RISC-V no MMU CPUs (removed in 5.1)
+'''''''''''''''''''''''''''''''''''
+
+The RISC-V no MMU cpus have been removed. The two CPUs: ``rv32imacu-nommu`` and
+``rv64imacu-nommu`` can no longer be used. Instead the MMU status can be specified
+via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
+
+System emulator machines
+------------------------
+
+``spike_v1.9.1`` and ``spike_v1.10`` (removed in 5.1)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The version specific Spike machines have been removed in favour of the
+generic ``spike`` machine. If you need to specify an older version of the RISC-V
+spec you can use the ``-cpu rv64gcsu,priv_spec=v1.10.0`` command line argument.
+
Related binaries
----------------
diff --git a/docs/system/s390x/3270.rst b/docs/system/s390x/3270.rst
new file mode 100644
index 0000000000..1774cdcadf
--- /dev/null
+++ b/docs/system/s390x/3270.rst
@@ -0,0 +1,32 @@
+3270 devices
+============
+
+QEMU supports connecting an external 3270 terminal emulator (such as
+``x3270``) to make a single 3270 device available to a guest. Note that this
+supports basic features only.
+
+To provide a 3270 device to a guest, create a ``x-terminal3270`` linked to
+a ``tn3270`` chardev. The guest will see a 3270 channel device. In order
+to actually be able to use it, attach the ``x3270`` emulator to the chardev.
+
+Example configuration
+---------------------
+
+* Add a ``tn3270`` chardev and a ``x-terminal3270`` to the QEMU command line::
+
+ -chardev socket,id=char_0,host=0.0.0.0,port=2300,nowait,server,tn3270
+ -device x-terminal3270,chardev=char_0,devno=fe.0.000a,id=terminal_0
+
+* Start the guest. In the guest, use ``chccwdev -e 0.0.000a`` to enable
+ the device.
+
+* On the host, start the ``x3270`` emulator::
+
+ x3270 <host>:2300
+
+* In the guest, locate the 3270 device node under ``/dev/3270/`` (say,
+ ``tty1``) and start a getty on it::
+
+ systemctl start serial-getty@3270-tty1.service
+
+This should get you an addtional tty for logging into the guest.
diff --git a/docs/system/s390x/css.rst b/docs/system/s390x/css.rst
new file mode 100644
index 0000000000..3b40161184
--- /dev/null
+++ b/docs/system/s390x/css.rst
@@ -0,0 +1,86 @@
+The virtual channel subsystem
+=============================
+
+QEMU implements a virtual channel subsystem with subchannels, (mostly
+functionless) channel paths, and channel devices (virtio-ccw, 3270, and
+devices passed via vfio-ccw). It supports multiple subchannel sets (MSS) and
+multiple channel subsystems extended (MCSS-E).
+
+All channel devices support the ``devno`` property, which takes a parameter
+in the form ``<cssid>.<ssid>.<device number>``.
+
+The default channel subsystem image id (``<cssid>``) is ``0xfe``. Devices in
+there will show up in channel subsystem image ``0`` to guests that do not
+enable MCSS-E. Note that devices with a different cssid will not be visible
+if the guest OS does not enable MCSS-E (which is true for all supported guest
+operating systems today).
+
+Supported values for the subchannel set id (``<ssid>``) range from ``0-3``.
+Devices with a ssid that is not ``0`` will not be visible if the guest OS
+does not enable MSS (any Linux version that supports virtio also enables MSS).
+Any device may be put into any subchannel set, there is no restriction by
+device type.
+
+The device number can range from ``0-0xffff``.
+
+If the ``devno`` property is not specified for a device, QEMU will choose the
+next free device number in subchannel set 0, skipping to the next subchannel
+set if no more device numbers are free.
+
+QEMU places a device at the first free subchannel in the specified subchannel
+set. If a device is hotunplugged and later replugged, it may appear at a
+different subchannel. (This is similar to how z/VM works.)
+
+
+Examples
+--------
+
+* a virtio-net device, cssid/ssid/devno automatically assigned::
+
+ -device virtio-net-ccw
+
+ In a Linux guest (without default devices and no other devices specified
+ prior to this one), this will show up as ``0.0.0000`` under subchannel
+ ``0.0.0000``.
+
+ The auto-assigned-properties in QEMU (as seen via e.g. ``info qtree``)
+ would be ``dev_id = "fe.0.0000"`` and ``subch_id = "fe.0.0000"``.
+
+* a virtio-rng device in subchannel set ``0``::
+
+ -device virtio-rng-ccw,devno=fe.0.0042
+
+ If added to the same Linux guest as above, it would show up as ``0.0.0042``
+ under subchannel ``0.0.0001``.
+
+ The properties for the device would be ``dev_id = "fe.0.0042"`` and
+ ``subch_id = "fe.0.0001"``.
+
+* a virtio-gpu device in subchannel set ``2``::
+
+ -device virtio-gpu-ccw,devno=fe.2.1111
+
+ If added to the same Linux guest as above, it would show up as ``0.2.1111``
+ under subchannel ``0.2.0000``.
+
+ The properties for the device would be ``dev_id = "fe.2.1111"`` and
+ ``subch_id = "fe.2.0000"``.
+
+* a virtio-mouse device in a non-standard channel subsystem image::
+
+ -device virtio-mouse-ccw,devno=2.0.2222
+
+ This would not show up in a standard Linux guest.
+
+ The properties for the device would be ``dev_id = "2.0.2222"`` and
+ ``subch_id = "2.0.0000"``.
+
+* a virtio-keyboard device in another non-standard channel subsystem image::
+
+ -device virtio-keyboard-ccw,devno=0.0.1234
+
+ This would not show up in a standard Linux guest, either, as ``0`` is not
+ the standard channel subsystem image id.
+
+ The properties for the device would be ``dev_id = "0.0.1234"`` and
+ ``subch_id = "0.0.0000"``.
diff --git a/docs/system/s390x/vfio-ccw.rst b/docs/system/s390x/vfio-ccw.rst
new file mode 100644
index 0000000000..8f65442c0f
--- /dev/null
+++ b/docs/system/s390x/vfio-ccw.rst
@@ -0,0 +1,77 @@
+Subchannel passthrough via vfio-ccw
+===================================
+
+vfio-ccw (based upon the mediated vfio device infrastructure) allows to
+make certain I/O subchannels and their devices available to a guest. The
+host will not interact with those subchannels/devices any more.
+
+Note that while vfio-ccw should work with most non-QDIO devices, only ECKD
+DASDs have really been tested.
+
+Example configuration
+---------------------
+
+Step 1: configure the host device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As every mdev is identified by a uuid, the first step is to obtain one::
+
+ [root@host ~]# uuidgen
+ 7e270a25-e163-4922-af60-757fc8ed48c6
+
+Note: it is recommended to use the ``mdevctl`` tool for actually configuring
+the host device.
+
+To define the same device as configured below to be started
+automatically, use
+
+::
+
+ [root@host ~]# driverctl -b css set-override 0.0.0313 vfio_ccw
+ [root@host ~]# mdevctl define -u 7e270a25-e163-4922-af60-757fc8ed48c6 \
+ -p 0.0.0313 -t vfio-ccw_io -a
+
+If using ``mdevctl`` is not possible or wanted, follow the manual procedure
+below.
+
+* Locate the subchannel for the device (in this example, ``0.0.2b09``)::
+
+ [root@host ~]# lscss | grep 0.0.2b09 | awk '{print $2}'
+ 0.0.0313
+
+* Unbind the subchannel (in this example, ``0.0.0313``) from the standard
+ I/O subchannel driver and bind it to the vfio-ccw driver::
+
+ [root@host ~]# echo 0.0.0313 > /sys/bus/css/devices/0.0.0313/driver/unbind
+ [root@host ~]# echo 0.0.0313 > /sys/bus/css/drivers/vfio_ccw/bind
+
+* Create the mediated device (identified by the uuid)::
+
+ [root@host ~]# echo "7e270a25-e163-4922-af60-757fc8ed48c6" > \
+ /sys/bus/css/devices/0.0.0313/mdev_supported_types/vfio_ccw-io/create
+
+Step 2: configure QEMU
+~~~~~~~~~~~~~~~~~~~~~~
+
+* Reference the created mediated device and (optionally) pick a device id to
+ be presented in the guest (here, ``fe.0.1234``, which will end up visible
+ in the guest as ``0.0.1234``::
+
+ -device vfio-ccw,devno=fe.0.1234,sysfsdev=\
+ /sys/bus/mdev/devices/7e270a25-e163-4922-af60-757fc8ed48c6
+
+* Start the guest. The device (here, ``0.0.1234``) should now be usable::
+
+ [root@guest ~]# lscss -d 0.0.1234
+ Device Subchan. DevType CU Type Use PIM PAM POM CHPID
+ ----------------------------------------------------------------------
+ 0.0.1234 0.0.0007 3390/0e 3990/e9 f0 f0 ff 1a2a3a0a 00000000
+ [root@guest ~]# chccwdev -e 0.0.1234
+ Setting device 0.0.1234 online
+ Done
+ [root@guest ~]# dmesg -t
+ (...)
+ dasd-eckd 0.0.1234: A channel path to the device has become operational
+ dasd-eckd 0.0.1234: New DASD 3390/0E (CU 3990/01) with 10017 cylinders, 15 heads, 224 sectors
+ dasd-eckd 0.0.1234: DASD with 4 KB/block, 7212240 KB total size, 48 KB/track, compatible disk layout
+ dasda:VOL1/ 0X2B09: dasda1
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
index dce384cb0e..1bd477a293 100644
--- a/docs/system/target-arm.rst
+++ b/docs/system/target-arm.rst
@@ -81,6 +81,7 @@ undocumented; you can get a complete list by running
arm/realview
arm/versatile
arm/vexpress
+ arm/aspeed
arm/musicpal
arm/nseries
arm/orangepi
diff --git a/docs/system/target-mips.rst b/docs/system/target-mips.rst
index 2736fd0509..cd2a931edf 100644
--- a/docs/system/target-mips.rst
+++ b/docs/system/target-mips.rst
@@ -74,7 +74,7 @@ The MIPS Magnum R4000 emulation supports:
- G364 framebuffer
-The Fulong 2E emulation supports:
+The Fuloong 2E emulation supports:
- Loongson 2E CPU
diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst
index 7d76ae97b4..644e404ef9 100644
--- a/docs/system/target-s390x.rst
+++ b/docs/system/target-s390x.rst
@@ -23,6 +23,9 @@ or vfio-ap is also available.
.. toctree::
s390x/vfio-ap
+ s390x/css
+ s390x/3270
+ s390x/vfio-ccw
Architectural features
======================
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 38d464ea3f..69cd9a3037 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -162,6 +162,10 @@ Parameters to convert subcommand:
.. program:: qemu-img-convert
+.. option:: --bitmaps
+
+ Additionally copy all persistent bitmaps from the top layer of the source
+
.. option:: -n
Skip the creation of the target volume
@@ -397,7 +401,7 @@ Command description:
4
Error on reading data
-.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
+.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM*
to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can
@@ -616,6 +620,7 @@ Command description:
required size: 524288
fully allocated size: 1074069504
+ bitmaps size: 0
The ``required size`` is the file size of the new image. It may be smaller
than the virtual disk size if the image format supports compact representation.
@@ -625,6 +630,12 @@ Command description:
occupy with the exception of internal snapshots, dirty bitmaps, vmstate data,
and other advanced image format features.
+ The ``bitmaps size`` is the additional size required in order to
+ copy bitmaps from a source image in addition to the guest-visible
+ data; the line is omitted if either source or destination lacks
+ bitmap support, or 0 if bitmaps are supported but there is nothing
+ to copy.
+
.. option:: snapshot [--object OBJECTDEF] [--image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
List, apply, create or delete snapshots in image *FILENAME*.
diff --git a/exec.c b/exec.c
index 6dfd314469..be4be2df3a 100644
--- a/exec.c
+++ b/exec.c
@@ -2129,7 +2129,7 @@ int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp)
* Otherwise no-op.
* @Note: this is supposed to be a synchronous op.
*/
-void qemu_ram_writeback(RAMBlock *block, ram_addr_t start, ram_addr_t length)
+void qemu_ram_msync(RAMBlock *block, ram_addr_t start, ram_addr_t length)
{
/* The requested range should fit in within the block range */
g_assert((start + length) <= block->used_length);
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 7f0f3974ad..28256209b5 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1791,8 +1791,22 @@ SRST
ERST
{
+ .name = "qom-get",
+ .args_type = "path:s,property:s",
+ .params = "path property",
+ .help = "print QOM property",
+ .cmd = hmp_qom_get,
+ .flags = "p",
+ },
+
+SRST
+``qom-get`` *path* *property*
+ Print QOM property *property* of object at location *path*
+ERST
+
+ {
.name = "qom-set",
- .args_type = "path:s,property:s,value:s",
+ .args_type = "path:s,property:s,value:S",
.params = "path property value",
.help = "set QOM property",
.cmd = hmp_qom_set,
diff --git a/hw/adc/stm32f2xx_adc.c b/hw/adc/stm32f2xx_adc.c
index 4f9d485ecf..01a0b14e69 100644
--- a/hw/adc/stm32f2xx_adc.c
+++ b/hw/adc/stm32f2xx_adc.c
@@ -246,6 +246,8 @@ static const MemoryRegionOps stm32f2xx_adc_ops = {
.read = stm32f2xx_adc_read,
.write = stm32f2xx_adc_write,
.endianness = DEVICE_NATIVE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
};
static const VMStateDescription vmstate_stm32f2xx_adc = {
@@ -278,7 +280,7 @@ static void stm32f2xx_adc_init(Object *obj)
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
memory_region_init_io(&s->mmio, obj, &stm32f2xx_adc_ops, s,
- TYPE_STM32F2XX_ADC, 0xFF);
+ TYPE_STM32F2XX_ADC, 0x100);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index f1bcc14f55..cca5b5ad04 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -125,6 +125,17 @@ static void bcm2835_peripherals_init(Object *obj)
OBJECT(&s->sdhci.sdbus));
object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost",
OBJECT(&s->sdhost.sdbus));
+
+ /* Mphi */
+ sysbus_init_child_obj(obj, "mphi", &s->mphi, sizeof(s->mphi),
+ TYPE_BCM2835_MPHI);
+
+ /* DWC2 */
+ sysbus_init_child_obj(obj, "dwc2", &s->dwc2, sizeof(s->dwc2),
+ TYPE_DWC2_USB);
+
+ object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr",
+ OBJECT(&s->gpu_bus_mr));
}
static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
@@ -360,6 +371,32 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus");
+ /* Mphi */
+ object_property_set_bool(OBJECT(&s->mphi), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ memory_region_add_subregion(&s->peri_mr, MPHI_OFFSET,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mphi), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->mphi), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
+ INTERRUPT_HOSTPORT));
+
+ /* DWC2 */
+ object_property_set_bool(OBJECT(&s->dwc2), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ memory_region_add_subregion(&s->peri_mr, USB_OTG_OFFSET,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dwc2), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->dwc2), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
+ INTERRUPT_USB));
+
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000);
create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000);
@@ -373,7 +410,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
create_unimp(s, &s->otp, "bcm2835-otp", OTP_OFFSET, 0x80);
create_unimp(s, &s->dbus, "bcm2835-dbus", DBUS_OFFSET, 0x8000);
create_unimp(s, &s->ave0, "bcm2835-ave0", AVE0_OFFSET, 0x8000);
- create_unimp(s, &s->dwc2, "dwc-usb2", USB_OTG_OFFSET, 0x1000);
create_unimp(s, &s->sdramc, "bcm2835-sdramc", SDRAMC_OFFSET, 0x100);
}
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 336c9bad4a..e649f8930c 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -26,6 +26,7 @@
#include "sysemu/blockdev.h"
#include "sysemu/qtest.h"
#include "qemu/cutils.h"
+#include "qemu/log.h"
static struct {
hwaddr io_base;
@@ -112,7 +113,9 @@ static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr,
return s->pm_regs[addr >> 2];
default:
fail:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -143,8 +146,9 @@ static void pxa2xx_pm_write(void *opaque, hwaddr addr,
s->pm_regs[addr >> 2] = value;
break;
}
-
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
}
@@ -185,7 +189,9 @@ static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr,
return s->cm_regs[CCCR >> 2] | (3 << 28);
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -210,7 +216,9 @@ static void pxa2xx_cm_write(void *opaque, hwaddr addr,
break;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
}
@@ -415,7 +423,9 @@ static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr,
return s->mm_regs[addr >> 2];
/* fall through */
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -434,7 +444,9 @@ static void pxa2xx_mm_write(void *opaque, hwaddr addr,
}
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
}
@@ -641,7 +653,9 @@ static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr,
case SSACD:
return s->ssacd;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -733,7 +747,9 @@ static void pxa2xx_ssp_write(void *opaque, hwaddr addr,
break;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
}
@@ -995,7 +1011,9 @@ static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr,
else
return s->last_swcr;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -1101,7 +1119,9 @@ static void pxa2xx_rtc_write(void *opaque, hwaddr addr,
break;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
}
}
@@ -1354,7 +1374,9 @@ static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr,
s->ibmr = 0;
return s->ibmr;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -1427,7 +1449,9 @@ static void pxa2xx_i2c_write(void *opaque, hwaddr addr,
break;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
}
}
@@ -1628,7 +1652,9 @@ static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr,
}
return 0;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -1685,7 +1711,9 @@ static void pxa2xx_i2s_write(void *opaque, hwaddr addr,
}
break;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
}
}
@@ -1870,7 +1898,9 @@ static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr,
case ICFOR:
return s->rx_len;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
break;
}
return 0;
@@ -1922,7 +1952,9 @@ static void pxa2xx_fir_write(void *opaque, hwaddr addr,
case ICFOR:
break;
default:
- printf("%s: Bad register " REG_FMT "\n", __func__, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
}
}
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
index 6f0e233d77..96cb30aa3c 100644
--- a/hw/arm/sabrelite.c
+++ b/hw/arm/sabrelite.c
@@ -41,7 +41,6 @@ static void sabrelite_reset_secondary(ARMCPU *cpu,
static void sabrelite_init(MachineState *machine)
{
FslIMX6State *s;
- Error *err = NULL;
/* Check the amount of memory is compatible with the SOC */
if (machine->ram_size > FSL_IMX6_MMDC_SIZE) {
@@ -52,11 +51,7 @@ static void sabrelite_init(MachineState *machine)
s = FSL_IMX6(object_new(TYPE_FSL_IMX6));
object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
- object_property_set_bool(OBJECT(s), true, "realized", &err);
- if (err != NULL) {
- error_report("%s", error_get_pretty(err));
- exit(1);
- }
+ object_property_set_bool(OBJECT(s), true, "realized", &error_fatal);
memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR,
machine->ram);
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
index 47960b5f0d..8855c22656 100644
--- a/hw/block/Makefile.objs
+++ b/hw/block/Makefile.objs
@@ -13,6 +13,6 @@ common-obj-$(CONFIG_SH4) += tc58128.o
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
-obj-$(CONFIG_NVME_PCI) += nvme.o
+common-obj-$(CONFIG_NVME_PCI) += nvme.o
obj-y += dataplane/
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 2f3100e56c..a21eeca2fb 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -46,8 +46,7 @@
#include "qapi/visitor.h"
#include "sysemu/hostmem.h"
#include "sysemu/block-backend.h"
-#include "exec/ram_addr.h"
-
+#include "exec/memory.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/cutils.h"
@@ -1207,8 +1206,7 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
*/
if (addr == 0xE08 &&
(NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
- qemu_ram_writeback(n->pmrdev->mr.ram_block,
- 0, n->pmrdev->size);
+ memory_region_msync(&n->pmrdev->mr, 0, n->pmrdev->size);
}
memcpy(&val, ptr + addr, size);
} else {
diff --git a/hw/display/ati.c b/hw/display/ati.c
index 065f197678..67604e68de 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -285,8 +285,11 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
if (idx <= s->vga.vram_size - size) {
val = ldn_le_p(s->vga.vram_ptr + idx, size);
}
- } else {
+ } else if (s->regs.mm_index > MM_DATA + 3) {
val = ati_mm_read(s, s->regs.mm_index + addr - MM_DATA, size);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ati_mm_read: mm_index too small: %u\n", s->regs.mm_index);
}
break;
case BIOS_0_SCRATCH ... BUS_CNTL - 1:
@@ -520,8 +523,11 @@ static void ati_mm_write(void *opaque, hwaddr addr,
if (idx <= s->vga.vram_size - size) {
stn_le_p(s->vga.vram_ptr + idx, size, data);
}
- } else {
+ } else if (s->regs.mm_index > MM_DATA + 3) {
ati_mm_write(s, s->regs.mm_index + addr - MM_DATA, data, size);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ati_mm_write: mm_index too small: %u\n", s->regs.mm_index);
}
break;
case BIOS_0_SCRATCH ... BUS_CNTL - 1:
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index f7f1c199ce..7cbe6e56ff 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -35,6 +35,7 @@
#include "hw/qdev-properties.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "trace.h"
/* Change to 1 to enable debugging */
#define DEBUG_CG3 0
@@ -63,12 +64,6 @@
#define CG3_VRAM_SIZE 0x100000
#define CG3_VRAM_OFFSET 0x800000
-#define DPRINTF(fmt, ...) do { \
- if (DEBUG_CG3) { \
- printf("CG3: " fmt , ## __VA_ARGS__); \
- } \
-} while (0)
-
#define TYPE_CG3 "cgthree"
#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3)
@@ -195,7 +190,8 @@ static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
val = 0;
break;
}
- DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr);
+ trace_cg3_read(addr, val, size);
+
return val;
}
@@ -206,9 +202,7 @@ static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
uint8_t regval;
int i;
- DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n",
- val, addr, size);
-
+ trace_cg3_write(addr, val, size);
switch (addr) {
case CG3_REG_BT458_ADDR:
s->dac_index = val;
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 1f29731ffe..212d6f5e61 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -35,6 +35,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/units.h"
+#include "qemu/log.h"
#include "sysemu/reset.h"
#include "qapi/error.h"
#include "trace.h"
@@ -52,7 +53,6 @@
*/
//#define DEBUG_CIRRUS
-//#define DEBUG_BITBLT
/***************************************
*
@@ -905,9 +905,8 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
{
/* XXX */
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
-#endif
+ qemu_log_mask(LOG_UNIMP,
+ "cirrus: bitblt (video to cpu) is not implemented\n");
return 0;
}
@@ -950,19 +949,16 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
s->cirrus_blt_dstaddr &= s->cirrus_addr_mask;
s->cirrus_blt_srcaddr &= s->cirrus_addr_mask;
-#ifdef DEBUG_BITBLT
- printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
- blt_rop,
- s->cirrus_blt_mode,
- s->cirrus_blt_modeext,
- s->cirrus_blt_width,
- s->cirrus_blt_height,
- s->cirrus_blt_dstpitch,
- s->cirrus_blt_srcpitch,
- s->cirrus_blt_dstaddr,
- s->cirrus_blt_srcaddr,
- s->vga.gr[0x2f]);
-#endif
+ trace_vga_cirrus_bitblt_start(blt_rop,
+ s->cirrus_blt_mode,
+ s->cirrus_blt_modeext,
+ s->cirrus_blt_width,
+ s->cirrus_blt_height,
+ s->cirrus_blt_dstpitch,
+ s->cirrus_blt_srcpitch,
+ s->cirrus_blt_dstaddr,
+ s->cirrus_blt_srcaddr,
+ s->vga.gr[0x2f]);
switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
case CIRRUS_BLTMODE_PIXELWIDTH8:
@@ -978,9 +974,8 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
s->cirrus_blt_pixelwidth = 4;
break;
default:
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt - pixel width is unknown\n");
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: bitblt - pixel width is unknown\n");
goto bitblt_ignore;
}
s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
@@ -989,9 +984,8 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
CIRRUS_BLTMODE_MEMSYSDEST))
== (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt - memory-to-memory copy is requested\n");
-#endif
+ qemu_log_mask(LOG_UNIMP,
+ "cirrus: bitblt - memory-to-memory copy requested\n");
goto bitblt_ignore;
}
@@ -1038,7 +1032,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
} else {
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
if (s->cirrus_blt_pixelwidth > 2) {
- printf("src transparent without colorexpand must be 8bpp or 16bpp\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: src transparent without colorexpand "
+ "must be 8bpp or 16bpp\n");
goto bitblt_ignore;
}
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
@@ -1136,10 +1132,9 @@ static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
ret = 16;
break; /* XGA HiColor */
default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: invalid DAC value %x in 16bpp\n",
- (s->cirrus_hidden_dac_data & 0xf));
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: invalid DAC value 0x%x in 16bpp\n",
+ (s->cirrus_hidden_dac_data & 0xf));
ret = 15; /* XXX */
break;
}
@@ -1308,11 +1303,9 @@ static int cirrus_vga_read_sr(CirrusVGAState * s)
#endif
return s->vga.sr[s->vga.sr_index];
default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport sr_index %02x\n", s->vga.sr_index);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: inport sr_index 0x%02x\n", s->vga.sr_index);
return 0xff;
- break;
}
}
@@ -1401,10 +1394,9 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
cirrus_update_memory_access(s);
break;
default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport sr_index %02x, sr_value %02x\n",
- s->vga.sr_index, val);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: outport sr_index 0x%02x, sr_value 0x%02x\n",
+ s->vga.sr_index, val);
break;
}
}
@@ -1502,9 +1494,8 @@ static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index)
if (reg_index < 0x3a) {
return s->vga.gr[reg_index];
} else {
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport gr_index %02x\n", reg_index);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: inport gr_index 0x%02x\n", reg_index);
return 0xff;
}
}
@@ -1512,9 +1503,7 @@ static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index)
static void
cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
{
-#if defined(DEBUG_BITBLT) && 0
- printf("gr%02x: %02x\n", reg_index, reg_value);
-#endif
+ trace_vga_cirrus_write_gr(reg_index, reg_value);
switch (reg_index) {
case 0x00: // Standard VGA, BGCOLOR 0x000000ff
s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
@@ -1593,10 +1582,9 @@ cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
cirrus_write_bitblt(s, reg_value);
break;
default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
- reg_value);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: outport gr_index 0x%02x, gr_value 0x%02x\n",
+ reg_index, reg_value);
break;
}
}
@@ -1651,9 +1639,8 @@ static int cirrus_vga_read_cr(CirrusVGAState * s, unsigned reg_index)
return s->vga.ar_index & 0x3f;
break;
default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport cr_index %02x\n", reg_index);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: inport cr_index 0x%02x\n", reg_index);
return 0xff;
}
}
@@ -1724,10 +1711,9 @@ static void cirrus_vga_write_cr(CirrusVGAState * s, int reg_value)
break;
case 0x25: // Part Status
default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport cr_index %02x, cr_value %02x\n",
- s->vga.cr_index, reg_value);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: outport cr_index 0x%02x, cr_value 0x%02x\n",
+ s->vga.cr_index, reg_value);
break;
}
}
@@ -1837,9 +1823,8 @@ static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
value = cirrus_vga_read_gr(s, 0x31);
break;
default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mmio read - address 0x%04x\n", address);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: mmio read - address 0x%04x\n", address);
break;
}
@@ -1949,10 +1934,9 @@ static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
cirrus_vga_write_gr(s, 0x31, value);
break;
default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
- address, value);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
+ address, value);
break;
}
}
@@ -2050,9 +2034,8 @@ static uint64_t cirrus_vga_mem_read(void *opaque,
}
} else {
val = 0xff;
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mem_readb " TARGET_FMT_plx "\n", addr);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: mem_readb 0x" TARGET_FMT_plx "\n", addr);
}
return val;
}
@@ -2115,10 +2098,9 @@ static void cirrus_vga_mem_write(void *opaque,
cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
}
} else {
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mem_writeb " TARGET_FMT_plx " value 0x%02" PRIu64 "\n", addr,
- mem_value);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "cirrus: mem_writeb 0x" TARGET_FMT_plx " "
+ "value 0x%02" PRIu64 "\n", addr, mem_value);
}
}
@@ -2414,6 +2396,9 @@ static uint64_t cirrus_linear_bitblt_read(void *opaque,
/* XXX handle bitblt */
(void)s;
+ qemu_log_mask(LOG_UNIMP,
+ "cirrus: linear bitblt is not implemented\n");
+
return 0xff;
}
diff --git a/hw/display/dpcd.c b/hw/display/dpcd.c
index 170545c605..64463654a1 100644
--- a/hw/display/dpcd.c
+++ b/hw/display/dpcd.c
@@ -1,5 +1,5 @@
/*
- * dpcd.c
+ * Xilinx Display Port Control Data
*
* Copyright (C) 2015 : GreenSocs Ltd
* http://www.greensocs.com/ , email: info@greensocs.com
@@ -32,16 +32,7 @@
#include "hw/misc/auxbus.h"
#include "migration/vmstate.h"
#include "hw/display/dpcd.h"
-
-#ifndef DEBUG_DPCD
-#define DEBUG_DPCD 0
-#endif
-
-#define DPRINTF(fmt, ...) do { \
- if (DEBUG_DPCD) { \
- qemu_log("dpcd: " fmt, ## __VA_ARGS__); \
- } \
-} while (0)
+#include "trace.h"
#define DPCD_READABLE_AREA 0x600
@@ -70,8 +61,8 @@ static uint64_t dpcd_read(void *opaque, hwaddr offset, unsigned size)
offset);
ret = 0;
}
+ trace_dpcd_read(offset, ret);
- DPRINTF("read 0x%" PRIX8 " @0x%" HWADDR_PRIX "\n", ret, offset);
return ret;
}
@@ -80,8 +71,7 @@ static void dpcd_write(void *opaque, hwaddr offset, uint64_t value,
{
DPCDState *e = DPCD(opaque);
- DPRINTF("write 0x%" PRIX8 " @0x%" HWADDR_PRIX "\n", (uint8_t)value, offset);
-
+ trace_dpcd_write(offset, value);
if (offset < DPCD_READABLE_AREA) {
e->dpcd_info[offset] = value;
} else {
@@ -137,7 +127,7 @@ static void dpcd_init(Object *obj)
{
DPCDState *s = DPCD(obj);
- memory_region_init_io(&s->iomem, obj, &aux_ops, s, TYPE_DPCD, 0x7FFFF);
+ memory_region_init_io(&s->iomem, obj, &aux_ops, s, TYPE_DPCD, 0x80000);
aux_init_mmio(AUX_SLAVE(obj), &s->iomem);
}
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 1c0266ce9f..4b7286b7c9 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -31,6 +31,7 @@
#include "ui/pixel_ops.h"
#include "qemu/bswap.h"
#include "qemu/module.h"
+#include "qemu/log.h"
/* Debug messages configuration */
#define EXYNOS4210_FIMD_DEBUG 0
@@ -39,20 +40,15 @@
#if EXYNOS4210_FIMD_DEBUG == 0
#define DPRINT_L1(fmt, args...) do { } while (0)
#define DPRINT_L2(fmt, args...) do { } while (0)
- #define DPRINT_ERROR(fmt, args...) do { } while (0)
#elif EXYNOS4210_FIMD_DEBUG == 1
#define DPRINT_L1(fmt, args...) \
do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
#define DPRINT_L2(fmt, args...) do { } while (0)
- #define DPRINT_ERROR(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
#else
#define DPRINT_L1(fmt, args...) \
do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
#define DPRINT_L2(fmt, args...) \
do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
- #define DPRINT_ERROR(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
#endif
#if EXYNOS4210_FIMD_MODE_TRACE == 0
@@ -1108,7 +1104,7 @@ static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
case FIMD_WINCON_BUF2_STAT:
return 2;
default:
- DPRINT_ERROR("Non-existent buffer index\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "FIMD: Non-existent buffer index\n");
return 0;
}
}
@@ -1160,20 +1156,24 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
if (int128_get64(w->mem_section.size) != w->fb_len ||
!memory_region_is_ram(w->mem_section.mr)) {
- DPRINT_ERROR("Failed to find window %u framebuffer region\n", win);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: Failed to find window %u framebuffer region\n",
+ win);
goto error_return;
}
w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len,
false);
if (!w->host_fb_addr) {
- DPRINT_ERROR("Failed to map window %u framebuffer\n", win);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: Failed to map window %u framebuffer\n", win);
goto error_return;
}
if (fb_mapped_len != w->fb_len) {
- DPRINT_ERROR("Window %u mapped framebuffer length is less then "
- "expected\n", win);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: Window %u mapped framebuffer length is less than "
+ "expected\n", win);
cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
goto error_return;
}
@@ -1490,7 +1490,9 @@ static void exynos4210_fimd_write(void *opaque, hwaddr offset,
break;
case 3:
if (w != 1 && w != 2) {
- DPRINT_ERROR("Bad write offset 0x%08x\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: Bad write offset 0x%08"HWADDR_PRIx"\n",
+ offset);
return;
}
s->window[w].osdsize = val;
@@ -1624,7 +1626,9 @@ static void exynos4210_fimd_write(void *opaque, hwaddr offset,
break;
case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n",
+ offset);
break;
}
w = (offset - FIMD_VIDW0ADD0_B2) >> 3;
@@ -1638,14 +1642,18 @@ static void exynos4210_fimd_write(void *opaque, hwaddr offset,
break;
case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n",
+ offset);
break;
}
s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val;
break;
case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n",
+ offset);
break;
}
s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val;
@@ -1665,7 +1673,8 @@ static void exynos4210_fimd_write(void *opaque, hwaddr offset,
s->window[w].palette[i] = val;
break;
default:
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n", offset);
break;
}
}
@@ -1715,7 +1724,9 @@ static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset,
break;
case 3:
if (w != 1 && w != 2) {
- DPRINT_ERROR("bad read offset 0x%08x\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: bad read offset 0x%08"HWADDR_PRIx"\n",
+ offset);
return 0xBAADBAAD;
}
ret = s->window[w].osdsize;
@@ -1809,7 +1820,8 @@ static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset,
return s->window[w].palette[i];
}
- DPRINT_ERROR("bad read offset 0x%08x\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FIMD: bad read offset 0x%08"HWADDR_PRIx"\n", offset);
return 0xBAADBAAD;
}
diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c
index 32dc0d6aa7..21fde58a26 100644
--- a/hw/display/omap_dss.c
+++ b/hw/display/omap_dss.c
@@ -619,7 +619,7 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s)
if (s->rfbi.control & (1 << 1)) { /* BYPASS */
/* TODO: in non-Bypass mode we probably need to just assert the
* DRQ and wait for DMA to write the pixels. */
- fprintf(stderr, "%s: Bypass mode unimplemented\n", __func__);
+ qemu_log_mask(LOG_UNIMP, "%s: Bypass mode unimplemented\n", __func__);
return;
}
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
index d5f2e82a4e..ff90104b80 100644
--- a/hw/display/pxa2xx_lcd.c
+++ b/hw/display/pxa2xx_lcd.c
@@ -426,9 +426,10 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
s->status[0] |= LCSR0_QD;
- if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
- printf("%s: internal frame buffer unsupported\n", __func__);
-
+ if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: internal frame buffer unsupported\n", __func__);
+ }
if ((s->control[3] & LCCR3_API) &&
(value & LCCR0_ENB) && !(value & LCCR0_LCDT))
s->status[0] |= LCSR0_ABC;
@@ -462,9 +463,9 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
break;
case OVL1C1:
- if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
- printf("%s: Overlay 1 not supported\n", __func__);
-
+ if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) {
+ qemu_log_mask(LOG_UNIMP, "%s: Overlay 1 not supported\n", __func__);
+ }
s->ovl1c[0] = value & 0x80ffffff;
s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
break;
@@ -474,9 +475,9 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
break;
case OVL2C1:
- if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
- printf("%s: Overlay 2 not supported\n", __func__);
-
+ if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) {
+ qemu_log_mask(LOG_UNIMP, "%s: Overlay 2 not supported\n", __func__);
+ }
s->ovl2c[0] = value & 0x80ffffff;
s->dma_ch[2].up = !!(value & OVLC1_EN);
s->dma_ch[3].up = !!(value & OVLC1_EN);
@@ -488,9 +489,10 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
break;
case CCR:
- if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
- printf("%s: Hardware cursor unimplemented\n", __func__);
-
+ if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Hardware cursor unimplemented\n", __func__);
+ }
s->ccr = value & 0x81ffffe7;
s->dma_ch[5].up = !!(value & CCR_CEN);
break;
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index acc692531a..edd8d24a76 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -2,7 +2,7 @@
* QEMU SM501 Device
*
* Copyright (c) 2008 Shin-ichiro KAWASAKI
- * Copyright (c) 2016 BALATON Zoltan
+ * Copyright (c) 2016-2020 BALATON Zoltan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -40,23 +40,6 @@
#include "ui/pixel_ops.h"
#include "qemu/bswap.h"
-/*
- * Status: 2010/05/07
- * - Minimum implementation for Linux console : mmio regs and CRT layer.
- * - 2D graphics acceleration partially supported : only fill rectangle.
- *
- * Status: 2016/12/04
- * - Misc fixes: endianness, hardware cursor
- * - Panel support
- *
- * TODO:
- * - Touch panel support
- * - USB support
- * - UART support
- * - More 2D graphics engine support
- * - Performance tuning
- */
-
/*#define DEBUG_SM501*/
/*#define DEBUG_BITBLT*/
@@ -699,139 +682,176 @@ static inline void hwc_invalidate(SM501State *s, int crt)
static void sm501_2d_operation(SM501State *s)
{
- /* obtain operation parameters */
- int operation = (s->twoD_control >> 16) & 0x1f;
- int rtl = s->twoD_control & 0x8000000;
- int src_x = (s->twoD_source >> 16) & 0x01FFF;
- int src_y = s->twoD_source & 0xFFFF;
- int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
- int dst_y = s->twoD_destination & 0xFFFF;
- int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
- int operation_height = s->twoD_dimension & 0xFFFF;
- uint32_t color = s->twoD_foreground;
- int format_flags = (s->twoD_stretch >> 20) & 0x3;
- int addressing = (s->twoD_stretch >> 16) & 0xF;
+ int cmd = (s->twoD_control >> 16) & 0x1F;
+ int rtl = s->twoD_control & BIT(27);
+ int format = (s->twoD_stretch >> 20) & 0x3;
int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */
/* 1 if rop2 source is the pattern, otherwise the source is the bitmap */
int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1;
int rop = s->twoD_control & 0xFF;
- uint32_t src_base = s->twoD_source_base & 0x03FFFFFF;
+ unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
+ unsigned int dst_y = s->twoD_destination & 0xFFFF;
+ unsigned int width = (s->twoD_dimension >> 16) & 0x1FFF;
+ unsigned int height = s->twoD_dimension & 0xFFFF;
uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF;
-
- /* get frame buffer info */
- uint8_t *src = s->local_mem + src_base;
- uint8_t *dst = s->local_mem + dst_base;
- int src_width = s->twoD_pitch & 0x1FFF;
- int dst_width = (s->twoD_pitch >> 16) & 0x1FFF;
+ unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF;
int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0;
int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt);
- if (addressing != 0x0) {
- printf("%s: only XY addressing is supported.\n", __func__);
- abort();
+ if ((s->twoD_stretch >> 16) & 0xF) {
+ qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n");
+ return;
}
- if (rop_mode == 0) {
- if (rop != 0xcc) {
- /* Anything other than plain copies are not supported */
- qemu_log_mask(LOG_UNIMP, "sm501: rop3 mode with rop %x is not "
- "supported.\n", rop);
- }
- } else {
- if (rop2_source_is_pattern && rop != 0x5) {
- /* For pattern source, we support only inverse dest */
- qemu_log_mask(LOG_UNIMP, "sm501: rop2 source being the pattern and "
- "rop %x is not supported.\n", rop);
- } else {
- if (rop != 0x5 && rop != 0xc) {
- /* Anything other than plain copies or inverse dest is not
- * supported */
- qemu_log_mask(LOG_UNIMP, "sm501: rop mode %x is not "
- "supported.\n", rop);
- }
- }
+ if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) {
+ qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n");
+ return;
}
- if ((s->twoD_source_base & 0x08000000) ||
- (s->twoD_destination_base & 0x08000000)) {
- printf("%s: only local memory is supported.\n", __func__);
- abort();
+ if (!dst_pitch) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero dest pitch.\n");
+ return;
+ }
+
+ if (!width || !height) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero size 2D op.\n");
+ return;
}
- switch (operation) {
- case 0x00: /* copy area */
-#define COPY_AREA(_bpp, _pixel_type, rtl) { \
- int y, x, index_d, index_s; \
- for (y = 0; y < operation_height; y++) { \
- for (x = 0; x < operation_width; x++) { \
- _pixel_type val; \
- \
- if (rtl) { \
- index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
- index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
- } else { \
- index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
- index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
- } \
- if (rop_mode == 1 && rop == 5) { \
- /* Invert dest */ \
- val = ~*(_pixel_type *)&dst[index_d]; \
- } else { \
- val = *(_pixel_type *)&src[index_s]; \
- } \
- *(_pixel_type *)&dst[index_d] = val; \
- } \
- } \
+ if (rtl) {
+ dst_x -= width - 1;
+ dst_y -= height - 1;
}
- switch (format_flags) {
- case 0:
- COPY_AREA(1, uint8_t, rtl);
- break;
- case 1:
- COPY_AREA(2, uint16_t, rtl);
- break;
- case 2:
- COPY_AREA(4, uint32_t, rtl);
- break;
+
+ if (dst_base >= get_local_mem_size(s) || dst_base +
+ (dst_x + width + (dst_y + height) * (dst_pitch + width)) *
+ (1 << format) >= get_local_mem_size(s)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n");
+ return;
+ }
+
+ switch (cmd) {
+ case 0: /* BitBlt */
+ {
+ static uint32_t tmp_buf[16384];
+ unsigned int src_x = (s->twoD_source >> 16) & 0x01FFF;
+ unsigned int src_y = s->twoD_source & 0xFFFF;
+ uint32_t src_base = s->twoD_source_base & 0x03FFFFFF;
+ unsigned int src_pitch = s->twoD_pitch & 0x1FFF;
+
+ if (!src_pitch) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero src pitch.\n");
+ return;
+ }
+
+ if (rtl) {
+ src_x -= width - 1;
+ src_y -= height - 1;
}
- break;
- case 0x01: /* fill rectangle */
-#define FILL_RECT(_bpp, _pixel_type) { \
- int y, x; \
- for (y = 0; y < operation_height; y++) { \
- for (x = 0; x < operation_width; x++) { \
- int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
- *(_pixel_type *)&dst[index] = (_pixel_type)color; \
- } \
- } \
+ if (src_base >= get_local_mem_size(s) || src_base +
+ (src_x + width + (src_y + height) * (src_pitch + width)) *
+ (1 << format) >= get_local_mem_size(s)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "sm501: 2D op src is outside vram.\n");
+ return;
+ }
+
+ if ((rop_mode && rop == 0x5) || (!rop_mode && rop == 0x55)) {
+ /* Invert dest, is there a way to do this with pixman? */
+ unsigned int x, y, i;
+ uint8_t *d = s->local_mem + dst_base;
+
+ for (y = 0; y < height; y++) {
+ i = (dst_x + (dst_y + y) * dst_pitch) * (1 << format);
+ for (x = 0; x < width; x++, i += (1 << format)) {
+ switch (format) {
+ case 0:
+ d[i] = ~d[i];
+ break;
+ case 1:
+ *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i];
+ break;
+ case 2:
+ *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i];
+ break;
+ }
+ }
+ }
+ } else {
+ /* Do copy src for unimplemented ops, better than unpainted area */
+ if ((rop_mode && (rop != 0xc || rop2_source_is_pattern)) ||
+ (!rop_mode && rop != 0xcc)) {
+ qemu_log_mask(LOG_UNIMP,
+ "sm501: rop%d op %x%s not implemented\n",
+ (rop_mode ? 2 : 3), rop,
+ (rop2_source_is_pattern ?
+ " with pattern source" : ""));
+ }
+ /* Check for overlaps, this could be made more exact */
+ uint32_t sb, se, db, de;
+ sb = src_base + src_x + src_y * (width + src_pitch);
+ se = sb + width + height * (width + src_pitch);
+ db = dst_base + dst_x + dst_y * (width + dst_pitch);
+ de = db + width + height * (width + dst_pitch);
+ if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) {
+ /* regions may overlap: copy via temporary */
+ int free_buf = 0, llb = width * (1 << format);
+ int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
+ uint32_t *tmp = tmp_buf;
+
+ if (tmp_stride * sizeof(uint32_t) * height > sizeof(tmp_buf)) {
+ tmp = g_malloc(tmp_stride * sizeof(uint32_t) * height);
+ free_buf = 1;
+ }
+ pixman_blt((uint32_t *)&s->local_mem[src_base], tmp,
+ src_pitch * (1 << format) / sizeof(uint32_t),
+ tmp_stride, 8 * (1 << format), 8 * (1 << format),
+ src_x, src_y, 0, 0, width, height);
+ pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base],
+ tmp_stride,
+ dst_pitch * (1 << format) / sizeof(uint32_t),
+ 8 * (1 << format), 8 * (1 << format),
+ 0, 0, dst_x, dst_y, width, height);
+ if (free_buf) {
+ g_free(tmp);
+ }
+ } else {
+ pixman_blt((uint32_t *)&s->local_mem[src_base],
+ (uint32_t *)&s->local_mem[dst_base],
+ src_pitch * (1 << format) / sizeof(uint32_t),
+ dst_pitch * (1 << format) / sizeof(uint32_t),
+ 8 * (1 << format), 8 * (1 << format),
+ src_x, src_y, dst_x, dst_y, width, height);
+ }
+ }
+ break;
}
+ case 1: /* Rectangle Fill */
+ {
+ uint32_t color = s->twoD_foreground;
- switch (format_flags) {
- case 0:
- FILL_RECT(1, uint8_t);
- break;
- case 1:
- color = cpu_to_le16(color);
- FILL_RECT(2, uint16_t);
- break;
- case 2:
+ if (format == 2) {
color = cpu_to_le32(color);
- FILL_RECT(4, uint32_t);
- break;
+ } else if (format == 1) {
+ color = cpu_to_le16(color);
}
- break;
- default:
- printf("non-implemented SM501 2D operation. %d\n", operation);
- abort();
+ pixman_fill((uint32_t *)&s->local_mem[dst_base],
+ dst_pitch * (1 << format) / sizeof(uint32_t),
+ 8 * (1 << format), dst_x, dst_y, width, height, color);
break;
}
+ default:
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n",
+ cmd);
+ return;
+ }
if (dst_base >= get_fb_addr(s, crt) &&
dst_base <= get_fb_addr(s, crt) + fb_len) {
- int dst_len = MIN(fb_len, ((dst_y + operation_height - 1) * dst_width +
- dst_x + operation_width) * (1 << format_flags));
+ int dst_len = MIN(fb_len, ((dst_y + height - 1) * dst_pitch +
+ dst_x + width) * (1 << format));
if (dst_len) {
memory_region_set_dirty(&s->local_mem_region, dst_base, dst_len);
}
@@ -892,9 +912,8 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
break;
default:
- printf("sm501 system config : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config"
+ "register read. addr=%" HWADDR_PRIx "\n", addr);
}
return ret;
@@ -948,15 +967,15 @@ static void sm501_system_config_write(void *opaque, hwaddr addr,
break;
case SM501_ENDIAN_CONTROL:
if (value & 0x00000001) {
- printf("sm501 system config : big endian mode not implemented.\n");
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: system config big endian mode not"
+ " implemented.\n");
}
break;
default:
- printf("sm501 system config : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config"
+ "register write. addr=%" HWADDR_PRIx
+ ", val=%" PRIx64 "\n", addr, value);
}
}
@@ -1207,9 +1226,8 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
break;
default:
- printf("sm501 disp ctrl : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register "
+ "read. addr=%" HWADDR_PRIx "\n", addr);
}
return ret;
@@ -1345,9 +1363,9 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
break;
default:
- printf("sm501 disp ctrl : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (unsigned)value);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register "
+ "write. addr=%" HWADDR_PRIx
+ ", val=%" PRIx64 "\n", addr, value);
}
}
@@ -1433,9 +1451,8 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
ret = 0; /* Should return interrupt status */
break;
default:
- printf("sm501 disp ctrl : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register "
+ "read. addr=%" HWADDR_PRIx "\n", addr);
}
return ret;
@@ -1520,9 +1537,9 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr,
/* ignored, writing 0 should clear interrupt status */
break;
default:
- printf("sm501 2d engine : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (unsigned)value);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2d engine register "
+ "write. addr=%" HWADDR_PRIx
+ ", val=%" PRIx64 "\n", addr, value);
}
}
@@ -1670,9 +1687,9 @@ static void sm501_update_display(void *opaque)
draw_line = draw_line32_funcs[dst_depth_index];
break;
default:
- printf("sm501 update display : invalid control register value.\n");
- abort();
- break;
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display"
+ "invalid control register value.\n");
+ return;
}
/* set up to draw hardware cursor */
diff --git a/hw/display/trace-events b/hw/display/trace-events
index e6e22bef88..72d4c9812c 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -133,6 +133,8 @@ vga_vbe_write(uint32_t index, uint32_t val) "index 0x%x, val 0x%x"
vga_cirrus_read_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
vga_cirrus_write_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
vga_cirrus_write_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x"
+vga_cirrus_write_gr(uint8_t index, uint8_t val) "GR addr 0x%02x, val 0x%02x"
+vga_cirrus_bitblt_start(uint8_t blt_rop, uint8_t blt_mode, uint8_t blt_modeext, int blt_width, int blt_height, int blt_dstpitch, int blt_srcpitch, uint32_t blt_dstaddr, uint32_t blt_srcaddr, uint8_t gr_val) "rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08"PRIx32" saddr=0x%08"PRIx32" writemask=0x%02x"
# sii9022.c
sii9022_read_reg(uint8_t addr, uint8_t val) "addr 0x%02x, val 0x%02x"
@@ -151,3 +153,11 @@ artist_vram_write(unsigned int size, uint64_t addr, uint64_t val) "%u 0x%"PRIx64
artist_fill_window(unsigned int start_x, unsigned int start_y, unsigned int width, unsigned int height, uint32_t op, uint32_t ctlpln) "start=%ux%u length=%ux%u op=0x%08x ctlpln=0x%08x"
artist_block_move(unsigned int start_x, unsigned int start_y, unsigned int dest_x, unsigned int dest_y, unsigned int width, unsigned int height) "source %ux%u -> dest %ux%u size %ux%u"
artist_draw_line(unsigned int start_x, unsigned int start_y, unsigned int end_x, unsigned int end_y) "%ux%u %ux%u"
+
+# cg3.c
+cg3_read(uint32_t addr, uint32_t val, unsigned size) "read addr:0x%06"PRIx32" val:0x%08"PRIx32" size:%u"
+cg3_write(uint32_t addr, uint32_t val, unsigned size) "write addr:0x%06"PRIx32" val:0x%08"PRIx32" size:%u"
+
+# dpcd.c
+dpcd_read(uint32_t addr, uint8_t val) "read addr:0x%"PRIx32" val:0x%02x"
+dpcd_write(uint32_t addr, uint8_t val) "write addr:0x%"PRIx32" val:0x%02x"
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 58ea82e3e5..2579f6b218 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -26,6 +26,7 @@
#include "qemu/module.h"
#include "qemu/units.h"
#include "qapi/error.h"
+#include "qemu/log.h"
#include "hw/loader.h"
#include "trace.h"
#include "ui/vnc.h"
@@ -953,7 +954,8 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
ret = s->scratch[s->index - SVGA_SCRATCH_BASE];
break;
}
- printf("%s: Bad register %02x\n", __func__, s->index);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad register %02x\n", __func__, s->index);
ret = 0;
break;
}
@@ -1002,7 +1004,8 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
s->new_width = value;
s->invalidated = 1;
} else {
- printf("%s: Bad width: %i\n", __func__, value);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad width: %i\n", __func__, value);
}
break;
@@ -1011,13 +1014,15 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
s->new_height = value;
s->invalidated = 1;
} else {
- printf("%s: Bad height: %i\n", __func__, value);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad height: %i\n", __func__, value);
}
break;
case SVGA_REG_BITS_PER_PIXEL:
if (value != 32) {
- printf("%s: Bad bits per pixel: %i bits\n", __func__, value);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad bits per pixel: %i bits\n", __func__, value);
s->config = 0;
s->invalidated = 1;
}
@@ -1082,7 +1087,8 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
s->scratch[s->index - SVGA_SCRATCH_BASE] = value;
break;
}
- printf("%s: Bad register %02x\n", __func__, s->index);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad register %02x\n", __func__, s->index);
}
}
@@ -1300,7 +1306,7 @@ static void pci_vmsvga_realize(PCIDevice *dev, Error **errp)
dev->config[PCI_LATENCY_TIMER] = 0x40;
dev->config[PCI_INTERRUPT_LINE] = 0xff; /* End */
- memory_region_init_io(&s->io_bar, NULL, &vmsvga_io_ops, &s->chip,
+ memory_region_init_io(&s->io_bar, OBJECT(dev), &vmsvga_io_ops, &s->chip,
"vmsvga-io", 0x10);
memory_region_set_flush_coalesced(&s->io_bar);
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index 3e5fb44e06..8d940cd8d1 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -1,5 +1,5 @@
/*
- * xlnx_dp.c
+ * Xilinx Display Port
*
* Copyright (C) 2015 : GreenSocs Ltd
* http://www.greensocs.com/ , email: info@greensocs.com
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/display/xlnx_dp.h"
@@ -465,7 +466,7 @@ static uint8_t xlnx_dp_aux_pop_tx_fifo(XlnxDPState *s)
uint8_t ret;
if (fifo8_is_empty(&s->tx_fifo)) {
- DPRINTF("tx_fifo underflow..\n");
+ error_report("%s: TX_FIFO underflow", __func__);
abort();
}
ret = fifo8_pop(&s->tx_fifo);
@@ -525,6 +526,7 @@ static void xlnx_dp_aux_set_command(XlnxDPState *s, uint32_t value)
qemu_log_mask(LOG_UNIMP, "xlnx_dp: Write i2c status not implemented\n");
break;
default:
+ error_report("%s: invalid command: %u", __func__, cmd);
abort();
}
@@ -631,8 +633,8 @@ static void xlnx_dp_change_graphic_fmt(XlnxDPState *s)
s->g_plane.format = PIXMAN_b8g8r8;
break;
default:
- DPRINTF("error: unsupported graphic format %u.\n",
- s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK);
+ error_report("%s: unsupported graphic format %u", __func__,
+ s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK);
abort();
}
@@ -647,8 +649,8 @@ static void xlnx_dp_change_graphic_fmt(XlnxDPState *s)
s->v_plane.format = PIXMAN_x8b8g8r8;
break;
default:
- DPRINTF("error: unsupported video format %u.\n",
- s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK);
+ error_report("%s: unsupported video format %u", __func__,
+ s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK);
abort();
}
diff --git a/hw/input/pxa2xx_keypad.c b/hw/input/pxa2xx_keypad.c
index 31862a7d16..62aa6f6b15 100644
--- a/hw/input/pxa2xx_keypad.c
+++ b/hw/input/pxa2xx_keypad.c
@@ -12,7 +12,7 @@
*/
#include "qemu/osdep.h"
-#include "hw/hw.h"
+#include "qemu/log.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "hw/arm/pxa.h"
@@ -233,7 +233,9 @@ static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
return s->kpkdi;
break;
default:
- hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
+ __func__, offset);
}
return 0;
@@ -280,7 +282,9 @@ static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
break;
default:
- hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
+ __func__, offset);
}
}
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index d9b51fce8d..fac4e56b7d 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -503,7 +503,7 @@ static void via_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_via;
/*
* Reason: part of VIA VT82C686 southbridge, needs to be wired up,
- * e.g. by mips_fulong2e_init()
+ * e.g. by mips_fuloong2e_init()
*/
dc->user_creatable = false;
}
diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c
index b155dd8170..a2fef04f8e 100644
--- a/hw/m68k/mcf5206.c
+++ b/hw/m68k/mcf5206.c
@@ -8,6 +8,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
+#include "qemu/log.h"
#include "cpu.h"
#include "hw/hw.h"
#include "hw/irq.h"
@@ -225,7 +226,8 @@ static void m5206_mbar_update(m5206_mbar_state *s)
break;
default:
/* Unknown vector. */
- error_report("Unhandled vector for IRQ %d", irq);
+ qemu_log_mask(LOG_UNIMP, "%s: Unhandled vector for IRQ %d\n",
+ __func__, irq);
vector = 0xf;
break;
}
@@ -273,7 +275,7 @@ static void m5206_mbar_reset(m5206_mbar_state *s)
}
static uint64_t m5206_mbar_read(m5206_mbar_state *s,
- uint64_t offset, unsigned size)
+ uint16_t offset, unsigned size)
{
if (offset >= 0x100 && offset < 0x120) {
return m5206_timer_read(s->timer[0], offset - 0x100);
@@ -306,11 +308,12 @@ static uint64_t m5206_mbar_read(m5206_mbar_state *s,
case 0x170: return s->uivr[0];
case 0x1b0: return s->uivr[1];
}
- hw_error("Bad MBAR read offset 0x%x", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad MBAR offset 0x%"PRIx16"\n",
+ __func__, offset);
return 0;
}
-static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
+static void m5206_mbar_write(m5206_mbar_state *s, uint16_t offset,
uint64_t value, unsigned size)
{
if (offset >= 0x100 && offset < 0x120) {
@@ -360,7 +363,8 @@ static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
s->uivr[1] = value;
break;
default:
- hw_error("Bad MBAR write offset 0x%x", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad MBAR offset 0x%"PRIx16"\n",
+ __func__, offset);
break;
}
}
diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
index b84c152ce3..2ab9701ad6 100644
--- a/hw/m68k/mcf5208.c
+++ b/hw/m68k/mcf5208.c
@@ -9,10 +9,10 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/error-report.h"
+#include "qemu/log.h"
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
-#include "hw/hw.h"
#include "hw/irq.h"
#include "hw/m68k/mcf.h"
#include "hw/m68k/mcf_fec.h"
@@ -111,8 +111,9 @@ static void m5208_timer_write(void *opaque, hwaddr offset,
case 4:
break;
default:
- hw_error("m5208_timer_write: Bad offset 0x%x\n", (int)offset);
- break;
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
+ __func__, offset);
+ return;
}
m5208_timer_update(s);
}
@@ -136,7 +137,8 @@ static uint64_t m5208_timer_read(void *opaque, hwaddr addr,
case 4:
return ptimer_get_count(s->timer);
default:
- hw_error("m5208_timer_read: Bad offset 0x%x\n", (int)addr);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
+ __func__, addr);
return 0;
}
}
@@ -164,7 +166,8 @@ static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
return 0;
default:
- hw_error("m5208_sys_read: Bad offset 0x%x\n", (int)addr);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
+ __func__, addr);
return 0;
}
}
@@ -172,7 +175,8 @@ static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
static void m5208_sys_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
+ __func__, addr);
}
static const MemoryRegionOps m5208_sys_ops = {
diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c
index d9e03a06ab..bc20742d9a 100644
--- a/hw/m68k/mcf_intc.c
+++ b/hw/m68k/mcf_intc.c
@@ -8,6 +8,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
+#include "qemu/log.h"
#include "cpu.h"
#include "hw/hw.h"
#include "hw/irq.h"
@@ -80,7 +81,9 @@ static uint64_t mcf_intc_read(void *opaque, hwaddr addr,
case 0xe1: case 0xe2: case 0xe3: case 0xe4:
case 0xe5: case 0xe6: case 0xe7:
/* LnIACK */
- hw_error("mcf_intc_read: LnIACK not implemented\n");
+ qemu_log_mask(LOG_UNIMP, "%s: LnIACK not implemented (offset 0x%02x)\n",
+ __func__, offset);
+ /* fallthru */
default:
return 0;
}
@@ -127,8 +130,9 @@ static void mcf_intc_write(void *opaque, hwaddr addr,
}
break;
default:
- hw_error("mcf_intc_write: Bad write offset %d\n", offset);
- break;
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%02x\n",
+ __func__, offset);
+ return;
}
mcf_intc_update(s);
}
diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index c5adedcc69..76f66e0b19 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -97,7 +97,6 @@ static void nvdimm_set_uuid(Object *obj, Visitor *v, const char *name,
if (qemu_uuid_parse(value, &nvdimm->uuid) != 0) {
error_setg(errp, "Property '%s.%s' has invalid value",
object_get_typename(obj), name);
- goto out;
}
g_free(value);
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
index 2c2adbc42a..67d39c56a4 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -41,8 +41,9 @@ config JAZZ
select DS1225Y
select JAZZ_LED
-config FULONG
+config FULOONG
bool
+ select PCI_BONITO
config MIPS_CPS
bool
diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
index 525809af07..739e2b7b40 100644
--- a/hw/mips/Makefile.objs
+++ b/hw/mips/Makefile.objs
@@ -1,8 +1,8 @@
obj-y += addr.o mips_int.o
-obj-$(CONFIG_R4K) += mips_r4k.o
-obj-$(CONFIG_MALTA) += gt64xxx_pci.o mips_malta.o
-obj-$(CONFIG_MIPSSIM) += mips_mipssim.o
-obj-$(CONFIG_JAZZ) += mips_jazz.o
-obj-$(CONFIG_FULONG) += mips_fulong2e.o
+obj-$(CONFIG_R4K) += r4k.o
+obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
+obj-$(CONFIG_MIPSSIM) += mipssim.o
+obj-$(CONFIG_JAZZ) += jazz.o
+obj-$(CONFIG_FULOONG) += fuloong2e.o
obj-$(CONFIG_MIPS_CPS) += cps.o
obj-$(CONFIG_MIPS_BOSTON) += boston.o
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index 98ecd25e8e..a896056be1 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -426,7 +426,6 @@ static void boston_mach_init(MachineState *machine)
{
DeviceState *dev;
BostonState *s;
- Error *err = NULL;
MemoryRegion *flash, *ddr_low_alias, *lcd, *platreg;
MemoryRegion *sys_mem = get_system_memory();
XilinxPCIEHost *pcie2;
@@ -458,19 +457,17 @@ static void boston_mach_init(MachineState *machine)
sysbus_init_child_obj(OBJECT(machine), "cps", OBJECT(&s->cps),
sizeof(s->cps), TYPE_MIPS_CPS);
object_property_set_str(OBJECT(&s->cps), machine->cpu_type, "cpu-type",
- &err);
- object_property_set_int(OBJECT(&s->cps), machine->smp.cpus, "num-vp", &err);
- object_property_set_bool(OBJECT(&s->cps), true, "realized", &err);
-
- if (err != NULL) {
- error_report("%s", error_get_pretty(err));
- exit(1);
- }
+ &error_fatal);
+ object_property_set_int(OBJECT(&s->cps), machine->smp.cpus, "num-vp",
+ &error_fatal);
+ object_property_set_bool(OBJECT(&s->cps), true, "realized",
+ &error_fatal);
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1);
flash = g_new(MemoryRegion, 1);
- memory_region_init_rom(flash, NULL, "boston.flash", 128 * MiB, &err);
+ memory_region_init_rom(flash, NULL, "boston.flash", 128 * MiB,
+ &error_fatal);
memory_region_add_subregion_overlap(sys_mem, 0x18000000, flash, 0);
memory_region_add_subregion_overlap(sys_mem, 0x80000000, machine->ram, 0);
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/fuloong2e.c
index 05b9efa516..7a65166cf0 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/fuloong2e.c
@@ -1,5 +1,5 @@
/*
- * QEMU fulong 2e mini pc support
+ * QEMU fuloong 2e mini pc support
*
* Copyright (c) 2008 yajin (yajin@vm-kernel.org)
* Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn)
@@ -11,8 +11,8 @@
*/
/*
- * Fulong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz)
- * http://www.linux-mips.org/wiki/Fulong
+ * Fuloong 2e mini pc is based on ICT/ST Loongson 2e CPU (MIPS III like, 800MHz)
+ * https://www.linux-mips.org/wiki/Fuloong_2E
*
* Loongson 2e user manual:
* http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf
@@ -45,13 +45,13 @@
#include "sysemu/reset.h"
#include "qemu/error-report.h"
-#define DEBUG_FULONG2E_INIT
+#define DEBUG_FULOONG2E_INIT
#define ENVP_ADDR 0x80002000l
#define ENVP_NB_ENTRIES 16
#define ENVP_ENTRY_SIZE 256
-/* fulong 2e has a 512k flash: Winbond W39L040AP70Z */
+/* Fuloong 2e has a 512k flash: Winbond W39L040AP70Z */
#define BIOS_SIZE (512 * KiB)
#define MAX_IDE_BUS 2
@@ -68,12 +68,12 @@
* 2, use "Bonito2edev" to replace "dir_corresponding_to_your_target_hardware"
* in the "Compile Guide".
*/
-#define FULONG_BIOSNAME "pmon_fulong2e.bin"
+#define FULOONG_BIOSNAME "pmon_2e.bin"
-/* PCI SLOT in fulong 2e */
-#define FULONG2E_VIA_SLOT 5
-#define FULONG2E_ATI_SLOT 6
-#define FULONG2E_RTL8139_SLOT 7
+/* PCI SLOT in Fuloong 2e */
+#define FULOONG2E_VIA_SLOT 5
+#define FULOONG2E_ATI_SLOT 6
+#define FULOONG2E_RTL8139_SLOT 7
static struct _loaderparams {
int ram_size;
@@ -278,7 +278,7 @@ static void network_init(PCIBus *pci_bus)
const char *default_devaddr = NULL;
if (i == 0 && (!nd->model || strcmp(nd->model, "rtl8139") == 0)) {
- /* The fulong board has a RTL8139 card using PCI SLOT 7 */
+ /* The Fuloong board has a RTL8139 card using PCI SLOT 7 */
default_devaddr = "07";
}
@@ -286,7 +286,7 @@ static void network_init(PCIBus *pci_bus)
}
}
-static void mips_fulong2e_init(MachineState *machine)
+static void mips_fuloong2e_init(MachineState *machine)
{
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
@@ -315,12 +315,11 @@ static void mips_fulong2e_init(MachineState *machine)
error_report("Invalid RAM size, should be 256MB");
exit(EXIT_FAILURE);
}
+ memory_region_add_subregion(address_space_mem, 0, machine->ram);
- /* allocate RAM */
- memory_region_init_rom(bios, NULL, "fulong2e.bios", BIOS_SIZE,
+ /* Boot ROM */
+ memory_region_init_rom(bios, NULL, "fuloong2e.bios", BIOS_SIZE,
&error_fatal);
-
- memory_region_add_subregion(address_space_mem, 0, machine->ram);
memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
/*
@@ -337,7 +336,7 @@ static void mips_fulong2e_init(MachineState *machine)
write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
} else {
if (bios_name == NULL) {
- bios_name = FULONG_BIOSNAME;
+ bios_name = FULOONG_BIOSNAME;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
@@ -363,7 +362,7 @@ static void mips_fulong2e_init(MachineState *machine)
pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
/* South bridge -> IP5 */
- vt82c686b_southbridge_init(pci_bus, FULONG2E_VIA_SLOT, env->irq[5],
+ vt82c686b_southbridge_init(pci_bus, FULOONG2E_VIA_SLOT, env->irq[5],
&smbus, &isa_bus);
/* GPU */
@@ -384,14 +383,16 @@ static void mips_fulong2e_init(MachineState *machine)
network_init(pci_bus);
}
-static void mips_fulong2e_machine_init(MachineClass *mc)
+static void mips_fuloong2e_machine_init(MachineClass *mc)
{
- mc->desc = "Fulong 2e mini pc";
- mc->init = mips_fulong2e_init;
+ mc->desc = "Fuloong 2e mini pc";
+ mc->alias = "fulong2e"; /* Incorrect name used up to QEMU 4.2 */
+ mc->init = mips_fuloong2e_init;
mc->block_default_type = IF_IDE;
mc->default_cpu_type = MIPS_CPU_TYPE_NAME("Loongson-2E");
mc->default_ram_size = 256 * MiB;
- mc->default_ram_id = "fulong2e.ram";
+ mc->default_ram_id = "fuloong2e.ram";
+ mc->minimum_page_bits = 14;
}
-DEFINE_MACHINE("fulong2e", mips_fulong2e_machine_init)
+DEFINE_MACHINE("fuloong2e", mips_fuloong2e_machine_init)
diff --git a/hw/mips/mips_jazz.c b/hw/mips/jazz.c
index afea52b41b..afea52b41b 100644
--- a/hw/mips/mips_jazz.c
+++ b/hw/mips/jazz.c
diff --git a/hw/mips/mips_malta.c b/hw/mips/malta.c
index e4c4de1b4e..636c95d1fe 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/malta.c
@@ -427,10 +427,9 @@ static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
break;
default:
-#if 0
- printf("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
- addr);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "malta_fpga_read: Bad register addr 0x%"HWADDR_PRIX"\n",
+ addr);
break;
}
return val;
@@ -515,10 +514,9 @@ static void malta_fpga_write(void *opaque, hwaddr addr,
break;
default:
-#if 0
- printf("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
- addr);
-#endif
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "malta_fpga_write: Bad register addr 0x%"HWADDR_PRIX"\n",
+ addr);
break;
}
}
@@ -1185,17 +1183,14 @@ static void create_cpu_without_cps(MachineState *ms,
static void create_cps(MachineState *ms, MaltaState *s,
qemu_irq *cbus_irq, qemu_irq *i8259_irq)
{
- Error *err = NULL;
-
sysbus_init_child_obj(OBJECT(s), "cps", OBJECT(&s->cps), sizeof(s->cps),
TYPE_MIPS_CPS);
- object_property_set_str(OBJECT(&s->cps), ms->cpu_type, "cpu-type", &err);
- object_property_set_int(OBJECT(&s->cps), ms->smp.cpus, "num-vp", &err);
- object_property_set_bool(OBJECT(&s->cps), true, "realized", &err);
- if (err != NULL) {
- error_report("%s", error_get_pretty(err));
- exit(1);
- }
+ object_property_set_str(OBJECT(&s->cps), ms->cpu_type, "cpu-type",
+ &error_fatal);
+ object_property_set_int(OBJECT(&s->cps), ms->smp.cpus, "num-vp",
+ &error_fatal);
+ object_property_set_bool(OBJECT(&s->cps), true, "realized",
+ &error_fatal);
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1);
diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c
index 796730b11d..0f9c6f07c1 100644
--- a/hw/mips/mips_int.c
+++ b/hw/mips/mips_int.c
@@ -47,17 +47,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level)
if (level) {
env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
-
- if (kvm_enabled() && irq == 2) {
- kvm_mips_set_interrupt(cpu, irq, level);
- }
-
} else {
env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
+ }
- if (kvm_enabled() && irq == 2) {
- kvm_mips_set_interrupt(cpu, irq, level);
- }
+ if (kvm_enabled() && (irq == 2 || irq == 3)) {
+ kvm_mips_set_interrupt(cpu, irq, level);
}
if (env->CP0_Cause & CP0Ca_IP_mask) {
diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mipssim.c
index d220318939..d220318939 100644
--- a/hw/mips/mips_mipssim.c
+++ b/hw/mips/mipssim.c
diff --git a/hw/mips/mips_r4k.c b/hw/mips/r4k.c
index 3487013a4a..3487013a4a 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/r4k.c
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index b25181b711..60a9d80b74 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -56,6 +56,7 @@ 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_mphi.o
common-obj-$(CONFIG_RASPI) += bcm2835_property.o
common-obj-$(CONFIG_RASPI) += bcm2835_rng.o
common-obj-$(CONFIG_RASPI) += bcm2835_thermal.o
diff --git a/hw/misc/bcm2835_mphi.c b/hw/misc/bcm2835_mphi.c
new file mode 100644
index 0000000000..0428e10ba5
--- /dev/null
+++ b/hw/misc/bcm2835_mphi.c
@@ -0,0 +1,191 @@
+/*
+ * BCM2835 SOC MPHI emulation
+ *
+ * Very basic emulation, only providing the FIQ interrupt needed to
+ * allow the dwc-otg USB host controller driver in the Raspbian kernel
+ * to function.
+ *
+ * Copyright (c) 2020 Paul Zimmerman <pauldzim@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/misc/bcm2835_mphi.h"
+#include "migration/vmstate.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+
+static inline void mphi_raise_irq(BCM2835MphiState *s)
+{
+ qemu_set_irq(s->irq, 1);
+}
+
+static inline void mphi_lower_irq(BCM2835MphiState *s)
+{
+ qemu_set_irq(s->irq, 0);
+}
+
+static uint64_t mphi_reg_read(void *ptr, hwaddr addr, unsigned size)
+{
+ BCM2835MphiState *s = ptr;
+ uint32_t val = 0;
+
+ switch (addr) {
+ case 0x28: /* outdda */
+ val = s->outdda;
+ break;
+ case 0x2c: /* outddb */
+ val = s->outddb;
+ break;
+ case 0x4c: /* ctrl */
+ val = s->ctrl;
+ val |= 1 << 17;
+ break;
+ case 0x50: /* intstat */
+ val = s->intstat;
+ break;
+ case 0x1f0: /* swirq_set */
+ val = s->swirq;
+ break;
+ case 0x1f4: /* swirq_clr */
+ val = s->swirq;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "read from unknown register");
+ break;
+ }
+
+ return val;
+}
+
+static void mphi_reg_write(void *ptr, hwaddr addr, uint64_t val, unsigned size)
+{
+ BCM2835MphiState *s = ptr;
+ int do_irq = 0;
+
+ switch (addr) {
+ case 0x28: /* outdda */
+ s->outdda = val;
+ break;
+ case 0x2c: /* outddb */
+ s->outddb = val;
+ if (val & (1 << 29)) {
+ do_irq = 1;
+ }
+ break;
+ case 0x4c: /* ctrl */
+ s->ctrl = val;
+ if (val & (1 << 16)) {
+ do_irq = -1;
+ }
+ break;
+ case 0x50: /* intstat */
+ s->intstat = val;
+ if (val & ((1 << 16) | (1 << 29))) {
+ do_irq = -1;
+ }
+ break;
+ case 0x1f0: /* swirq_set */
+ s->swirq |= val;
+ do_irq = 1;
+ break;
+ case 0x1f4: /* swirq_clr */
+ s->swirq &= ~val;
+ do_irq = -1;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "write to unknown register");
+ return;
+ }
+
+ if (do_irq > 0) {
+ mphi_raise_irq(s);
+ } else if (do_irq < 0) {
+ mphi_lower_irq(s);
+ }
+}
+
+static const MemoryRegionOps mphi_mmio_ops = {
+ .read = mphi_reg_read,
+ .write = mphi_reg_write,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void mphi_reset(DeviceState *dev)
+{
+ BCM2835MphiState *s = BCM2835_MPHI(dev);
+
+ s->outdda = 0;
+ s->outddb = 0;
+ s->ctrl = 0;
+ s->intstat = 0;
+ s->swirq = 0;
+}
+
+static void mphi_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ BCM2835MphiState *s = BCM2835_MPHI(dev);
+
+ sysbus_init_irq(sbd, &s->irq);
+}
+
+static void mphi_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ BCM2835MphiState *s = BCM2835_MPHI(obj);
+
+ memory_region_init_io(&s->iomem, obj, &mphi_mmio_ops, s, "mphi", MPHI_MMIO_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+const VMStateDescription vmstate_mphi_state = {
+ .name = "mphi",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(outdda, BCM2835MphiState),
+ VMSTATE_UINT32(outddb, BCM2835MphiState),
+ VMSTATE_UINT32(ctrl, BCM2835MphiState),
+ VMSTATE_UINT32(intstat, BCM2835MphiState),
+ VMSTATE_UINT32(swirq, BCM2835MphiState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void mphi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = mphi_realize;
+ dc->reset = mphi_reset;
+ dc->vmsd = &vmstate_mphi_state;
+}
+
+static const TypeInfo bcm2835_mphi_type_info = {
+ .name = TYPE_BCM2835_MPHI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BCM2835MphiState),
+ .instance_init = mphi_init,
+ .class_init = mphi_class_init,
+};
+
+static void bcm2835_mphi_register_types(void)
+{
+ type_register_static(&bcm2835_mphi_type_info);
+}
+
+type_init(bcm2835_mphi_register_types)
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
index 9327ac8a30..281345862c 100644
--- a/hw/net/mcf_fec.c
+++ b/hw/net/mcf_fec.c
@@ -7,7 +7,7 @@
*/
#include "qemu/osdep.h"
-#include "hw/hw.h"
+#include "qemu/log.h"
#include "hw/irq.h"
#include "net/net.h"
#include "qemu/module.h"
@@ -392,7 +392,8 @@ static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
case 0x188: return s->emrbr;
case 0x200 ... 0x2e0: return s->mib[(addr & 0x1ff) / 4];
default:
- hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address 0x%" HWADDR_PRIX "\n",
+ __func__, addr);
return 0;
}
}
@@ -492,7 +493,9 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
s->mib[(addr & 0x1ff) / 4] = value;
break;
default:
- hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address 0x%" HWADDR_PRIX "\n",
+ __func__, addr);
+ return;
}
mcf_fec_update(s);
}
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
index ff5db03e6b..beec1c4e4d 100644
--- a/hw/nvram/mac_nvram.c
+++ b/hw/nvram/mac_nvram.c
@@ -30,18 +30,9 @@
#include "migration/vmstate.h"
#include "qemu/cutils.h"
#include "qemu/module.h"
+#include "trace.h"
#include <zlib.h>
-/* debug NVR */
-//#define DEBUG_NVR
-
-#ifdef DEBUG_NVR
-#define NVR_DPRINTF(fmt, ...) \
- do { printf("NVR: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define NVR_DPRINTF(fmt, ...)
-#endif
-
#define DEF_SYSTEM_SIZE 0xc10
/* macio style NVRAM device */
@@ -51,9 +42,8 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr,
MacIONVRAMState *s = opaque;
addr = (addr >> s->it_shift) & (s->size - 1);
+ trace_macio_nvram_write(addr, value);
s->data[addr] = value;
- NVR_DPRINTF("writeb addr %04" HWADDR_PRIx " val %" PRIx64 "\n",
- addr, value);
}
static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
@@ -64,8 +54,7 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
addr = (addr >> s->it_shift) & (s->size - 1);
value = s->data[addr];
- NVR_DPRINTF("readb addr %04" HWADDR_PRIx " val %" PRIx32 "\n",
- addr, value);
+ trace_macio_nvram_read(addr, value);
return value;
}
diff --git a/hw/nvram/trace-events b/hw/nvram/trace-events
index 0dea9260ce..e023193295 100644
--- a/hw/nvram/trace-events
+++ b/hw/nvram/trace-events
@@ -13,3 +13,7 @@ fw_cfg_add_string(uint16_t key_value, const char *key_name, const char *value) "
fw_cfg_add_i16(uint16_t key_value, const char *key_name, uint16_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx16
fw_cfg_add_i32(uint16_t key_value, const char *key_name, uint32_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx32
fw_cfg_add_i64(uint16_t key_value, const char *key_name, uint64_t value) "key 0x%04" PRIx16 " '%s', value 0x%" PRIx64
+
+# mac_nvram.c
+macio_nvram_read(uint32_t addr, uint8_t val) "read addr=0x%04"PRIx32" val=0x%02x"
+macio_nvram_write(uint32_t addr, uint8_t val) "write addr=0x%04"PRIx32" val=0x%02x"
diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c
index 3ae2f788a4..952bc71122 100644
--- a/hw/pci-bridge/dec.c
+++ b/hw/pci-bridge/dec.c
@@ -32,16 +32,6 @@
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_bus.h"
-/* debug DEC */
-//#define DEBUG_DEC
-
-#ifdef DEBUG_DEC
-#define DEC_DPRINTF(fmt, ...) \
- do { printf("DEC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DEC_DPRINTF(fmt, ...)
-#endif
-
#define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154)
typedef struct DECState {
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index 9642c77e98..036a61877a 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -55,3 +55,8 @@ config PCI_EXPRESS_DESIGNWARE
bool
select PCI_EXPRESS
select MSI_NONBROKEN
+
+config PCI_BONITO
+ select PCI
+ select UNIMP
+ bool
diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs
index 8c87e8494d..e422e0aca0 100644
--- a/hw/pci-host/Makefile.objs
+++ b/hw/pci-host/Makefile.objs
@@ -12,7 +12,7 @@ common-obj-$(CONFIG_PPCE500_PCI) += ppce500.o
common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o
common-obj-$(CONFIG_PCI_SABRE) += sabre.o
-common-obj-$(CONFIG_FULONG) += bonito.o
+common-obj-$(CONFIG_PCI_BONITO) += bonito.o
common-obj-$(CONFIG_PCI_I440FX) += i440fx.o
common-obj-$(CONFIG_XEN_IGD_PASSTHROUGH) += xen_igd_pt.o
common-obj-$(CONFIG_PCI_EXPRESS_Q35) += q35.o
diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c
index f212796044..f9697dcc43 100644
--- a/hw/pci-host/bonito.c
+++ b/hw/pci-host/bonito.c
@@ -11,7 +11,7 @@
*/
/*
- * fulong 2e mini pc has a bonito north bridge.
+ * fuloong 2e mini pc has a bonito north bridge.
*/
/*
@@ -39,6 +39,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qemu/error-report.h"
#include "hw/pci/pci.h"
#include "hw/irq.h"
@@ -48,6 +49,8 @@
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
#include "exec/address-spaces.h"
+#include "hw/misc/unimp.h"
+#include "hw/registerfields.h"
/* #define DEBUG_BONITO */
@@ -81,7 +84,7 @@
#define BONITO_PCILO1_BASE 0x14000000
#define BONITO_PCILO2_BASE 0x18000000
#define BONITO_PCIHI_BASE 0x20000000
-#define BONITO_PCIHI_SIZE 0x20000000
+#define BONITO_PCIHI_SIZE 0x60000000
#define BONITO_PCIHI_TOP (BONITO_PCIHI_BASE + BONITO_PCIHI_SIZE - 1)
#define BONITO_PCIIO_BASE 0x1fd00000
#define BONITO_PCIIO_BASE_VA 0xbfd00000
@@ -110,8 +113,19 @@
/* Power on register */
#define BONITO_BONPONCFG (0x00 >> 2) /* 0x100 */
+
+/* PCI configuration register */
#define BONITO_BONGENCFG_OFFSET 0x4
#define BONITO_BONGENCFG (BONITO_BONGENCFG_OFFSET >> 2) /*0x104 */
+REG32(BONGENCFG, 0x104)
+FIELD(BONGENCFG, DEBUGMODE, 0, 1)
+FIELD(BONGENCFG, SNOOP, 1, 1)
+FIELD(BONGENCFG, CPUSELFRESET, 2, 1)
+FIELD(BONGENCFG, BYTESWAP, 6, 1)
+FIELD(BONGENCFG, UNCACHED, 7, 1)
+FIELD(BONGENCFG, PREFETCH, 8, 1)
+FIELD(BONGENCFG, WRITEBEHIND, 9, 1)
+FIELD(BONGENCFG, PCIQUEUE, 12, 1)
/* 2. IO & IDE configuration */
#define BONITO_IODEVCFG (0x08 >> 2) /* 0x108 */
@@ -239,7 +253,7 @@ static void bonito_writel(void *opaque, hwaddr addr,
saddr = addr >> 2;
- DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n",
+ DPRINTF("bonito_writel "TARGET_FMT_plx" val %lx saddr %x\n",
addr, val, saddr);
switch (saddr) {
case BONITO_BONPONCFG:
@@ -327,7 +341,7 @@ static void bonito_pciconf_writel(void *opaque, hwaddr addr,
PCIBonitoState *s = opaque;
PCIDevice *d = PCI_DEVICE(s);
- DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
+ DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %lx\n", addr, val);
d->config_write(d, addr, val, 4);
}
@@ -474,7 +488,7 @@ static void bonito_spciconf_write(void *opaque, hwaddr addr, uint64_t val,
uint32_t pciaddr;
uint16_t status;
- DPRINTF("bonito_spciconf_write "TARGET_FMT_plx" size %d val %x\n",
+ DPRINTF("bonito_spciconf_write "TARGET_FMT_plx" size %d val %lx\n",
addr, size, val);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -559,11 +573,11 @@ static int pci_bonito_map_irq(PCIDevice *pci_dev, int irq_num)
slot = (pci_dev->devfn >> 3);
switch (slot) {
- case 5: /* FULONG2E_VIA_SLOT, SouthBridge, IDE, USB, ACPI, AC97, MC97 */
+ case 5: /* FULOONG2E_VIA_SLOT, SouthBridge, IDE, USB, ACPI, AC97, MC97 */
return irq_num % 4 + BONITO_IRQ_BASE;
- case 6: /* FULONG2E_ATI_SLOT, VGA */
+ case 6: /* FULOONG2E_ATI_SLOT, VGA */
return 4 + BONITO_IRQ_BASE;
- case 7: /* FULONG2E_RTL_SLOT, RTL8139 */
+ case 7: /* FULOONG2E_RTL_SLOT, RTL8139 */
return 5 + BONITO_IRQ_BASE;
case 8 ... 12: /* PCI slot 1 to 4 */
return (slot - 8 + irq_num) + 6 + BONITO_IRQ_BASE;
@@ -575,11 +589,18 @@ static int pci_bonito_map_irq(PCIDevice *pci_dev, int irq_num)
static void bonito_reset(void *opaque)
{
PCIBonitoState *s = opaque;
+ uint32_t val = 0;
/* set the default value of north bridge registers */
s->regs[BONITO_BONPONCFG] = 0xc40;
- s->regs[BONITO_BONGENCFG] = 0x1384;
+ val = FIELD_DP32(val, BONGENCFG, PCIQUEUE, 1);
+ val = FIELD_DP32(val, BONGENCFG, WRITEBEHIND, 1);
+ val = FIELD_DP32(val, BONGENCFG, PREFETCH, 1);
+ val = FIELD_DP32(val, BONGENCFG, UNCACHED, 1);
+ val = FIELD_DP32(val, BONGENCFG, CPUSELFRESET, 1);
+ s->regs[BONITO_BONGENCFG] = val;
+
s->regs[BONITO_IODEVCFG] = 0x2bff8010;
s->regs[BONITO_SDCFG] = 0x255e0091;
@@ -604,14 +625,26 @@ static void bonito_pcihost_realize(DeviceState *dev, Error **errp)
{
PCIHostState *phb = PCI_HOST_BRIDGE(dev);
BonitoState *bs = BONITO_PCI_HOST_BRIDGE(dev);
+ MemoryRegion *pcimem_lo_alias = g_new(MemoryRegion, 3);
- memory_region_init(&bs->pci_mem, OBJECT(dev), "pci.mem", BONITO_PCILO_SIZE);
+ memory_region_init(&bs->pci_mem, OBJECT(dev), "pci.mem", BONITO_PCIHI_SIZE);
phb->bus = pci_register_root_bus(dev, "pci",
pci_bonito_set_irq, pci_bonito_map_irq,
dev, &bs->pci_mem, get_system_io(),
0x28, 32, TYPE_PCI_BUS);
- memory_region_add_subregion(get_system_memory(), BONITO_PCILO_BASE,
- &bs->pci_mem);
+
+ for (size_t i = 0; i < 3; i++) {
+ char *name = g_strdup_printf("pci.lomem%zu", i);
+
+ memory_region_init_alias(&pcimem_lo_alias[i], NULL, name,
+ &bs->pci_mem, i * 64 * MiB, 64 * MiB);
+ memory_region_add_subregion(get_system_memory(),
+ BONITO_PCILO_BASE + i * 64 * MiB,
+ &pcimem_lo_alias[i]);
+ g_free(name);
+ }
+
+ create_unimplemented_device("pci.io", BONITO_PCIIO_BASE, 1 * MiB);
}
static void bonito_realize(PCIDevice *dev, Error **errp)
@@ -619,6 +652,8 @@ static void bonito_realize(PCIDevice *dev, Error **errp)
PCIBonitoState *s = PCI_BONITO(dev);
SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost);
PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+ BonitoState *bs = BONITO_PCI_HOST_BRIDGE(s->pcihost);
+ MemoryRegion *pcimem_alias = g_new(MemoryRegion, 1);
/*
* Bonito North Bridge, built on FPGA,
@@ -644,15 +679,20 @@ static void bonito_realize(PCIDevice *dev, Error **errp)
sysbus_init_mmio(sysbus, &phb->data_mem);
sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE);
+ create_unimplemented_device("bonito", BONITO_REG_BASE, BONITO_REG_SIZE);
+
memory_region_init_io(&s->iomem_ldma, OBJECT(s), &bonito_ldma_ops, s,
"ldma", 0x100);
sysbus_init_mmio(sysbus, &s->iomem_ldma);
- sysbus_mmio_map(sysbus, 3, 0xbfe00200);
+ sysbus_mmio_map(sysbus, 3, 0x1fe00200);
+ /* PCI copier */
memory_region_init_io(&s->iomem_cop, OBJECT(s), &bonito_cop_ops, s,
"cop", 0x100);
sysbus_init_mmio(sysbus, &s->iomem_cop);
- sysbus_mmio_map(sysbus, 4, 0xbfe00300);
+ sysbus_mmio_map(sysbus, 4, 0x1fe00300);
+
+ create_unimplemented_device("ROMCS", BONITO_FLASH_BASE, 60 * MiB);
/* Map PCI IO Space 0x1fd0 0000 - 0x1fd1 0000 */
memory_region_init_alias(&s->bonito_pciio, OBJECT(s), "isa_mmio",
@@ -661,10 +701,25 @@ static void bonito_realize(PCIDevice *dev, Error **errp)
sysbus_mmio_map(sysbus, 5, BONITO_PCIIO_BASE);
/* add pci local io mapping */
- memory_region_init_alias(&s->bonito_localio, OBJECT(s), "isa_mmio",
- get_system_io(), 0, BONITO_DEV_SIZE);
+
+ memory_region_init_alias(&s->bonito_localio, OBJECT(s), "IOCS[0]",
+ get_system_io(), 0, 256 * KiB);
sysbus_init_mmio(sysbus, &s->bonito_localio);
sysbus_mmio_map(sysbus, 6, BONITO_DEV_BASE);
+ create_unimplemented_device("IOCS[1]", BONITO_DEV_BASE + 1 * 256 * KiB,
+ 256 * KiB);
+ create_unimplemented_device("IOCS[2]", BONITO_DEV_BASE + 2 * 256 * KiB,
+ 256 * KiB);
+ create_unimplemented_device("IOCS[3]", BONITO_DEV_BASE + 3 * 256 * KiB,
+ 256 * KiB);
+
+ memory_region_init_alias(pcimem_alias, NULL, "pci.mem.alias",
+ &bs->pci_mem, 0, BONITO_PCIHI_SIZE);
+ memory_region_add_subregion(get_system_memory(),
+ BONITO_PCIHI_BASE, pcimem_alias);
+ create_unimplemented_device("PCI_2",
+ (hwaddr)BONITO_PCIHI_BASE + BONITO_PCIHI_SIZE,
+ 2 * GiB);
/* set the default value of north bridge pci config */
pci_set_word(dev->config + PCI_COMMAND, 0x0000);
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index da637822f9..806a5d9a8d 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1984,12 +1984,26 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
cpu_synchronize_state(cs);
ppc_cpu_do_system_reset(cs);
- /*
- * SRR1[42:45] is set to 0100 which the ISA defines as implementation
- * dependent. POWER processors use this for xscom triggered interrupts,
- * which come from the BMC or NMI IPIs.
- */
- env->spr[SPR_SRR1] |= PPC_BIT(43);
+ if (env->spr[SPR_SRR1] & SRR1_WAKESTATE) {
+ /*
+ * Power-save wakeups, as indicated by non-zero SRR1[46:47] put the
+ * wakeup reason in SRR1[42:45], system reset is indicated with 0b0100
+ * (PPC_BIT(43)).
+ */
+ if (!(env->spr[SPR_SRR1] & SRR1_WAKERESET)) {
+ warn_report("ppc_cpu_do_system_reset does not set system reset wakeup reason");
+ env->spr[SPR_SRR1] |= SRR1_WAKERESET;
+ }
+ } else {
+ /*
+ * For non-powersave system resets, SRR1[42:45] are defined to be
+ * implementation-dependent. The POWER9 User Manual specifies that
+ * an external (SCOM driven, which may come from a BMC nmi command or
+ * another CPU requesting a NMI IPI) system reset exception should be
+ * 0b0010 (PPC_BIT(44)).
+ */
+ env->spr[SPR_SRR1] |= SRR1_WAKESCOM;
+ }
}
static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 9b358fcc60..3b1a5ed865 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -445,7 +445,8 @@ static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
g_assert(drc);
elem = spapr_get_drconf_cell(size / lmb_size, addr,
spapr_drc_index(drc), node,
- SPAPR_LMB_FLAGS_ASSIGNED);
+ (SPAPR_LMB_FLAGS_ASSIGNED |
+ SPAPR_LMB_FLAGS_HOTREMOVABLE));
QSIMPLEQ_INSERT_TAIL(&drconf_queue, elem, entry);
nr_entries++;
cur_addr = addr + size;
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index e1f76c74f3..9c8c1b14cf 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -407,6 +407,7 @@ static const TypeInfo spapr_cpu_core_type_infos[] = {
DEFINE_SPAPR_CPU_CORE_TYPE("power8nvl_v1.0"),
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v1.0"),
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.0"),
+ DEFINE_SPAPR_CPU_CORE_TYPE("power10_v1.0"),
#ifdef CONFIG_KVM
DEFINE_SPAPR_CPU_CORE_TYPE("host"),
#endif
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index ff9fbe958a..94d19571f7 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -27,6 +27,11 @@ config SPIKE
select HTIF
select SIFIVE
+config OPENTITAN
+ bool
+ select HART
+ select UNIMP
+
config RISCV_VIRT
bool
imply PCI_DEVICES
diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs
index fc3c6dd7c8..57cc708f5d 100644
--- a/hw/riscv/Makefile.objs
+++ b/hw/riscv/Makefile.objs
@@ -1,6 +1,7 @@
obj-y += boot.o
obj-$(CONFIG_SPIKE) += riscv_htif.o
obj-$(CONFIG_HART) += riscv_hart.o
+obj-$(CONFIG_OPENTITAN) += opentitan.o
obj-$(CONFIG_SIFIVE_E) += sifive_e.o
obj-$(CONFIG_SIFIVE_E) += sifive_e_prci.o
obj-$(CONFIG_SIFIVE) += sifive_clint.o
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index 726300a171..adb421b91b 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -41,34 +41,11 @@ void riscv_find_and_load_firmware(MachineState *machine,
{
char *firmware_filename = NULL;
- if (!machine->firmware) {
+ if ((!machine->firmware) || (!strcmp(machine->firmware, "default"))) {
/*
- * The user didn't specify -bios.
- * At the moment we default to loading nothing when this hapens.
- * In the future this defaul will change to loading the prebuilt
- * OpenSBI firmware. Let's warn the user and then continue.
- */
- if (!qtest_enabled()) {
- warn_report("No -bios option specified. Not loading a firmware.");
- warn_report("This default will change in a future QEMU release. " \
- "Please use the -bios option to avoid breakages when "\
- "this happens.");
- warn_report("See QEMU's deprecation documentation for details.");
- }
- return;
- }
-
- if (!strcmp(machine->firmware, "default")) {
- /*
- * The user has specified "-bios default". That means we are going to
- * load the OpenSBI binary included in the QEMU source.
- *
- * We can't load the binary by default as it will break existing users
- * as users are already loading their own firmware.
- *
- * Let's try to get everyone to specify the -bios option at all times,
- * so then in the future we can make "-bios default" the default option
- * if no -bios option is set without breaking anything.
+ * The user didn't specify -bios, or has specified "-bios default".
+ * That means we are going to load the OpenSBI binary included in
+ * the QEMU source.
*/
firmware_filename = riscv_find_firmware(default_machine_firmware);
} else if (strcmp(machine->firmware, "none")) {
@@ -88,9 +65,17 @@ char *riscv_find_firmware(const char *firmware_filename)
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename);
if (filename == NULL) {
- error_report("Unable to load the RISC-V firmware \"%s\"",
- firmware_filename);
- exit(1);
+ if (!qtest_enabled()) {
+ /*
+ * We only ship plain binary bios images in the QEMU source.
+ * With Spike machine that uses ELF images as the default bios,
+ * running QEMU test will complain hence let's suppress the error
+ * report for QEMU testing.
+ */
+ error_report("Unable to load the RISC-V firmware \"%s\"",
+ firmware_filename);
+ exit(1);
+ }
}
return filename;
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
new file mode 100644
index 0000000000..b4fb836466
--- /dev/null
+++ b/hw/riscv/opentitan.c
@@ -0,0 +1,184 @@
+/*
+ * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * Provides a board compatible with the OpenTitan FPGA platform:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/riscv/opentitan.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/misc/unimp.h"
+#include "hw/riscv/boot.h"
+#include "exec/address-spaces.h"
+
+static const struct MemmapEntry {
+ hwaddr base;
+ hwaddr size;
+} ibex_memmap[] = {
+ [IBEX_ROM] = { 0x00008000, 0xc000 },
+ [IBEX_RAM] = { 0x10000000, 0x10000 },
+ [IBEX_FLASH] = { 0x20000000, 0x80000 },
+ [IBEX_UART] = { 0x40000000, 0x10000 },
+ [IBEX_GPIO] = { 0x40010000, 0x10000 },
+ [IBEX_SPI] = { 0x40020000, 0x10000 },
+ [IBEX_FLASH_CTRL] = { 0x40030000, 0x10000 },
+ [IBEX_PINMUX] = { 0x40070000, 0x10000 },
+ [IBEX_RV_TIMER] = { 0x40080000, 0x10000 },
+ [IBEX_PLIC] = { 0x40090000, 0x10000 },
+ [IBEX_PWRMGR] = { 0x400A0000, 0x10000 },
+ [IBEX_RSTMGR] = { 0x400B0000, 0x10000 },
+ [IBEX_CLKMGR] = { 0x400C0000, 0x10000 },
+ [IBEX_AES] = { 0x40110000, 0x10000 },
+ [IBEX_HMAC] = { 0x40120000, 0x10000 },
+ [IBEX_ALERT_HANDLER] = { 0x40130000, 0x10000 },
+ [IBEX_NMI_GEN] = { 0x40140000, 0x10000 },
+ [IBEX_USBDEV] = { 0x40150000, 0x10000 },
+ [IBEX_PADCTRL] = { 0x40160000, 0x10000 }
+};
+
+static void riscv_opentitan_init(MachineState *machine)
+{
+ const struct MemmapEntry *memmap = ibex_memmap;
+ OpenTitanState *s = g_new0(OpenTitanState, 1);
+ MemoryRegion *sys_mem = get_system_memory();
+ MemoryRegion *main_mem = g_new(MemoryRegion, 1);
+
+ /* Initialize SoC */
+ object_initialize_child(OBJECT(machine), "soc", &s->soc,
+ sizeof(s->soc), TYPE_RISCV_IBEX_SOC,
+ &error_abort, NULL);
+ object_property_set_bool(OBJECT(&s->soc), true, "realized",
+ &error_abort);
+
+ memory_region_init_ram(main_mem, NULL, "riscv.lowrisc.ibex.ram",
+ memmap[IBEX_RAM].size, &error_fatal);
+ memory_region_add_subregion(sys_mem,
+ memmap[IBEX_RAM].base, main_mem);
+
+
+ if (machine->firmware) {
+ riscv_load_firmware(machine->firmware, memmap[IBEX_RAM].base, NULL);
+ }
+
+ if (machine->kernel_filename) {
+ riscv_load_kernel(machine->kernel_filename, NULL);
+ }
+}
+
+static void riscv_opentitan_machine_init(MachineClass *mc)
+{
+ mc->desc = "RISC-V Board compatible with OpenTitan";
+ mc->init = riscv_opentitan_init;
+ mc->max_cpus = 1;
+ mc->default_cpu_type = TYPE_RISCV_CPU_IBEX;
+}
+
+DEFINE_MACHINE("opentitan", riscv_opentitan_machine_init)
+
+static void riscv_lowrisc_ibex_soc_init(Object *obj)
+{
+ LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj);
+
+ object_initialize_child(obj, "cpus", &s->cpus,
+ sizeof(s->cpus), TYPE_RISCV_HART_ARRAY,
+ &error_abort, NULL);
+}
+
+static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+ const struct MemmapEntry *memmap = ibex_memmap;
+ MachineState *ms = MACHINE(qdev_get_machine());
+ LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc);
+ MemoryRegion *sys_mem = get_system_memory();
+
+ object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type",
+ &error_abort);
+ object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts",
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->cpus), true, "realized",
+ &error_abort);
+
+ /* Boot ROM */
+ memory_region_init_rom(&s->rom, OBJECT(dev_soc), "riscv.lowrisc.ibex.rom",
+ memmap[IBEX_ROM].size, &error_fatal);
+ memory_region_add_subregion(sys_mem,
+ memmap[IBEX_ROM].base, &s->rom);
+
+ /* Flash memory */
+ memory_region_init_rom(&s->flash_mem, OBJECT(dev_soc), "riscv.lowrisc.ibex.flash",
+ memmap[IBEX_FLASH].size, &error_fatal);
+ memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base,
+ &s->flash_mem);
+
+ create_unimplemented_device("riscv.lowrisc.ibex.uart",
+ memmap[IBEX_UART].base, memmap[IBEX_UART].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.gpio",
+ memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.spi",
+ memmap[IBEX_SPI].base, memmap[IBEX_SPI].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.flash_ctrl",
+ memmap[IBEX_FLASH_CTRL].base, memmap[IBEX_FLASH_CTRL].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.rv_timer",
+ memmap[IBEX_RV_TIMER].base, memmap[IBEX_RV_TIMER].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.pwrmgr",
+ memmap[IBEX_PWRMGR].base, memmap[IBEX_PWRMGR].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.rstmgr",
+ memmap[IBEX_RSTMGR].base, memmap[IBEX_RSTMGR].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.clkmgr",
+ memmap[IBEX_CLKMGR].base, memmap[IBEX_CLKMGR].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.aes",
+ memmap[IBEX_AES].base, memmap[IBEX_AES].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.hmac",
+ memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.plic",
+ memmap[IBEX_PLIC].base, memmap[IBEX_PLIC].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.pinmux",
+ memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.alert_handler",
+ memmap[IBEX_ALERT_HANDLER].base, memmap[IBEX_ALERT_HANDLER].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.nmi_gen",
+ memmap[IBEX_NMI_GEN].base, memmap[IBEX_NMI_GEN].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.usbdev",
+ memmap[IBEX_USBDEV].base, memmap[IBEX_USBDEV].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.padctrl",
+ memmap[IBEX_PADCTRL].base, memmap[IBEX_PADCTRL].size);
+}
+
+static void riscv_lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = riscv_lowrisc_ibex_soc_realize;
+ /* Reason: Uses serial_hds in realize function, thus can't be used twice */
+ dc->user_creatable = false;
+}
+
+static const TypeInfo riscv_lowrisc_ibex_soc_type_info = {
+ .name = TYPE_RISCV_IBEX_SOC,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(LowRISCIbexSoCState),
+ .instance_init = riscv_lowrisc_ibex_soc_init,
+ .class_init = riscv_lowrisc_ibex_soc_class_init,
+};
+
+static void riscv_lowrisc_ibex_soc_register_types(void)
+{
+ type_register_static(&riscv_lowrisc_ibex_soc_type_info);
+}
+
+type_init(riscv_lowrisc_ibex_soc_register_types)
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index b53109521e..472a98970b 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -79,7 +79,7 @@ static void riscv_sifive_e_init(MachineState *machine)
{
const struct MemmapEntry *memmap = sifive_e_memmap;
- SiFiveEState *s = g_new0(SiFiveEState, 1);
+ SiFiveEState *s = RISCV_E_MACHINE(machine);
MemoryRegion *sys_mem = get_system_memory();
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
int i;
@@ -115,6 +115,35 @@ static void riscv_sifive_e_init(MachineState *machine)
}
}
+static void sifive_e_machine_instance_init(Object *obj)
+{
+}
+
+static void sifive_e_machine_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "RISC-V Board compatible with SiFive E SDK";
+ mc->init = riscv_sifive_e_init;
+ mc->max_cpus = 1;
+ mc->default_cpu_type = SIFIVE_E_CPU;
+}
+
+static const TypeInfo sifive_e_machine_typeinfo = {
+ .name = MACHINE_TYPE_NAME("sifive_e"),
+ .parent = TYPE_MACHINE,
+ .class_init = sifive_e_machine_class_init,
+ .instance_init = sifive_e_machine_instance_init,
+ .instance_size = sizeof(SiFiveEState),
+};
+
+static void sifive_e_machine_init_register_types(void)
+{
+ type_register_static(&sifive_e_machine_typeinfo);
+}
+
+type_init(sifive_e_machine_init_register_types)
+
static void riscv_sifive_e_soc_init(Object *obj)
{
MachineState *ms = MACHINE(qdev_get_machine());
@@ -214,16 +243,6 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
&s->xip_mem);
}
-static void riscv_sifive_e_machine_init(MachineClass *mc)
-{
- mc->desc = "RISC-V Board compatible with SiFive E SDK";
- mc->init = riscv_sifive_e_init;
- mc->max_cpus = 1;
- mc->default_cpu_type = SIFIVE_E_CPU;
-}
-
-DEFINE_MACHINE("sifive_e", riscv_sifive_e_machine_init)
-
static void riscv_sifive_e_soc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 4299bdf480..f9fef2be91 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -481,7 +481,7 @@ static void sifive_u_machine_init_register_types(void)
type_init(sifive_u_machine_init_register_types)
-static void riscv_sifive_u_soc_init(Object *obj)
+static void sifive_u_soc_instance_init(Object *obj)
{
MachineState *ms = MACHINE(qdev_get_machine());
SiFiveUSoCState *s = RISCV_U_SOC(obj);
@@ -520,7 +520,7 @@ static void riscv_sifive_u_soc_init(Object *obj)
TYPE_CADENCE_GEM);
}
-static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
+static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
SiFiveUSoCState *s = RISCV_U_SOC(dev);
@@ -635,32 +635,32 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size);
}
-static Property riscv_sifive_u_soc_props[] = {
+static Property sifive_u_soc_props[] = {
DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL),
DEFINE_PROP_END_OF_LIST()
};
-static void riscv_sifive_u_soc_class_init(ObjectClass *oc, void *data)
+static void sifive_u_soc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- device_class_set_props(dc, riscv_sifive_u_soc_props);
- dc->realize = riscv_sifive_u_soc_realize;
+ device_class_set_props(dc, sifive_u_soc_props);
+ dc->realize = sifive_u_soc_realize;
/* Reason: Uses serial_hds in realize function, thus can't be used twice */
dc->user_creatable = false;
}
-static const TypeInfo riscv_sifive_u_soc_type_info = {
+static const TypeInfo sifive_u_soc_type_info = {
.name = TYPE_RISCV_U_SOC,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SiFiveUSoCState),
- .instance_init = riscv_sifive_u_soc_init,
- .class_init = riscv_sifive_u_soc_class_init,
+ .instance_init = sifive_u_soc_instance_init,
+ .class_init = sifive_u_soc_class_init,
};
-static void riscv_sifive_u_soc_register_types(void)
+static void sifive_u_soc_register_types(void)
{
- type_register_static(&riscv_sifive_u_soc_type_info);
+ type_register_static(&sifive_u_soc_type_info);
}
-type_init(riscv_sifive_u_soc_register_types)
+type_init(sifive_u_soc_register_types)
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index d0c4843712..7bbbdb5036 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -257,221 +257,6 @@ static void spike_board_init(MachineState *machine)
false);
}
-static void spike_v1_10_0_board_init(MachineState *machine)
-{
- const struct MemmapEntry *memmap = spike_memmap;
-
- SpikeState *s = g_new0(SpikeState, 1);
- MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *main_mem = g_new(MemoryRegion, 1);
- MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
- int i;
- unsigned int smp_cpus = machine->smp.cpus;
-
- if (!qtest_enabled()) {
- info_report("The Spike v1.10.0 machine has been deprecated. "
- "Please use the generic spike machine and specify the ISA "
- "versions using -cpu.");
- }
-
- /* Initialize SOC */
- object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
- TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
- object_property_set_str(OBJECT(&s->soc), SPIKE_V1_10_0_CPU, "cpu-type",
- &error_abort);
- object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts",
- &error_abort);
- object_property_set_bool(OBJECT(&s->soc), true, "realized",
- &error_abort);
-
- /* register system main memory (actual RAM) */
- memory_region_init_ram(main_mem, NULL, "riscv.spike.ram",
- machine->ram_size, &error_fatal);
- memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base,
- main_mem);
-
- /* create device tree */
- create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
-
- /* boot rom */
- memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom",
- memmap[SPIKE_MROM].size, &error_fatal);
- memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base,
- mask_rom);
-
- if (machine->kernel_filename) {
- riscv_load_kernel(machine->kernel_filename, htif_symbol_callback);
- }
-
- /* reset vector */
- uint32_t reset_vec[8] = {
- 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
- 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */
- 0xf1402573, /* csrr a0, mhartid */
-#if defined(TARGET_RISCV32)
- 0x0182a283, /* lw t0, 24(t0) */
-#elif defined(TARGET_RISCV64)
- 0x0182b283, /* ld t0, 24(t0) */
-#endif
- 0x00028067, /* jr t0 */
- 0x00000000,
- memmap[SPIKE_DRAM].base, /* start: .dword DRAM_BASE */
- 0x00000000,
- /* dtb: */
- };
-
- /* copy in the reset vector in little_endian byte order */
- for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
- reset_vec[i] = cpu_to_le32(reset_vec[i]);
- }
- rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
- memmap[SPIKE_MROM].base, &address_space_memory);
-
- /* copy in the device tree */
- if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
- memmap[SPIKE_MROM].size - sizeof(reset_vec)) {
- error_report("not enough space to store device-tree");
- exit(1);
- }
- qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt));
- rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt),
- memmap[SPIKE_MROM].base + sizeof(reset_vec),
- &address_space_memory);
-
- /* initialize HTIF using symbols found in load_kernel */
- htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0));
-
- /* Core Local Interruptor (timer and IPI) */
- sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size,
- smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
- false);
-}
-
-static void spike_v1_09_1_board_init(MachineState *machine)
-{
- const struct MemmapEntry *memmap = spike_memmap;
-
- SpikeState *s = g_new0(SpikeState, 1);
- MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *main_mem = g_new(MemoryRegion, 1);
- MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
- int i;
- unsigned int smp_cpus = machine->smp.cpus;
-
- if (!qtest_enabled()) {
- info_report("The Spike v1.09.1 machine has been deprecated. "
- "Please use the generic spike machine and specify the ISA "
- "versions using -cpu.");
- }
-
- /* Initialize SOC */
- object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
- TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
- object_property_set_str(OBJECT(&s->soc), SPIKE_V1_09_1_CPU, "cpu-type",
- &error_abort);
- object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts",
- &error_abort);
- object_property_set_bool(OBJECT(&s->soc), true, "realized",
- &error_abort);
-
- /* register system main memory (actual RAM) */
- memory_region_init_ram(main_mem, NULL, "riscv.spike.ram",
- machine->ram_size, &error_fatal);
- memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base,
- main_mem);
-
- /* boot rom */
- memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom",
- memmap[SPIKE_MROM].size, &error_fatal);
- memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base,
- mask_rom);
-
- if (machine->kernel_filename) {
- riscv_load_kernel(machine->kernel_filename, htif_symbol_callback);
- }
-
- /* reset vector */
- uint32_t reset_vec[8] = {
- 0x297 + memmap[SPIKE_DRAM].base - memmap[SPIKE_MROM].base, /* lui */
- 0x00028067, /* jump to DRAM_BASE */
- 0x00000000, /* reserved */
- memmap[SPIKE_MROM].base + sizeof(reset_vec), /* config string pointer */
- 0, 0, 0, 0 /* trap vector */
- };
-
- /* part one of config string - before memory size specified */
- const char *config_string_tmpl =
- "platform {\n"
- " vendor ucb;\n"
- " arch spike;\n"
- "};\n"
- "rtc {\n"
- " addr 0x%" PRIx64 "x;\n"
- "};\n"
- "ram {\n"
- " 0 {\n"
- " addr 0x%" PRIx64 "x;\n"
- " size 0x%" PRIx64 "x;\n"
- " };\n"
- "};\n"
- "core {\n"
- " 0" " {\n"
- " " "0 {\n"
- " isa %s;\n"
- " timecmp 0x%" PRIx64 "x;\n"
- " ipi 0x%" PRIx64 "x;\n"
- " };\n"
- " };\n"
- "};\n";
-
- /* build config string with supplied memory size */
- char *isa = riscv_isa_string(&s->soc.harts[0]);
- char *config_string = g_strdup_printf(config_string_tmpl,
- (uint64_t)memmap[SPIKE_CLINT].base + SIFIVE_TIME_BASE,
- (uint64_t)memmap[SPIKE_DRAM].base,
- (uint64_t)ram_size, isa,
- (uint64_t)memmap[SPIKE_CLINT].base + SIFIVE_TIMECMP_BASE,
- (uint64_t)memmap[SPIKE_CLINT].base + SIFIVE_SIP_BASE);
- g_free(isa);
- size_t config_string_len = strlen(config_string);
-
- /* copy in the reset vector in little_endian byte order */
- for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
- reset_vec[i] = cpu_to_le32(reset_vec[i]);
- }
- rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
- memmap[SPIKE_MROM].base, &address_space_memory);
-
- /* copy in the config string */
- rom_add_blob_fixed_as("mrom.reset", config_string, config_string_len,
- memmap[SPIKE_MROM].base + sizeof(reset_vec),
- &address_space_memory);
-
- /* initialize HTIF using symbols found in load_kernel */
- htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0));
-
- /* Core Local Interruptor (timer and IPI) */
- sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size,
- smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
- false);
-
- g_free(config_string);
-}
-
-static void spike_v1_09_1_machine_init(MachineClass *mc)
-{
- mc->desc = "RISC-V Spike Board (Privileged ISA v1.9.1)";
- mc->init = spike_v1_09_1_board_init;
- mc->max_cpus = 1;
-}
-
-static void spike_v1_10_0_machine_init(MachineClass *mc)
-{
- mc->desc = "RISC-V Spike Board (Privileged ISA v1.10)";
- mc->init = spike_v1_10_0_board_init;
- mc->max_cpus = 1;
-}
-
static void spike_machine_init(MachineClass *mc)
{
mc->desc = "RISC-V Spike Board";
@@ -481,6 +266,4 @@ static void spike_machine_init(MachineClass *mc)
mc->default_cpu_type = SPIKE_V1_10_0_CPU;
}
-DEFINE_MACHINE("spike_v1.9.1", spike_v1_09_1_machine_init)
-DEFINE_MACHINE("spike_v1.10", spike_v1_10_0_machine_init)
DEFINE_MACHINE("spike", spike_machine_init)
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 7ce28895bc..4e4c494a70 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -471,7 +471,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
return dev;
}
-static void riscv_virt_board_init(MachineState *machine)
+static void virt_machine_init(MachineState *machine)
{
const struct MemmapEntry *memmap = virt_memmap;
RISCVVirtState *s = RISCV_VIRT_MACHINE(machine);
@@ -632,32 +632,32 @@ static void riscv_virt_board_init(MachineState *machine)
g_free(plic_hart_config);
}
-static void riscv_virt_machine_instance_init(Object *obj)
+static void virt_machine_instance_init(Object *obj)
{
}
-static void riscv_virt_machine_class_init(ObjectClass *oc, void *data)
+static void virt_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "RISC-V VirtIO board";
- mc->init = riscv_virt_board_init;
+ mc->init = virt_machine_init;
mc->max_cpus = 8;
mc->default_cpu_type = VIRT_CPU;
mc->pci_allow_0_address = true;
}
-static const TypeInfo riscv_virt_machine_typeinfo = {
+static const TypeInfo virt_machine_typeinfo = {
.name = MACHINE_TYPE_NAME("virt"),
.parent = TYPE_MACHINE,
- .class_init = riscv_virt_machine_class_init,
- .instance_init = riscv_virt_machine_instance_init,
+ .class_init = virt_machine_class_init,
+ .instance_init = virt_machine_instance_init,
.instance_size = sizeof(RISCVVirtState),
};
-static void riscv_virt_machine_init_register_types(void)
+static void virt_machine_init_register_types(void)
{
- type_register_static(&riscv_virt_machine_typeinfo);
+ type_register_static(&virt_machine_typeinfo);
}
-type_init(riscv_virt_machine_init_register_types)
+type_init(virt_machine_init_register_types)
diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c
index f11868e865..ab3a2482aa 100644
--- a/hw/s390x/pv.c
+++ b/hw/s390x/pv.c
@@ -88,7 +88,7 @@ int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak)
return s390_pv_cmd(KVM_PV_UNPACK, &args);
}
-void s390_pv_perf_clear_reset(void)
+void s390_pv_prep_reset(void)
{
s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL);
}
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 67ae2e02ff..60b16fef77 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -401,7 +401,7 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms)
s390_cpu_set_state(S390_CPU_STATE_STOPPED, S390_CPU(cs));
}
s390_pv_unshare();
- s390_pv_perf_clear_reset();
+ s390_pv_prep_reset();
}
static void s390_machine_reset(MachineState *machine)
diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c
index 8f9ab0ec16..f9c50ddda5 100644
--- a/hw/sd/pxa2xx_mmci.c
+++ b/hw/sd/pxa2xx_mmci.c
@@ -497,12 +497,12 @@ PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
qdev_prop_set_drive(carddev, "drive", blk, &err);
if (err) {
- error_report("failed to init SD card: %s", error_get_pretty(err));
+ error_reportf_err(err, "failed to init SD card: ");
return NULL;
}
object_property_set_bool(OBJECT(carddev), true, "realized", &err);
if (err) {
- error_report("failed to init SD card: %s", error_get_pretty(err));
+ error_reportf_err(err, "failed to init SD card: ");
return NULL;
}
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 71a9af09ab..3c06a0ac6d 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -703,13 +703,13 @@ SDState *sd_init(BlockBackend *blk, bool is_spi)
dev = DEVICE(obj);
qdev_prop_set_drive(dev, "drive", blk, &err);
if (err) {
- error_report("sd_init failed: %s", error_get_pretty(err));
+ error_reportf_err(err, "sd_init failed: ");
return NULL;
}
qdev_prop_set_bit(dev, "spi", is_spi);
object_property_set_bool(obj, true, "realized", &err);
if (err) {
- error_report("sd_init failed: %s", error_get_pretty(err));
+ error_reportf_err(err, "sd_init failed: ");
return NULL;
}
diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index 2dd9a631e1..43b2f14dd2 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -182,7 +182,7 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
rx = 0;
- while (tx_burst) {
+ while (tx_burst > 0) {
uint8_t byte = tx & 0xff;
DPRINTF("writing 0x%02x\n", (uint32_t)byte);
@@ -206,7 +206,7 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
if (fifo32_is_full(&s->rx_fifo)) {
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RO;
} else {
- fifo32_push(&s->rx_fifo, (uint8_t)rx);
+ fifo32_push(&s->rx_fifo, rx);
}
if (s->burst_length <= 0) {
diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig
index 464348ba14..d4d8c37c28 100644
--- a/hw/usb/Kconfig
+++ b/hw/usb/Kconfig
@@ -46,6 +46,11 @@ config USB_MUSB
bool
select USB
+config USB_DWC2
+ bool
+ default y
+ select USB
+
config TUSB6010
bool
select USB_MUSB
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 66835e5bf7..fa5c3fa1b8 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -12,6 +12,7 @@ common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci-sysbus.o
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
common-obj-$(CONFIG_USB_XHCI_NEC) += hcd-xhci-nec.o
common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o
+common-obj-$(CONFIG_USB_DWC2) += hcd-dwc2.o
common-obj-$(CONFIG_TUSB6010) += tusb6010.o
common-obj-$(CONFIG_IMX) += chipidea.o
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 20717f026b..168428156b 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -631,8 +631,9 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
int64_t id = qemu_file_monitor_add_watch(s->file_monitor, o->path, NULL,
file_monitor_event, s, &err);
if (id == -1) {
- error_report("usb-mtp: failed to add watch for %s: %s", o->path,
- error_get_pretty(err));
+ error_reportf_err(err,
+ "usb-mtp: failed to add watch for %s: ",
+ o->path);
error_free(err);
} else {
trace_usb_mtp_file_monitor_event(s->dev.addr, o->path,
@@ -1276,8 +1277,8 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
s->file_monitor = qemu_file_monitor_new(&err);
if (err) {
- error_report("usb-mtp: file monitoring init failed: %s",
- error_get_pretty(err));
+ error_reportf_err(err,
+ "usb-mtp: file monitoring init failed: ");
error_free(err);
} else {
QTAILQ_INIT(&s->events);
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 4eba47538d..a5204b6f2a 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -229,6 +229,9 @@ static void usb_msd_copy_data(MSDState *s, USBPacket *p)
usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
s->scsi_len -= len;
s->scsi_off += len;
+ if (len > s->data_len) {
+ len = s->data_len;
+ }
s->data_len -= len;
if (s->scsi_len == 0 || s->data_len == 0) {
scsi_req_continue(s->req);
@@ -303,6 +306,9 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
if (s->data_len) {
int len = (p->iov.size - p->actual_length);
usb_packet_skip(p, len);
+ if (len > s->data_len) {
+ len = s->data_len;
+ }
s->data_len -= len;
}
if (s->data_len == 0) {
@@ -469,6 +475,9 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
int len = p->iov.size - p->actual_length;
if (len) {
usb_packet_skip(p, len);
+ if (len > s->data_len) {
+ len = s->data_len;
+ }
s->data_len -= len;
if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
@@ -528,13 +537,17 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
int len = p->iov.size - p->actual_length;
if (len) {
usb_packet_skip(p, len);
+ if (len > s->data_len) {
+ len = s->data_len;
+ }
s->data_len -= len;
if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
}
}
- if (p->actual_length < p->iov.size) {
+ if (p->actual_length < p->iov.size && (p->short_not_ok ||
+ s->scsi_len >= p->ep->max_packet_size)) {
DPRINTF("Deferring packet %p [wait data-in]\n", p);
s->packet = p;
p->status = USB_RET_ASYNC;
diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c
new file mode 100644
index 0000000000..72cbd051f3
--- /dev/null
+++ b/hw/usb/hcd-dwc2.c
@@ -0,0 +1,1417 @@
+/*
+ * dwc-hsotg (dwc2) USB host controller emulation
+ *
+ * Based on hw/usb/hcd-ehci.c and hw/usb/hcd-ohci.c
+ *
+ * Note that to use this emulation with the dwc-otg driver in the
+ * Raspbian kernel, you must pass the option "dwc_otg.fiq_fsm_enable=0"
+ * on the kernel command line.
+ *
+ * Some useful documentation used to develop this emulation can be
+ * found online (as of April 2020) at:
+ *
+ * http://www.capital-micro.com/PDF/CME-M7_Family_User_Guide_EN.pdf
+ * which has a pretty complete description of the controller starting
+ * on page 370.
+ *
+ * https://sourceforge.net/p/wive-ng/wive-ng-mt/ci/master/tree/docs/DataSheets/RT3050_5x_V2.0_081408_0902.pdf
+ * which has a description of the controller registers starting on
+ * page 130.
+ *
+ * Copyright (c) 2020 Paul Zimmerman <pauldzim@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "hw/usb/dwc2-regs.h"
+#include "hw/usb/hcd-dwc2.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+#include "hw/qdev-properties.h"
+
+#define USB_HZ_FS 12000000
+#define USB_HZ_HS 96000000
+#define USB_FRMINTVL 12000
+
+/* nifty macros from Arnon's EHCI version */
+#define get_field(data, field) \
+ (((data) & field##_MASK) >> field##_SHIFT)
+
+#define set_field(data, newval, field) do { \
+ uint32_t val = *(data); \
+ val &= ~field##_MASK; \
+ val |= ((newval) << field##_SHIFT) & field##_MASK; \
+ *(data) = val; \
+} while (0)
+
+#define get_bit(data, bitmask) \
+ (!!((data) & (bitmask)))
+
+/* update irq line */
+static inline void dwc2_update_irq(DWC2State *s)
+{
+ static int oldlevel;
+ int level = 0;
+
+ if ((s->gintsts & s->gintmsk) && (s->gahbcfg & GAHBCFG_GLBL_INTR_EN)) {
+ level = 1;
+ }
+ if (level != oldlevel) {
+ oldlevel = level;
+ trace_usb_dwc2_update_irq(level);
+ qemu_set_irq(s->irq, level);
+ }
+}
+
+/* flag interrupt condition */
+static inline void dwc2_raise_global_irq(DWC2State *s, uint32_t intr)
+{
+ if (!(s->gintsts & intr)) {
+ s->gintsts |= intr;
+ trace_usb_dwc2_raise_global_irq(intr);
+ dwc2_update_irq(s);
+ }
+}
+
+static inline void dwc2_lower_global_irq(DWC2State *s, uint32_t intr)
+{
+ if (s->gintsts & intr) {
+ s->gintsts &= ~intr;
+ trace_usb_dwc2_lower_global_irq(intr);
+ dwc2_update_irq(s);
+ }
+}
+
+static inline void dwc2_raise_host_irq(DWC2State *s, uint32_t host_intr)
+{
+ if (!(s->haint & host_intr)) {
+ s->haint |= host_intr;
+ s->haint &= 0xffff;
+ trace_usb_dwc2_raise_host_irq(host_intr);
+ if (s->haint & s->haintmsk) {
+ dwc2_raise_global_irq(s, GINTSTS_HCHINT);
+ }
+ }
+}
+
+static inline void dwc2_lower_host_irq(DWC2State *s, uint32_t host_intr)
+{
+ if (s->haint & host_intr) {
+ s->haint &= ~host_intr;
+ trace_usb_dwc2_lower_host_irq(host_intr);
+ if (!(s->haint & s->haintmsk)) {
+ dwc2_lower_global_irq(s, GINTSTS_HCHINT);
+ }
+ }
+}
+
+static inline void dwc2_update_hc_irq(DWC2State *s, int index)
+{
+ uint32_t host_intr = 1 << (index >> 3);
+
+ if (s->hreg1[index + 2] & s->hreg1[index + 3]) {
+ dwc2_raise_host_irq(s, host_intr);
+ } else {
+ dwc2_lower_host_irq(s, host_intr);
+ }
+}
+
+/* set a timer for EOF */
+static void dwc2_eof_timer(DWC2State *s)
+{
+ timer_mod(s->eof_timer, s->sof_time + s->usb_frame_time);
+}
+
+/* Set a timer for EOF and generate SOF event */
+static void dwc2_sof(DWC2State *s)
+{
+ s->sof_time += s->usb_frame_time;
+ trace_usb_dwc2_sof(s->sof_time);
+ dwc2_eof_timer(s);
+ dwc2_raise_global_irq(s, GINTSTS_SOF);
+}
+
+/* Do frame processing on frame boundary */
+static void dwc2_frame_boundary(void *opaque)
+{
+ DWC2State *s = opaque;
+ int64_t now;
+ uint16_t frcnt;
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ /* Frame boundary, so do EOF stuff here */
+
+ /* Increment frame number */
+ frcnt = (uint16_t)((now - s->sof_time) / s->fi);
+ s->frame_number = (s->frame_number + frcnt) & 0xffff;
+ s->hfnum = s->frame_number & HFNUM_MAX_FRNUM;
+
+ /* Do SOF stuff here */
+ dwc2_sof(s);
+}
+
+/* Start sending SOF tokens on the USB bus */
+static void dwc2_bus_start(DWC2State *s)
+{
+ trace_usb_dwc2_bus_start();
+ s->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ dwc2_eof_timer(s);
+}
+
+/* Stop sending SOF tokens on the USB bus */
+static void dwc2_bus_stop(DWC2State *s)
+{
+ trace_usb_dwc2_bus_stop();
+ timer_del(s->eof_timer);
+}
+
+static USBDevice *dwc2_find_device(DWC2State *s, uint8_t addr)
+{
+ USBDevice *dev;
+
+ trace_usb_dwc2_find_device(addr);
+
+ if (!(s->hprt0 & HPRT0_ENA)) {
+ trace_usb_dwc2_port_disabled(0);
+ } else {
+ dev = usb_find_device(&s->uport, addr);
+ if (dev != NULL) {
+ trace_usb_dwc2_device_found(0);
+ return dev;
+ }
+ }
+
+ trace_usb_dwc2_device_not_found();
+ return NULL;
+}
+
+static const char *pstatus[] = {
+ "USB_RET_SUCCESS", "USB_RET_NODEV", "USB_RET_NAK", "USB_RET_STALL",
+ "USB_RET_BABBLE", "USB_RET_IOERROR", "USB_RET_ASYNC",
+ "USB_RET_ADD_TO_QUEUE", "USB_RET_REMOVE_FROM_QUEUE"
+};
+
+static uint32_t pintr[] = {
+ HCINTMSK_XFERCOMPL, HCINTMSK_XACTERR, HCINTMSK_NAK, HCINTMSK_STALL,
+ HCINTMSK_BBLERR, HCINTMSK_XACTERR, HCINTMSK_XACTERR, HCINTMSK_XACTERR,
+ HCINTMSK_XACTERR
+};
+
+static const char *types[] = {
+ "Ctrl", "Isoc", "Bulk", "Intr"
+};
+
+static const char *dirs[] = {
+ "Out", "In"
+};
+
+static void dwc2_handle_packet(DWC2State *s, uint32_t devadr, USBDevice *dev,
+ USBEndpoint *ep, uint32_t index, bool send)
+{
+ DWC2Packet *p;
+ uint32_t hcchar = s->hreg1[index];
+ uint32_t hctsiz = s->hreg1[index + 4];
+ uint32_t hcdma = s->hreg1[index + 5];
+ uint32_t chan, epnum, epdir, eptype, mps, pid, pcnt, len, tlen, intr = 0;
+ uint32_t tpcnt, stsidx, actual = 0;
+ bool do_intr = false, done = false;
+
+ epnum = get_field(hcchar, HCCHAR_EPNUM);
+ epdir = get_bit(hcchar, HCCHAR_EPDIR);
+ eptype = get_field(hcchar, HCCHAR_EPTYPE);
+ mps = get_field(hcchar, HCCHAR_MPS);
+ pid = get_field(hctsiz, TSIZ_SC_MC_PID);
+ pcnt = get_field(hctsiz, TSIZ_PKTCNT);
+ len = get_field(hctsiz, TSIZ_XFERSIZE);
+ assert(len <= DWC2_MAX_XFER_SIZE);
+ chan = index >> 3;
+ p = &s->packet[chan];
+
+ trace_usb_dwc2_handle_packet(chan, dev, &p->packet, epnum, types[eptype],
+ dirs[epdir], mps, len, pcnt);
+
+ if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) {
+ pid = USB_TOKEN_SETUP;
+ } else {
+ pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT;
+ }
+
+ if (send) {
+ tlen = len;
+ if (p->small) {
+ if (tlen > mps) {
+ tlen = mps;
+ }
+ }
+
+ if (pid != USB_TOKEN_IN) {
+ trace_usb_dwc2_memory_read(hcdma, tlen);
+ if (dma_memory_read(&s->dma_as, hcdma,
+ s->usb_buf[chan], tlen) != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_read failed\n",
+ __func__);
+ }
+ }
+
+ usb_packet_init(&p->packet);
+ usb_packet_setup(&p->packet, pid, ep, 0, hcdma,
+ pid != USB_TOKEN_IN, true);
+ usb_packet_addbuf(&p->packet, s->usb_buf[chan], tlen);
+ p->async = DWC2_ASYNC_NONE;
+ usb_handle_packet(dev, &p->packet);
+ } else {
+ tlen = p->len;
+ }
+
+ stsidx = -p->packet.status;
+ assert(stsidx < sizeof(pstatus) / sizeof(*pstatus));
+ actual = p->packet.actual_length;
+ trace_usb_dwc2_packet_status(pstatus[stsidx], actual);
+
+babble:
+ if (p->packet.status != USB_RET_SUCCESS &&
+ p->packet.status != USB_RET_NAK &&
+ p->packet.status != USB_RET_STALL &&
+ p->packet.status != USB_RET_ASYNC) {
+ trace_usb_dwc2_packet_error(pstatus[stsidx]);
+ }
+
+ if (p->packet.status == USB_RET_ASYNC) {
+ trace_usb_dwc2_async_packet(&p->packet, chan, dev, epnum,
+ dirs[epdir], tlen);
+ usb_device_flush_ep_queue(dev, ep);
+ assert(p->async != DWC2_ASYNC_INFLIGHT);
+ p->devadr = devadr;
+ p->epnum = epnum;
+ p->epdir = epdir;
+ p->mps = mps;
+ p->pid = pid;
+ p->index = index;
+ p->pcnt = pcnt;
+ p->len = tlen;
+ p->async = DWC2_ASYNC_INFLIGHT;
+ p->needs_service = false;
+ return;
+ }
+
+ if (p->packet.status == USB_RET_SUCCESS) {
+ if (actual > tlen) {
+ p->packet.status = USB_RET_BABBLE;
+ goto babble;
+ }
+
+ if (pid == USB_TOKEN_IN) {
+ trace_usb_dwc2_memory_write(hcdma, actual);
+ if (dma_memory_write(&s->dma_as, hcdma, s->usb_buf[chan],
+ actual) != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_write failed\n",
+ __func__);
+ }
+ }
+
+ tpcnt = actual / mps;
+ if (actual % mps) {
+ tpcnt++;
+ if (pid == USB_TOKEN_IN) {
+ done = true;
+ }
+ }
+
+ pcnt -= tpcnt < pcnt ? tpcnt : pcnt;
+ set_field(&hctsiz, pcnt, TSIZ_PKTCNT);
+ len -= actual < len ? actual : len;
+ set_field(&hctsiz, len, TSIZ_XFERSIZE);
+ s->hreg1[index + 4] = hctsiz;
+ hcdma += actual;
+ s->hreg1[index + 5] = hcdma;
+
+ if (!pcnt || len == 0 || actual == 0) {
+ done = true;
+ }
+ } else {
+ intr |= pintr[stsidx];
+ if (p->packet.status == USB_RET_NAK &&
+ (eptype == USB_ENDPOINT_XFER_CONTROL ||
+ eptype == USB_ENDPOINT_XFER_BULK)) {
+ /*
+ * for ctrl/bulk, automatically retry on NAK,
+ * but send the interrupt anyway
+ */
+ intr &= ~HCINTMSK_RESERVED14_31;
+ s->hreg1[index + 2] |= intr;
+ do_intr = true;
+ } else {
+ intr |= HCINTMSK_CHHLTD;
+ done = true;
+ }
+ }
+
+ usb_packet_cleanup(&p->packet);
+
+ if (done) {
+ hcchar &= ~HCCHAR_CHENA;
+ s->hreg1[index] = hcchar;
+ if (!(intr & HCINTMSK_CHHLTD)) {
+ intr |= HCINTMSK_CHHLTD | HCINTMSK_XFERCOMPL;
+ }
+ intr &= ~HCINTMSK_RESERVED14_31;
+ s->hreg1[index + 2] |= intr;
+ p->needs_service = false;
+ trace_usb_dwc2_packet_done(pstatus[stsidx], actual, len, pcnt);
+ dwc2_update_hc_irq(s, index);
+ return;
+ }
+
+ p->devadr = devadr;
+ p->epnum = epnum;
+ p->epdir = epdir;
+ p->mps = mps;
+ p->pid = pid;
+ p->index = index;
+ p->pcnt = pcnt;
+ p->len = len;
+ p->needs_service = true;
+ trace_usb_dwc2_packet_next(pstatus[stsidx], len, pcnt);
+ if (do_intr) {
+ dwc2_update_hc_irq(s, index);
+ }
+}
+
+/* Attach or detach a device on root hub */
+
+static const char *speeds[] = {
+ "low", "full", "high"
+};
+
+static void dwc2_attach(USBPort *port)
+{
+ DWC2State *s = port->opaque;
+ int hispd = 0;
+
+ trace_usb_dwc2_attach(port);
+ assert(port->index == 0);
+
+ if (!port->dev || !port->dev->attached) {
+ return;
+ }
+
+ assert(port->dev->speed <= USB_SPEED_HIGH);
+ trace_usb_dwc2_attach_speed(speeds[port->dev->speed]);
+ s->hprt0 &= ~HPRT0_SPD_MASK;
+
+ switch (port->dev->speed) {
+ case USB_SPEED_LOW:
+ s->hprt0 |= HPRT0_SPD_LOW_SPEED << HPRT0_SPD_SHIFT;
+ break;
+ case USB_SPEED_FULL:
+ s->hprt0 |= HPRT0_SPD_FULL_SPEED << HPRT0_SPD_SHIFT;
+ break;
+ case USB_SPEED_HIGH:
+ s->hprt0 |= HPRT0_SPD_HIGH_SPEED << HPRT0_SPD_SHIFT;
+ hispd = 1;
+ break;
+ }
+
+ if (hispd) {
+ s->usb_frame_time = NANOSECONDS_PER_SECOND / 8000; /* 125000 */
+ if (NANOSECONDS_PER_SECOND >= USB_HZ_HS) {
+ s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_HS; /* 10.4 */
+ } else {
+ s->usb_bit_time = 1;
+ }
+ } else {
+ s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000; /* 1000000 */
+ if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) {
+ s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */
+ } else {
+ s->usb_bit_time = 1;
+ }
+ }
+
+ s->fi = USB_FRMINTVL - 1;
+ s->hprt0 |= HPRT0_CONNDET | HPRT0_CONNSTS;
+
+ dwc2_bus_start(s);
+ dwc2_raise_global_irq(s, GINTSTS_PRTINT);
+}
+
+static void dwc2_detach(USBPort *port)
+{
+ DWC2State *s = port->opaque;
+
+ trace_usb_dwc2_detach(port);
+ assert(port->index == 0);
+
+ dwc2_bus_stop(s);
+
+ s->hprt0 &= ~(HPRT0_SPD_MASK | HPRT0_SUSP | HPRT0_ENA | HPRT0_CONNSTS);
+ s->hprt0 |= HPRT0_CONNDET | HPRT0_ENACHG;
+
+ dwc2_raise_global_irq(s, GINTSTS_PRTINT);
+}
+
+static void dwc2_child_detach(USBPort *port, USBDevice *child)
+{
+ trace_usb_dwc2_child_detach(port, child);
+ assert(port->index == 0);
+}
+
+static void dwc2_wakeup(USBPort *port)
+{
+ DWC2State *s = port->opaque;
+
+ trace_usb_dwc2_wakeup(port);
+ assert(port->index == 0);
+
+ if (s->hprt0 & HPRT0_SUSP) {
+ s->hprt0 |= HPRT0_RES;
+ dwc2_raise_global_irq(s, GINTSTS_PRTINT);
+ }
+
+ qemu_bh_schedule(s->async_bh);
+}
+
+static void dwc2_async_packet_complete(USBPort *port, USBPacket *packet)
+{
+ DWC2State *s = port->opaque;
+ DWC2Packet *p;
+ USBDevice *dev;
+ USBEndpoint *ep;
+
+ assert(port->index == 0);
+ p = container_of(packet, DWC2Packet, packet);
+ dev = dwc2_find_device(s, p->devadr);
+ ep = usb_ep_get(dev, p->pid, p->epnum);
+ trace_usb_dwc2_async_packet_complete(port, packet, p->index >> 3, dev,
+ p->epnum, dirs[p->epdir], p->len);
+ assert(p->async == DWC2_ASYNC_INFLIGHT);
+
+ if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
+ usb_cancel_packet(packet);
+ usb_packet_cleanup(packet);
+ return;
+ }
+
+ dwc2_handle_packet(s, p->devadr, dev, ep, p->index, false);
+
+ p->async = DWC2_ASYNC_FINISHED;
+ qemu_bh_schedule(s->async_bh);
+}
+
+static USBPortOps dwc2_port_ops = {
+ .attach = dwc2_attach,
+ .detach = dwc2_detach,
+ .child_detach = dwc2_child_detach,
+ .wakeup = dwc2_wakeup,
+ .complete = dwc2_async_packet_complete,
+};
+
+static uint32_t dwc2_get_frame_remaining(DWC2State *s)
+{
+ uint32_t fr = 0;
+ int64_t tks;
+
+ tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->sof_time;
+ if (tks < 0) {
+ tks = 0;
+ }
+
+ /* avoid muldiv if possible */
+ if (tks >= s->usb_frame_time) {
+ goto out;
+ }
+ if (tks < s->usb_bit_time) {
+ fr = s->fi;
+ goto out;
+ }
+
+ /* tks = number of ns since SOF, divided by 83 (fs) or 10 (hs) */
+ tks = tks / s->usb_bit_time;
+ if (tks >= (int64_t)s->fi) {
+ goto out;
+ }
+
+ /* remaining = frame interval minus tks */
+ fr = (uint32_t)((int64_t)s->fi - tks);
+
+out:
+ return fr;
+}
+
+static void dwc2_work_bh(void *opaque)
+{
+ DWC2State *s = opaque;
+ DWC2Packet *p;
+ USBDevice *dev;
+ USBEndpoint *ep;
+ int64_t t_now, expire_time;
+ int chan;
+ bool found = false;
+
+ trace_usb_dwc2_work_bh();
+ if (s->working) {
+ return;
+ }
+ s->working = true;
+
+ t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ chan = s->next_chan;
+
+ do {
+ p = &s->packet[chan];
+ if (p->needs_service) {
+ dev = dwc2_find_device(s, p->devadr);
+ ep = usb_ep_get(dev, p->pid, p->epnum);
+ trace_usb_dwc2_work_bh_service(s->next_chan, chan, dev, p->epnum);
+ dwc2_handle_packet(s, p->devadr, dev, ep, p->index, true);
+ found = true;
+ }
+ if (++chan == DWC2_NB_CHAN) {
+ chan = 0;
+ }
+ if (found) {
+ s->next_chan = chan;
+ trace_usb_dwc2_work_bh_next(chan);
+ }
+ } while (chan != s->next_chan);
+
+ if (found) {
+ expire_time = t_now + NANOSECONDS_PER_SECOND / 4000;
+ timer_mod(s->frame_timer, expire_time);
+ }
+ s->working = false;
+}
+
+static void dwc2_enable_chan(DWC2State *s, uint32_t index)
+{
+ USBDevice *dev;
+ USBEndpoint *ep;
+ uint32_t hcchar;
+ uint32_t hctsiz;
+ uint32_t devadr, epnum, epdir, eptype, pid, len;
+ DWC2Packet *p;
+
+ assert((index >> 3) < DWC2_NB_CHAN);
+ p = &s->packet[index >> 3];
+ hcchar = s->hreg1[index];
+ hctsiz = s->hreg1[index + 4];
+ devadr = get_field(hcchar, HCCHAR_DEVADDR);
+ epnum = get_field(hcchar, HCCHAR_EPNUM);
+ epdir = get_bit(hcchar, HCCHAR_EPDIR);
+ eptype = get_field(hcchar, HCCHAR_EPTYPE);
+ pid = get_field(hctsiz, TSIZ_SC_MC_PID);
+ len = get_field(hctsiz, TSIZ_XFERSIZE);
+
+ dev = dwc2_find_device(s, devadr);
+
+ trace_usb_dwc2_enable_chan(index >> 3, dev, &p->packet, epnum);
+ if (dev == NULL) {
+ return;
+ }
+
+ if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) {
+ pid = USB_TOKEN_SETUP;
+ } else {
+ pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT;
+ }
+
+ ep = usb_ep_get(dev, pid, epnum);
+
+ /*
+ * Hack: Networking doesn't like us delivering large transfers, it kind
+ * of works but the latency is horrible. So if the transfer is <= the mtu
+ * size, we take that as a hint that this might be a network transfer,
+ * and do the transfer packet-by-packet.
+ */
+ if (len > 1536) {
+ p->small = false;
+ } else {
+ p->small = true;
+ }
+
+ dwc2_handle_packet(s, devadr, dev, ep, index, true);
+ qemu_bh_schedule(s->async_bh);
+}
+
+static const char *glbregnm[] = {
+ "GOTGCTL ", "GOTGINT ", "GAHBCFG ", "GUSBCFG ", "GRSTCTL ",
+ "GINTSTS ", "GINTMSK ", "GRXSTSR ", "GRXSTSP ", "GRXFSIZ ",
+ "GNPTXFSIZ", "GNPTXSTS ", "GI2CCTL ", "GPVNDCTL ", "GGPIO ",
+ "GUID ", "GSNPSID ", "GHWCFG1 ", "GHWCFG2 ", "GHWCFG3 ",
+ "GHWCFG4 ", "GLPMCFG ", "GPWRDN ", "GDFIFOCFG", "GADPCTL ",
+ "GREFCLK ", "GINTMSK2 ", "GINTSTS2 "
+};
+
+static uint64_t dwc2_glbreg_read(void *ptr, hwaddr addr, int index,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ uint32_t val;
+
+ assert(addr <= GINTSTS2);
+ val = s->glbreg[index];
+
+ switch (addr) {
+ case GRSTCTL:
+ /* clear any self-clearing bits that were set */
+ val &= ~(GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH | GRSTCTL_IN_TKNQ_FLSH |
+ GRSTCTL_FRMCNTRRST | GRSTCTL_HSFTRST | GRSTCTL_CSFTRST);
+ s->glbreg[index] = val;
+ break;
+ default:
+ break;
+ }
+
+ trace_usb_dwc2_glbreg_read(addr, glbregnm[index], val);
+ return val;
+}
+
+static void dwc2_glbreg_write(void *ptr, hwaddr addr, int index, uint64_t val,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ uint64_t orig = val;
+ uint32_t *mmio;
+ uint32_t old;
+ int iflg = 0;
+
+ assert(addr <= GINTSTS2);
+ mmio = &s->glbreg[index];
+ old = *mmio;
+
+ switch (addr) {
+ case GOTGCTL:
+ /* don't allow setting of read-only bits */
+ val &= ~(GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD |
+ GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B |
+ GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS);
+ /* don't allow clearing of read-only bits */
+ val |= old & (GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD |
+ GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B |
+ GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS);
+ break;
+ case GAHBCFG:
+ if ((val & GAHBCFG_GLBL_INTR_EN) && !(old & GAHBCFG_GLBL_INTR_EN)) {
+ iflg = 1;
+ }
+ break;
+ case GRSTCTL:
+ val |= GRSTCTL_AHBIDLE;
+ val &= ~GRSTCTL_DMAREQ;
+ if (!(old & GRSTCTL_TXFFLSH) && (val & GRSTCTL_TXFFLSH)) {
+ /* TODO - TX fifo flush */
+ qemu_log_mask(LOG_UNIMP, "Tx FIFO flush not implemented\n");
+ }
+ if (!(old & GRSTCTL_RXFFLSH) && (val & GRSTCTL_RXFFLSH)) {
+ /* TODO - RX fifo flush */
+ qemu_log_mask(LOG_UNIMP, "Rx FIFO flush not implemented\n");
+ }
+ if (!(old & GRSTCTL_IN_TKNQ_FLSH) && (val & GRSTCTL_IN_TKNQ_FLSH)) {
+ /* TODO - device IN token queue flush */
+ qemu_log_mask(LOG_UNIMP, "Token queue flush not implemented\n");
+ }
+ if (!(old & GRSTCTL_FRMCNTRRST) && (val & GRSTCTL_FRMCNTRRST)) {
+ /* TODO - host frame counter reset */
+ qemu_log_mask(LOG_UNIMP, "Frame counter reset not implemented\n");
+ }
+ if (!(old & GRSTCTL_HSFTRST) && (val & GRSTCTL_HSFTRST)) {
+ /* TODO - host soft reset */
+ qemu_log_mask(LOG_UNIMP, "Host soft reset not implemented\n");
+ }
+ if (!(old & GRSTCTL_CSFTRST) && (val & GRSTCTL_CSFTRST)) {
+ /* TODO - core soft reset */
+ qemu_log_mask(LOG_UNIMP, "Core soft reset not implemented\n");
+ }
+ /* don't allow clearing of self-clearing bits */
+ val |= old & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH |
+ GRSTCTL_IN_TKNQ_FLSH | GRSTCTL_FRMCNTRRST |
+ GRSTCTL_HSFTRST | GRSTCTL_CSFTRST);
+ break;
+ case GINTSTS:
+ /* clear the write-1-to-clear bits */
+ val |= ~old;
+ val = ~val;
+ /* don't allow clearing of read-only bits */
+ val |= old & (GINTSTS_PTXFEMP | GINTSTS_HCHINT | GINTSTS_PRTINT |
+ GINTSTS_OEPINT | GINTSTS_IEPINT | GINTSTS_GOUTNAKEFF |
+ GINTSTS_GINNAKEFF | GINTSTS_NPTXFEMP | GINTSTS_RXFLVL |
+ GINTSTS_OTGINT | GINTSTS_CURMODE_HOST);
+ iflg = 1;
+ break;
+ case GINTMSK:
+ iflg = 1;
+ break;
+ default:
+ break;
+ }
+
+ trace_usb_dwc2_glbreg_write(addr, glbregnm[index], orig, old, val);
+ *mmio = val;
+
+ if (iflg) {
+ dwc2_update_irq(s);
+ }
+}
+
+static uint64_t dwc2_fszreg_read(void *ptr, hwaddr addr, int index,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ uint32_t val;
+
+ assert(addr == HPTXFSIZ);
+ val = s->fszreg[index];
+
+ trace_usb_dwc2_fszreg_read(addr, val);
+ return val;
+}
+
+static void dwc2_fszreg_write(void *ptr, hwaddr addr, int index, uint64_t val,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ uint64_t orig = val;
+ uint32_t *mmio;
+ uint32_t old;
+
+ assert(addr == HPTXFSIZ);
+ mmio = &s->fszreg[index];
+ old = *mmio;
+
+ trace_usb_dwc2_fszreg_write(addr, orig, old, val);
+ *mmio = val;
+}
+
+static const char *hreg0nm[] = {
+ "HCFG ", "HFIR ", "HFNUM ", "<rsvd> ", "HPTXSTS ",
+ "HAINT ", "HAINTMSK ", "HFLBADDR ", "<rsvd> ", "<rsvd> ",
+ "<rsvd> ", "<rsvd> ", "<rsvd> ", "<rsvd> ", "<rsvd> ",
+ "<rsvd> ", "HPRT0 "
+};
+
+static uint64_t dwc2_hreg0_read(void *ptr, hwaddr addr, int index,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ uint32_t val;
+
+ assert(addr >= HCFG && addr <= HPRT0);
+ val = s->hreg0[index];
+
+ switch (addr) {
+ case HFNUM:
+ val = (dwc2_get_frame_remaining(s) << HFNUM_FRREM_SHIFT) |
+ (s->hfnum << HFNUM_FRNUM_SHIFT);
+ break;
+ default:
+ break;
+ }
+
+ trace_usb_dwc2_hreg0_read(addr, hreg0nm[index], val);
+ return val;
+}
+
+static void dwc2_hreg0_write(void *ptr, hwaddr addr, int index, uint64_t val,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ USBDevice *dev = s->uport.dev;
+ uint64_t orig = val;
+ uint32_t *mmio;
+ uint32_t tval, told, old;
+ int prst = 0;
+ int iflg = 0;
+
+ assert(addr >= HCFG && addr <= HPRT0);
+ mmio = &s->hreg0[index];
+ old = *mmio;
+
+ switch (addr) {
+ case HFIR:
+ break;
+ case HFNUM:
+ case HPTXSTS:
+ case HAINT:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n",
+ __func__);
+ return;
+ case HAINTMSK:
+ val &= 0xffff;
+ break;
+ case HPRT0:
+ /* don't allow clearing of read-only bits */
+ val |= old & (HPRT0_SPD_MASK | HPRT0_LNSTS_MASK | HPRT0_OVRCURRACT |
+ HPRT0_CONNSTS);
+ /* don't allow clearing of self-clearing bits */
+ val |= old & (HPRT0_SUSP | HPRT0_RES);
+ /* don't allow setting of self-setting bits */
+ if (!(old & HPRT0_ENA) && (val & HPRT0_ENA)) {
+ val &= ~HPRT0_ENA;
+ }
+ /* clear the write-1-to-clear bits */
+ tval = val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
+ HPRT0_CONNDET);
+ told = old & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
+ HPRT0_CONNDET);
+ tval |= ~told;
+ tval = ~tval;
+ tval &= (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
+ HPRT0_CONNDET);
+ val &= ~(HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
+ HPRT0_CONNDET);
+ val |= tval;
+ if (!(val & HPRT0_RST) && (old & HPRT0_RST)) {
+ if (dev && dev->attached) {
+ val |= HPRT0_ENA | HPRT0_ENACHG;
+ prst = 1;
+ }
+ }
+ if (val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_CONNDET)) {
+ iflg = 1;
+ } else {
+ iflg = -1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (prst) {
+ trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old,
+ val & ~HPRT0_CONNDET);
+ trace_usb_dwc2_hreg0_action("call usb_port_reset");
+ usb_port_reset(&s->uport);
+ val &= ~HPRT0_CONNDET;
+ } else {
+ trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old, val);
+ }
+
+ *mmio = val;
+
+ if (iflg > 0) {
+ trace_usb_dwc2_hreg0_action("enable PRTINT");
+ dwc2_raise_global_irq(s, GINTSTS_PRTINT);
+ } else if (iflg < 0) {
+ trace_usb_dwc2_hreg0_action("disable PRTINT");
+ dwc2_lower_global_irq(s, GINTSTS_PRTINT);
+ }
+}
+
+static const char *hreg1nm[] = {
+ "HCCHAR ", "HCSPLT ", "HCINT ", "HCINTMSK", "HCTSIZ ", "HCDMA ",
+ "<rsvd> ", "HCDMAB "
+};
+
+static uint64_t dwc2_hreg1_read(void *ptr, hwaddr addr, int index,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ uint32_t val;
+
+ assert(addr >= HCCHAR(0) && addr <= HCDMAB(DWC2_NB_CHAN - 1));
+ val = s->hreg1[index];
+
+ trace_usb_dwc2_hreg1_read(addr, hreg1nm[index & 7], addr >> 5, val);
+ return val;
+}
+
+static void dwc2_hreg1_write(void *ptr, hwaddr addr, int index, uint64_t val,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ uint64_t orig = val;
+ uint32_t *mmio;
+ uint32_t old;
+ int iflg = 0;
+ int enflg = 0;
+ int disflg = 0;
+
+ assert(addr >= HCCHAR(0) && addr <= HCDMAB(DWC2_NB_CHAN - 1));
+ mmio = &s->hreg1[index];
+ old = *mmio;
+
+ switch (HSOTG_REG(0x500) + (addr & 0x1c)) {
+ case HCCHAR(0):
+ if ((val & HCCHAR_CHDIS) && !(old & HCCHAR_CHDIS)) {
+ val &= ~(HCCHAR_CHENA | HCCHAR_CHDIS);
+ disflg = 1;
+ } else {
+ val |= old & HCCHAR_CHDIS;
+ if ((val & HCCHAR_CHENA) && !(old & HCCHAR_CHENA)) {
+ val &= ~HCCHAR_CHDIS;
+ enflg = 1;
+ } else {
+ val |= old & HCCHAR_CHENA;
+ }
+ }
+ break;
+ case HCINT(0):
+ /* clear the write-1-to-clear bits */
+ val |= ~old;
+ val = ~val;
+ val &= ~HCINTMSK_RESERVED14_31;
+ iflg = 1;
+ break;
+ case HCINTMSK(0):
+ val &= ~HCINTMSK_RESERVED14_31;
+ iflg = 1;
+ break;
+ case HCDMAB(0):
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n",
+ __func__);
+ return;
+ default:
+ break;
+ }
+
+ trace_usb_dwc2_hreg1_write(addr, hreg1nm[index & 7], index >> 3, orig,
+ old, val);
+ *mmio = val;
+
+ if (disflg) {
+ /* set ChHltd in HCINT */
+ s->hreg1[(index & ~7) + 2] |= HCINTMSK_CHHLTD;
+ iflg = 1;
+ }
+
+ if (enflg) {
+ dwc2_enable_chan(s, index & ~7);
+ }
+
+ if (iflg) {
+ dwc2_update_hc_irq(s, index & ~7);
+ }
+}
+
+static const char *pcgregnm[] = {
+ "PCGCTL ", "PCGCCTL1 "
+};
+
+static uint64_t dwc2_pcgreg_read(void *ptr, hwaddr addr, int index,
+ unsigned size)
+{
+ DWC2State *s = ptr;
+ uint32_t val;
+
+ assert(addr >= PCGCTL && addr <= PCGCCTL1);
+ val = s->pcgreg[index];
+
+ trace_usb_dwc2_pcgreg_read(addr, pcgregnm[index], val);
+ return val;
+}
+
+static void dwc2_pcgreg_write(void *ptr, hwaddr addr, int index,
+ uint64_t val, unsigned size)
+{
+ DWC2State *s = ptr;
+ uint64_t orig = val;
+ uint32_t *mmio;
+ uint32_t old;
+
+ assert(addr >= PCGCTL && addr <= PCGCCTL1);
+ mmio = &s->pcgreg[index];
+ old = *mmio;
+
+ trace_usb_dwc2_pcgreg_write(addr, pcgregnm[index], orig, old, val);
+ *mmio = val;
+}
+
+static uint64_t dwc2_hsotg_read(void *ptr, hwaddr addr, unsigned size)
+{
+ uint64_t val;
+
+ switch (addr) {
+ case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):
+ val = dwc2_glbreg_read(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, size);
+ break;
+ case HSOTG_REG(0x100):
+ val = dwc2_fszreg_read(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, size);
+ break;
+ case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc):
+ /* Gadget-mode registers, just return 0 for now */
+ val = 0;
+ break;
+ case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc):
+ val = dwc2_hreg0_read(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, size);
+ break;
+ case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc):
+ val = dwc2_hreg1_read(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, size);
+ break;
+ case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc):
+ /* Gadget-mode registers, just return 0 for now */
+ val = 0;
+ break;
+ case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc):
+ val = dwc2_pcgreg_read(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, size);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return val;
+}
+
+static void dwc2_hsotg_write(void *ptr, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ switch (addr) {
+ case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):
+ dwc2_glbreg_write(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, val, size);
+ break;
+ case HSOTG_REG(0x100):
+ dwc2_fszreg_write(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, val, size);
+ break;
+ case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc):
+ /* Gadget-mode registers, do nothing for now */
+ break;
+ case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc):
+ dwc2_hreg0_write(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, val, size);
+ break;
+ case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc):
+ dwc2_hreg1_write(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, val, size);
+ break;
+ case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc):
+ /* Gadget-mode registers, do nothing for now */
+ break;
+ case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc):
+ dwc2_pcgreg_write(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, val, size);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static const MemoryRegionOps dwc2_mmio_hsotg_ops = {
+ .read = dwc2_hsotg_read,
+ .write = dwc2_hsotg_write,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t dwc2_hreg2_read(void *ptr, hwaddr addr, unsigned size)
+{
+ /* TODO - implement FIFOs to support slave mode */
+ trace_usb_dwc2_hreg2_read(addr, addr >> 12, 0);
+ qemu_log_mask(LOG_UNIMP, "FIFO read not implemented\n");
+ return 0;
+}
+
+static void dwc2_hreg2_write(void *ptr, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ uint64_t orig = val;
+
+ /* TODO - implement FIFOs to support slave mode */
+ trace_usb_dwc2_hreg2_write(addr, addr >> 12, orig, 0, val);
+ qemu_log_mask(LOG_UNIMP, "FIFO write not implemented\n");
+}
+
+static const MemoryRegionOps dwc2_mmio_hreg2_ops = {
+ .read = dwc2_hreg2_read,
+ .write = dwc2_hreg2_write,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void dwc2_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
+ unsigned int stream)
+{
+ DWC2State *s = container_of(bus, DWC2State, bus);
+
+ trace_usb_dwc2_wakeup_endpoint(ep, stream);
+
+ /* TODO - do something here? */
+ qemu_bh_schedule(s->async_bh);
+}
+
+static USBBusOps dwc2_bus_ops = {
+ .wakeup_endpoint = dwc2_wakeup_endpoint,
+};
+
+static void dwc2_work_timer(void *opaque)
+{
+ DWC2State *s = opaque;
+
+ trace_usb_dwc2_work_timer();
+ qemu_bh_schedule(s->async_bh);
+}
+
+static void dwc2_reset_enter(Object *obj, ResetType type)
+{
+ DWC2Class *c = DWC2_GET_CLASS(obj);
+ DWC2State *s = DWC2_USB(obj);
+ int i;
+
+ trace_usb_dwc2_reset_enter();
+
+ if (c->parent_phases.enter) {
+ c->parent_phases.enter(obj, type);
+ }
+
+ timer_del(s->frame_timer);
+ qemu_bh_cancel(s->async_bh);
+
+ if (s->uport.dev && s->uport.dev->attached) {
+ usb_detach(&s->uport);
+ }
+
+ dwc2_bus_stop(s);
+
+ s->gotgctl = GOTGCTL_BSESVLD | GOTGCTL_ASESVLD | GOTGCTL_CONID_B;
+ s->gotgint = 0;
+ s->gahbcfg = 0;
+ s->gusbcfg = 5 << GUSBCFG_USBTRDTIM_SHIFT;
+ s->grstctl = GRSTCTL_AHBIDLE;
+ s->gintsts = GINTSTS_CONIDSTSCHNG | GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP |
+ GINTSTS_CURMODE_HOST;
+ s->gintmsk = 0;
+ s->grxstsr = 0;
+ s->grxstsp = 0;
+ s->grxfsiz = 1024;
+ s->gnptxfsiz = 1024 << FIFOSIZE_DEPTH_SHIFT;
+ s->gnptxsts = (4 << FIFOSIZE_DEPTH_SHIFT) | 1024;
+ s->gi2cctl = GI2CCTL_I2CDATSE0 | GI2CCTL_ACK;
+ s->gpvndctl = 0;
+ s->ggpio = 0;
+ s->guid = 0;
+ s->gsnpsid = 0x4f54294a;
+ s->ghwcfg1 = 0;
+ s->ghwcfg2 = (8 << GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT) |
+ (4 << GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT) |
+ (4 << GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT) |
+ GHWCFG2_DYNAMIC_FIFO |
+ GHWCFG2_PERIO_EP_SUPPORTED |
+ ((DWC2_NB_CHAN - 1) << GHWCFG2_NUM_HOST_CHAN_SHIFT) |
+ (GHWCFG2_INT_DMA_ARCH << GHWCFG2_ARCHITECTURE_SHIFT) |
+ (GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST << GHWCFG2_OP_MODE_SHIFT);
+ s->ghwcfg3 = (4096 << GHWCFG3_DFIFO_DEPTH_SHIFT) |
+ (4 << GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT) |
+ (4 << GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT);
+ s->ghwcfg4 = 0;
+ s->glpmcfg = 0;
+ s->gpwrdn = GPWRDN_PWRDNRSTN;
+ s->gdfifocfg = 0;
+ s->gadpctl = 0;
+ s->grefclk = 0;
+ s->gintmsk2 = 0;
+ s->gintsts2 = 0;
+
+ s->hptxfsiz = 500 << FIFOSIZE_DEPTH_SHIFT;
+
+ s->hcfg = 2 << HCFG_RESVALID_SHIFT;
+ s->hfir = 60000;
+ s->hfnum = 0x3fff;
+ s->hptxsts = (16 << TXSTS_QSPCAVAIL_SHIFT) | 32768;
+ s->haint = 0;
+ s->haintmsk = 0;
+ s->hprt0 = 0;
+
+ memset(s->hreg1, 0, sizeof(s->hreg1));
+ memset(s->pcgreg, 0, sizeof(s->pcgreg));
+
+ s->sof_time = 0;
+ s->frame_number = 0;
+ s->fi = USB_FRMINTVL - 1;
+ s->next_chan = 0;
+ s->working = false;
+
+ for (i = 0; i < DWC2_NB_CHAN; i++) {
+ s->packet[i].needs_service = false;
+ }
+}
+
+static void dwc2_reset_hold(Object *obj)
+{
+ DWC2Class *c = DWC2_GET_CLASS(obj);
+ DWC2State *s = DWC2_USB(obj);
+
+ trace_usb_dwc2_reset_hold();
+
+ if (c->parent_phases.hold) {
+ c->parent_phases.hold(obj);
+ }
+
+ dwc2_update_irq(s);
+}
+
+static void dwc2_reset_exit(Object *obj)
+{
+ DWC2Class *c = DWC2_GET_CLASS(obj);
+ DWC2State *s = DWC2_USB(obj);
+
+ trace_usb_dwc2_reset_exit();
+
+ if (c->parent_phases.exit) {
+ c->parent_phases.exit(obj);
+ }
+
+ s->hprt0 = HPRT0_PWR;
+ if (s->uport.dev && s->uport.dev->attached) {
+ usb_attach(&s->uport);
+ usb_device_reset(s->uport.dev);
+ }
+}
+
+static void dwc2_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ DWC2State *s = DWC2_USB(dev);
+ Object *obj;
+ Error *err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
+ if (err) {
+ error_setg(errp, "dwc2: required dma-mr link not found: %s",
+ error_get_pretty(err));
+ return;
+ }
+ assert(obj != NULL);
+
+ s->dma_mr = MEMORY_REGION(obj);
+ address_space_init(&s->dma_as, s->dma_mr, "dwc2");
+
+ usb_bus_new(&s->bus, sizeof(s->bus), &dwc2_bus_ops, dev);
+ usb_register_port(&s->bus, &s->uport, s, 0, &dwc2_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
+ (s->usb_version == 2 ? USB_SPEED_MASK_HIGH : 0));
+ s->uport.dev = 0;
+
+ s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000; /* 1000000 */
+ if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) {
+ s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */
+ } else {
+ s->usb_bit_time = 1;
+ }
+
+ s->fi = USB_FRMINTVL - 1;
+ s->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_frame_boundary, s);
+ s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_work_timer, s);
+ s->async_bh = qemu_bh_new(dwc2_work_bh, s);
+
+ sysbus_init_irq(sbd, &s->irq);
+}
+
+static void dwc2_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ DWC2State *s = DWC2_USB(obj);
+
+ memory_region_init(&s->container, obj, "dwc2", DWC2_MMIO_SIZE);
+ sysbus_init_mmio(sbd, &s->container);
+
+ memory_region_init_io(&s->hsotg, obj, &dwc2_mmio_hsotg_ops, s,
+ "dwc2-io", 4 * KiB);
+ memory_region_add_subregion(&s->container, 0x0000, &s->hsotg);
+
+ memory_region_init_io(&s->fifos, obj, &dwc2_mmio_hreg2_ops, s,
+ "dwc2-fifo", 64 * KiB);
+ memory_region_add_subregion(&s->container, 0x1000, &s->fifos);
+}
+
+static const VMStateDescription vmstate_dwc2_state_packet = {
+ .name = "dwc2/packet",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(devadr, DWC2Packet),
+ VMSTATE_UINT32(epnum, DWC2Packet),
+ VMSTATE_UINT32(epdir, DWC2Packet),
+ VMSTATE_UINT32(mps, DWC2Packet),
+ VMSTATE_UINT32(pid, DWC2Packet),
+ VMSTATE_UINT32(index, DWC2Packet),
+ VMSTATE_UINT32(pcnt, DWC2Packet),
+ VMSTATE_UINT32(len, DWC2Packet),
+ VMSTATE_INT32(async, DWC2Packet),
+ VMSTATE_BOOL(small, DWC2Packet),
+ VMSTATE_BOOL(needs_service, DWC2Packet),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+const VMStateDescription vmstate_dwc2_state = {
+ .name = "dwc2",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(glbreg, DWC2State,
+ DWC2_GLBREG_SIZE / sizeof(uint32_t)),
+ VMSTATE_UINT32_ARRAY(fszreg, DWC2State,
+ DWC2_FSZREG_SIZE / sizeof(uint32_t)),
+ VMSTATE_UINT32_ARRAY(hreg0, DWC2State,
+ DWC2_HREG0_SIZE / sizeof(uint32_t)),
+ VMSTATE_UINT32_ARRAY(hreg1, DWC2State,
+ DWC2_HREG1_SIZE / sizeof(uint32_t)),
+ VMSTATE_UINT32_ARRAY(pcgreg, DWC2State,
+ DWC2_PCGREG_SIZE / sizeof(uint32_t)),
+
+ VMSTATE_TIMER_PTR(eof_timer, DWC2State),
+ VMSTATE_TIMER_PTR(frame_timer, DWC2State),
+ VMSTATE_INT64(sof_time, DWC2State),
+ VMSTATE_INT64(usb_frame_time, DWC2State),
+ VMSTATE_INT64(usb_bit_time, DWC2State),
+ VMSTATE_UINT32(usb_version, DWC2State),
+ VMSTATE_UINT16(frame_number, DWC2State),
+ VMSTATE_UINT16(fi, DWC2State),
+ VMSTATE_UINT16(next_chan, DWC2State),
+ VMSTATE_BOOL(working, DWC2State),
+
+ VMSTATE_STRUCT_ARRAY(packet, DWC2State, DWC2_NB_CHAN, 1,
+ vmstate_dwc2_state_packet, DWC2Packet),
+ VMSTATE_UINT8_2DARRAY(usb_buf, DWC2State, DWC2_NB_CHAN,
+ DWC2_MAX_XFER_SIZE),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property dwc2_usb_properties[] = {
+ DEFINE_PROP_UINT32("usb_version", DWC2State, usb_version, 2),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void dwc2_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ DWC2Class *c = DWC2_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = dwc2_realize;
+ dc->vmsd = &vmstate_dwc2_state;
+ set_bit(DEVICE_CATEGORY_USB, dc->categories);
+ device_class_set_props(dc, dwc2_usb_properties);
+ resettable_class_set_parent_phases(rc, dwc2_reset_enter, dwc2_reset_hold,
+ dwc2_reset_exit, &c->parent_phases);
+}
+
+static const TypeInfo dwc2_usb_type_info = {
+ .name = TYPE_DWC2_USB,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(DWC2State),
+ .instance_init = dwc2_init,
+ .class_size = sizeof(DWC2Class),
+ .class_init = dwc2_class_init,
+};
+
+static void dwc2_usb_register_types(void)
+{
+ type_register_static(&dwc2_usb_type_info);
+}
+
+type_init(dwc2_usb_register_types)
diff --git a/hw/usb/hcd-dwc2.h b/hw/usb/hcd-dwc2.h
new file mode 100644
index 0000000000..4ba809a07b
--- /dev/null
+++ b/hw/usb/hcd-dwc2.h
@@ -0,0 +1,190 @@
+/*
+ * dwc-hsotg (dwc2) USB host controller state definitions
+ *
+ * Based on hw/usb/hcd-ehci.h
+ *
+ * Copyright (c) 2020 Paul Zimmerman <pauldzim@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef HW_USB_DWC2_H
+#define HW_USB_DWC2_H
+
+#include "qemu/timer.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "hw/usb.h"
+#include "sysemu/dma.h"
+
+#define DWC2_MMIO_SIZE 0x11000
+
+#define DWC2_NB_CHAN 8 /* Number of host channels */
+#define DWC2_MAX_XFER_SIZE 65536 /* Max transfer size expected in HCTSIZ */
+
+typedef struct DWC2Packet DWC2Packet;
+typedef struct DWC2State DWC2State;
+typedef struct DWC2Class DWC2Class;
+
+enum async_state {
+ DWC2_ASYNC_NONE = 0,
+ DWC2_ASYNC_INITIALIZED,
+ DWC2_ASYNC_INFLIGHT,
+ DWC2_ASYNC_FINISHED,
+};
+
+struct DWC2Packet {
+ USBPacket packet;
+ uint32_t devadr;
+ uint32_t epnum;
+ uint32_t epdir;
+ uint32_t mps;
+ uint32_t pid;
+ uint32_t index;
+ uint32_t pcnt;
+ uint32_t len;
+ int32_t async;
+ bool small;
+ bool needs_service;
+};
+
+struct DWC2State {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ USBBus bus;
+ qemu_irq irq;
+ MemoryRegion *dma_mr;
+ AddressSpace dma_as;
+ MemoryRegion container;
+ MemoryRegion hsotg;
+ MemoryRegion fifos;
+
+ union {
+#define DWC2_GLBREG_SIZE 0x70
+ uint32_t glbreg[DWC2_GLBREG_SIZE / sizeof(uint32_t)];
+ struct {
+ uint32_t gotgctl; /* 00 */
+ uint32_t gotgint; /* 04 */
+ uint32_t gahbcfg; /* 08 */
+ uint32_t gusbcfg; /* 0c */
+ uint32_t grstctl; /* 10 */
+ uint32_t gintsts; /* 14 */
+ uint32_t gintmsk; /* 18 */
+ uint32_t grxstsr; /* 1c */
+ uint32_t grxstsp; /* 20 */
+ uint32_t grxfsiz; /* 24 */
+ uint32_t gnptxfsiz; /* 28 */
+ uint32_t gnptxsts; /* 2c */
+ uint32_t gi2cctl; /* 30 */
+ uint32_t gpvndctl; /* 34 */
+ uint32_t ggpio; /* 38 */
+ uint32_t guid; /* 3c */
+ uint32_t gsnpsid; /* 40 */
+ uint32_t ghwcfg1; /* 44 */
+ uint32_t ghwcfg2; /* 48 */
+ uint32_t ghwcfg3; /* 4c */
+ uint32_t ghwcfg4; /* 50 */
+ uint32_t glpmcfg; /* 54 */
+ uint32_t gpwrdn; /* 58 */
+ uint32_t gdfifocfg; /* 5c */
+ uint32_t gadpctl; /* 60 */
+ uint32_t grefclk; /* 64 */
+ uint32_t gintmsk2; /* 68 */
+ uint32_t gintsts2; /* 6c */
+ };
+ };
+
+ union {
+#define DWC2_FSZREG_SIZE 0x04
+ uint32_t fszreg[DWC2_FSZREG_SIZE / sizeof(uint32_t)];
+ struct {
+ uint32_t hptxfsiz; /* 100 */
+ };
+ };
+
+ union {
+#define DWC2_HREG0_SIZE 0x44
+ uint32_t hreg0[DWC2_HREG0_SIZE / sizeof(uint32_t)];
+ struct {
+ uint32_t hcfg; /* 400 */
+ uint32_t hfir; /* 404 */
+ uint32_t hfnum; /* 408 */
+ uint32_t rsvd0; /* 40c */
+ uint32_t hptxsts; /* 410 */
+ uint32_t haint; /* 414 */
+ uint32_t haintmsk; /* 418 */
+ uint32_t hflbaddr; /* 41c */
+ uint32_t rsvd1[8]; /* 420-43c */
+ uint32_t hprt0; /* 440 */
+ };
+ };
+
+#define DWC2_HREG1_SIZE (0x20 * DWC2_NB_CHAN)
+ uint32_t hreg1[DWC2_HREG1_SIZE / sizeof(uint32_t)];
+
+#define hcchar(_ch) hreg1[((_ch) << 3) + 0] /* 500, 520, ... */
+#define hcsplt(_ch) hreg1[((_ch) << 3) + 1] /* 504, 524, ... */
+#define hcint(_ch) hreg1[((_ch) << 3) + 2] /* 508, 528, ... */
+#define hcintmsk(_ch) hreg1[((_ch) << 3) + 3] /* 50c, 52c, ... */
+#define hctsiz(_ch) hreg1[((_ch) << 3) + 4] /* 510, 530, ... */
+#define hcdma(_ch) hreg1[((_ch) << 3) + 5] /* 514, 534, ... */
+#define hcdmab(_ch) hreg1[((_ch) << 3) + 7] /* 51c, 53c, ... */
+
+ union {
+#define DWC2_PCGREG_SIZE 0x08
+ uint32_t pcgreg[DWC2_PCGREG_SIZE / sizeof(uint32_t)];
+ struct {
+ uint32_t pcgctl; /* e00 */
+ uint32_t pcgcctl1; /* e04 */
+ };
+ };
+
+ /* TODO - implement FIFO registers for slave mode */
+#define DWC2_HFIFO_SIZE (0x1000 * DWC2_NB_CHAN)
+
+ /*
+ * Internal state
+ */
+ QEMUTimer *eof_timer;
+ QEMUTimer *frame_timer;
+ QEMUBH *async_bh;
+ int64_t sof_time;
+ int64_t usb_frame_time;
+ int64_t usb_bit_time;
+ uint32_t usb_version;
+ uint16_t frame_number;
+ uint16_t fi;
+ uint16_t next_chan;
+ bool working;
+ USBPort uport;
+ DWC2Packet packet[DWC2_NB_CHAN]; /* one packet per chan */
+ uint8_t usb_buf[DWC2_NB_CHAN][DWC2_MAX_XFER_SIZE]; /* one buffer per chan */
+};
+
+struct DWC2Class {
+ /*< private >*/
+ SysBusDeviceClass parent_class;
+ ResettablePhases parent_phases;
+
+ /*< public >*/
+};
+
+#define TYPE_DWC2_USB "dwc2-usb"
+#define DWC2_USB(obj) \
+ OBJECT_CHECK(DWC2State, (obj), TYPE_DWC2_USB)
+#define DWC2_CLASS(klass) \
+ OBJECT_CLASS_CHECK(DWC2Class, (klass), TYPE_DWC2_USB)
+#define DWC2_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(DWC2Class, (obj), TYPE_DWC2_USB)
+
+#endif
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index 1c24d82c09..5817ce4421 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -176,6 +176,56 @@ usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d"
usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)"
usb_xhci_enforced_limit(const char *item) "%s"
+# hcd-dwc2.c
+usb_dwc2_update_irq(uint32_t level) "level=%d"
+usb_dwc2_raise_global_irq(uint32_t intr) "0x%08x"
+usb_dwc2_lower_global_irq(uint32_t intr) "0x%08x"
+usb_dwc2_raise_host_irq(uint32_t intr) "0x%04x"
+usb_dwc2_lower_host_irq(uint32_t intr) "0x%04x"
+usb_dwc2_sof(int64_t next) "next SOF %" PRId64
+usb_dwc2_bus_start(void) "start SOFs"
+usb_dwc2_bus_stop(void) "stop SOFs"
+usb_dwc2_find_device(uint8_t addr) "%d"
+usb_dwc2_port_disabled(uint32_t pnum) "port %d disabled"
+usb_dwc2_device_found(uint32_t pnum) "device found on port %d"
+usb_dwc2_device_not_found(void) "device not found"
+usb_dwc2_handle_packet(uint32_t chan, void *dev, void *pkt, uint32_t ep, const char *type, const char *dir, uint32_t mps, uint32_t len, uint32_t pcnt) "ch %d dev %p pkt %p ep %d type %s dir %s mps %d len %d pcnt %d"
+usb_dwc2_memory_read(uint32_t addr, uint32_t len) "addr %d len %d"
+usb_dwc2_packet_status(const char *status, uint32_t len) "status %s len %d"
+usb_dwc2_packet_error(const char *status) "ERROR %s"
+usb_dwc2_async_packet(void *pkt, uint32_t chan, void *dev, uint32_t ep, const char *dir, uint32_t len) "pkt %p ch %d dev %p ep %d %s len %d"
+usb_dwc2_memory_write(uint32_t addr, uint32_t len) "addr %d len %d"
+usb_dwc2_packet_done(const char *status, uint32_t actual, uint32_t len, uint32_t pcnt) "status %s actual %d len %d pcnt %d"
+usb_dwc2_packet_next(const char *status, uint32_t len, uint32_t pcnt) "status %s len %d pcnt %d"
+usb_dwc2_attach(void *port) "port %p"
+usb_dwc2_attach_speed(const char *speed) "%s-speed device attached"
+usb_dwc2_detach(void *port) "port %p"
+usb_dwc2_child_detach(void *port, void *child) "port %p child %p"
+usb_dwc2_wakeup(void *port) "port %p"
+usb_dwc2_async_packet_complete(void *port, void *pkt, uint32_t chan, void *dev, uint32_t ep, const char *dir, uint32_t len) "port %p packet %p ch %d dev %p ep %d %s len %d"
+usb_dwc2_work_bh(void) ""
+usb_dwc2_work_bh_service(uint32_t first, uint32_t current, void *dev, uint32_t ep) "first %d servicing %d dev %p ep %d"
+usb_dwc2_work_bh_next(uint32_t chan) "next %d"
+usb_dwc2_enable_chan(uint32_t chan, void *dev, void *pkt, uint32_t ep) "ch %d dev %p pkt %p ep %d"
+usb_dwc2_glbreg_read(uint64_t addr, const char *reg, uint32_t val) " 0x%04" PRIx64 " %s val 0x%08x"
+usb_dwc2_glbreg_write(uint64_t addr, const char *reg, uint64_t val, uint32_t old, uint64_t result) "0x%04" PRIx64 " %s val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64
+usb_dwc2_fszreg_read(uint64_t addr, uint32_t val) " 0x%04" PRIx64 " HPTXFSIZ val 0x%08x"
+usb_dwc2_fszreg_write(uint64_t addr, uint64_t val, uint32_t old, uint64_t result) "0x%04" PRIx64 " HPTXFSIZ val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64
+usb_dwc2_hreg0_read(uint64_t addr, const char *reg, uint32_t val) " 0x%04" PRIx64 " %s val 0x%08x"
+usb_dwc2_hreg0_write(uint64_t addr, const char *reg, uint64_t val, uint32_t old, uint64_t result) " 0x%04" PRIx64 " %s val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64
+usb_dwc2_hreg1_read(uint64_t addr, const char *reg, uint64_t chan, uint32_t val) " 0x%04" PRIx64 " %s%" PRId64 " val 0x%08x"
+usb_dwc2_hreg1_write(uint64_t addr, const char *reg, uint64_t chan, uint64_t val, uint32_t old, uint64_t result) " 0x%04" PRIx64 " %s%" PRId64 " val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64
+usb_dwc2_pcgreg_read(uint64_t addr, const char *reg, uint32_t val) " 0x%04" PRIx64 " %s val 0x%08x"
+usb_dwc2_pcgreg_write(uint64_t addr, const char *reg, uint64_t val, uint32_t old, uint64_t result) "0x%04" PRIx64 " %s val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64
+usb_dwc2_hreg2_read(uint64_t addr, uint64_t fifo, uint32_t val) " 0x%04" PRIx64 " FIFO%" PRId64 " val 0x%08x"
+usb_dwc2_hreg2_write(uint64_t addr, uint64_t fifo, uint64_t val, uint32_t old, uint64_t result) " 0x%04" PRIx64 " FIFO%" PRId64 " val 0x%08" PRIx64 " old 0x%08x result 0x%08" PRIx64
+usb_dwc2_hreg0_action(const char *s) "%s"
+usb_dwc2_wakeup_endpoint(void *ep, uint32_t stream) "endp %p stream %d"
+usb_dwc2_work_timer(void) ""
+usb_dwc2_reset_enter(void) "=== RESET enter ==="
+usb_dwc2_reset_hold(void) "=== RESET hold ==="
+usb_dwc2_reset_exit(void) "=== RESET exit ==="
+
# desc.c
usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c
index 961190d0f7..4d266d7bb4 100644
--- a/hw/usb/xen-usb.c
+++ b/hw/usb/xen-usb.c
@@ -30,6 +30,7 @@
#include "hw/usb.h"
#include "hw/xen/xen-legacy-backend.h"
#include "monitor/qdev.h"
+#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
@@ -755,13 +756,16 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port,
qdict_put_int(qdict, "port", port);
qdict_put_int(qdict, "hostbus", atoi(busid));
qdict_put_str(qdict, "hostport", portname);
- opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
- if (local_err) {
- goto err;
- }
+ opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict,
+ &error_abort);
usbif->ports[port - 1].dev = USB_DEVICE(qdev_device_add(opts, &local_err));
if (!usbif->ports[port - 1].dev) {
- goto err;
+ qobject_unref(qdict);
+ xen_pv_printf(&usbif->xendev, 0,
+ "device %s could not be opened: %s\n",
+ busid, error_get_pretty(local_err));
+ error_free(local_err);
+ return;
}
qobject_unref(qdict);
speed = usbif->ports[port - 1].dev->speed;
@@ -793,11 +797,6 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port,
usbback_hotplug_enq(usbif, port);
TR_BUS(&usbif->xendev, "port %d attached\n", port);
- return;
-
-err:
- qobject_unref(qdict);
- xen_pv_printf(&usbif->xendev, 0, "device %s could not be opened\n", busid);
}
static void usbback_process_port(struct usbback_info *usbif, unsigned port)
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index c8624943c1..63406184d2 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -74,16 +74,9 @@ static IOInstEnding vfio_ccw_handle_request(SubchDev *sch)
struct ccw_io_region *region = vcdev->io_region;
int ret;
- if (!(sch->orb.ctrl0 & ORB_CTRL0_MASK_PFCH)) {
- if (!(vcdev->force_orb_pfch)) {
- warn_once_pfch(vcdev, sch, "requires PFCH flag set");
- sch_gen_unit_exception(sch);
- css_inject_io_interrupt(sch);
- return IOINST_CC_EXPECTED;
- } else {
- sch->orb.ctrl0 |= ORB_CTRL0_MASK_PFCH;
- warn_once_pfch(vcdev, sch, "PFCH flag forced");
- }
+ if (!(sch->orb.ctrl0 & ORB_CTRL0_MASK_PFCH) && vcdev->force_orb_pfch) {
+ sch->orb.ctrl0 |= ORB_CTRL0_MASK_PFCH;
+ warn_once_pfch(vcdev, sch, "PFCH flag forced");
}
QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB));
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index 3bd05fed12..f2155ddb1d 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1620,7 +1620,7 @@ int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp)
}
cap = (void *) hdr;
- p = mmap(NULL, nv2reg->size, PROT_READ | PROT_WRITE | PROT_EXEC,
+ p = mmap(NULL, nv2reg->size, PROT_READ | PROT_WRITE,
MAP_SHARED, vdev->vbasedev.fd, nv2reg->offset);
if (p == MAP_FAILED) {
ret = -errno;
@@ -1680,7 +1680,7 @@ int vfio_pci_nvlink2_init(VFIOPCIDevice *vdev, Error **errp)
/* Some NVLink bridges may not have assigned ATSD */
if (atsdreg->size) {
- p = mmap(NULL, atsdreg->size, PROT_READ | PROT_WRITE | PROT_EXEC,
+ p = mmap(NULL, atsdreg->size, PROT_READ | PROT_WRITE,
MAP_SHARED, vdev->vbasedev.fd, atsdreg->offset);
if (p == MAP_FAILED) {
ret = -errno;
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 5a8d52e4de..36e8da4fc2 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -95,6 +95,7 @@ int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
+bool bdrv_has_named_bitmaps(BlockDriverState *bs);
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap);
diff --git a/include/exec/memory.h b/include/exec/memory.h
index e000bd2f97..3e00cdbbfa 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1473,15 +1473,26 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr);
*/
void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize,
Error **errp);
+
+/**
+ * memory_region_msync: Synchronize selected address range of
+ * a memory mapped region
+ *
+ * @mr: the memory region to be msync
+ * @addr: the initial address of the range to be sync
+ * @size: the size of the range to be sync
+ */
+void memory_region_msync(MemoryRegion *mr, hwaddr addr, hwaddr size);
+
/**
- * memory_region_do_writeback: Trigger cache writeback or msync for
+ * memory_region_writeback: Trigger cache writeback for
* selected address range
*
* @mr: the memory region to be updated
* @addr: the initial address of the range to be written back
* @size: the size of the range to be written back
*/
-void memory_region_do_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size);
+void memory_region_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size);
/**
* memory_region_set_log: Turn dirty logging on or off for a region.
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 5e59a3d8d7..b295f6a784 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -136,12 +136,12 @@ void qemu_ram_free(RAMBlock *block);
int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp);
-void qemu_ram_writeback(RAMBlock *block, ram_addr_t start, ram_addr_t length);
+void qemu_ram_msync(RAMBlock *block, ram_addr_t start, ram_addr_t length);
/* Clear whole block of mem */
static inline void qemu_ram_block_writeback(RAMBlock *block)
{
- qemu_ram_writeback(block, 0, block->used_length);
+ qemu_ram_msync(block, 0, block->used_length);
}
#define DIRTY_CLIENTS_ALL ((1 << DIRTY_MEMORY_NUM) - 1)
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
index 2e8655a7c2..48a0ad1633 100644
--- a/include/hw/arm/bcm2835_peripherals.h
+++ b/include/hw/arm/bcm2835_peripherals.h
@@ -21,11 +21,13 @@
#include "hw/misc/bcm2835_property.h"
#include "hw/misc/bcm2835_rng.h"
#include "hw/misc/bcm2835_mbox.h"
+#include "hw/misc/bcm2835_mphi.h"
#include "hw/misc/bcm2835_thermal.h"
#include "hw/sd/sdhci.h"
#include "hw/sd/bcm2835_sdhost.h"
#include "hw/gpio/bcm2835_gpio.h"
#include "hw/timer/bcm2835_systmr.h"
+#include "hw/usb/hcd-dwc2.h"
#include "hw/misc/unimp.h"
#define TYPE_BCM2835_PERIPHERALS "bcm2835-peripherals"
@@ -42,6 +44,7 @@ typedef struct BCM2835PeripheralState {
qemu_irq irq, fiq;
BCM2835SystemTimerState systmr;
+ BCM2835MphiState mphi;
UnimplementedDeviceState armtmr;
UnimplementedDeviceState cprman;
UnimplementedDeviceState a2w;
@@ -65,7 +68,7 @@ typedef struct BCM2835PeripheralState {
UnimplementedDeviceState ave0;
UnimplementedDeviceState bscsl;
UnimplementedDeviceState smi;
- UnimplementedDeviceState dwc2;
+ DWC2State dwc2;
UnimplementedDeviceState sdramc;
} BCM2835PeripheralState;
diff --git a/include/hw/display/edid.h b/include/hw/display/edid.h
index ff99dc0a05..23371ee82c 100644
--- a/include/hw/display/edid.h
+++ b/include/hw/display/edid.h
@@ -2,6 +2,7 @@
#define EDID_H
#include "qom/object.h"
+#include "hw/qdev-properties.h"
typedef struct qemu_edid_info {
const char *vendor; /* http://www.uefi.org/pnp_id_list */
diff --git a/include/hw/misc/bcm2835_mphi.h b/include/hw/misc/bcm2835_mphi.h
new file mode 100644
index 0000000000..e084314d0f
--- /dev/null
+++ b/include/hw/misc/bcm2835_mphi.h
@@ -0,0 +1,44 @@
+/*
+ * BCM2835 SOC MPHI state definitions
+ *
+ * Copyright (c) 2020 Paul Zimmerman <pauldzim@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef HW_MISC_BCM2835_MPHI_H
+#define HW_MISC_BCM2835_MPHI_H
+
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+
+#define MPHI_MMIO_SIZE 0x1000
+
+typedef struct BCM2835MphiState BCM2835MphiState;
+
+struct BCM2835MphiState {
+ SysBusDevice parent_obj;
+ qemu_irq irq;
+ MemoryRegion iomem;
+
+ uint32_t outdda;
+ uint32_t outddb;
+ uint32_t ctrl;
+ uint32_t intstat;
+ uint32_t swirq;
+};
+
+#define TYPE_BCM2835_MPHI "bcm2835-mphi"
+
+#define BCM2835_MPHI(obj) \
+ OBJECT_CHECK(BCM2835MphiState, (obj), TYPE_BCM2835_MPHI)
+
+#endif
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index d2533e7264..c421410e3f 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -886,6 +886,7 @@ int spapr_rtc_import_offset(SpaprRtcState *rtc, int64_t legacy_offset);
#define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008
#define SPAPR_LMB_FLAGS_DRC_INVALID 0x00000020
#define SPAPR_LMB_FLAGS_RESERVED 0x00000080
+#define SPAPR_LMB_FLAGS_HOTREMOVABLE 0x00000100
void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h
index 0407edb7ec..93fa4a84c2 100644
--- a/include/hw/registerfields.h
+++ b/include/hw/registerfields.h
@@ -66,35 +66,35 @@
#define FIELD_DP8(storage, reg, field, val) ({ \
struct { \
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
- } v = { .v = val }; \
- uint8_t d; \
- d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
- R_ ## reg ## _ ## field ## _LENGTH, v.v); \
- d; })
+ } _v = { .v = val }; \
+ uint8_t _d; \
+ _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
+ R_ ## reg ## _ ## field ## _LENGTH, _v.v); \
+ _d; })
#define FIELD_DP16(storage, reg, field, val) ({ \
struct { \
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
- } v = { .v = val }; \
- uint16_t d; \
- d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
- R_ ## reg ## _ ## field ## _LENGTH, v.v); \
- d; })
+ } _v = { .v = val }; \
+ uint16_t _d; \
+ _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
+ R_ ## reg ## _ ## field ## _LENGTH, _v.v); \
+ _d; })
#define FIELD_DP32(storage, reg, field, val) ({ \
struct { \
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
- } v = { .v = val }; \
- uint32_t d; \
- d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
- R_ ## reg ## _ ## field ## _LENGTH, v.v); \
- d; })
+ } _v = { .v = val }; \
+ uint32_t _d; \
+ _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
+ R_ ## reg ## _ ## field ## _LENGTH, _v.v); \
+ _d; })
#define FIELD_DP64(storage, reg, field, val) ({ \
struct { \
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
- } v = { .v = val }; \
- uint64_t d; \
- d = deposit64((storage), R_ ## reg ## _ ## field ## _SHIFT, \
- R_ ## reg ## _ ## field ## _LENGTH, v.v); \
- d; })
+ } _v = { .v = val }; \
+ uint64_t _d; \
+ _d = deposit64((storage), R_ ## reg ## _ ## field ## _SHIFT, \
+ R_ ## reg ## _ ## field ## _LENGTH, _v.v); \
+ _d; })
/* Deposit a field to array of registers. */
#define ARRAY_FIELD_DP32(regs, reg, field, val) \
diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index 474a940ad5..9daa98da08 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -21,6 +21,7 @@
#define RISCV_BOOT_H
#include "exec/cpu-defs.h"
+#include "hw/loader.h"
void riscv_find_and_load_firmware(MachineState *machine,
const char *default_machine_firmware,
diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
new file mode 100644
index 0000000000..a4b6499444
--- /dev/null
+++ b/include/hw/riscv/opentitan.h
@@ -0,0 +1,68 @@
+/*
+ * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_OPENTITAN_H
+#define HW_OPENTITAN_H
+
+#include "hw/riscv/riscv_hart.h"
+
+#define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
+#define RISCV_IBEX_SOC(obj) \
+ OBJECT_CHECK(LowRISCIbexSoCState, (obj), TYPE_RISCV_IBEX_SOC)
+
+typedef struct LowRISCIbexSoCState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ RISCVHartArrayState cpus;
+ MemoryRegion flash_mem;
+ MemoryRegion rom;
+} LowRISCIbexSoCState;
+
+typedef struct OpenTitanState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ LowRISCIbexSoCState soc;
+} OpenTitanState;
+
+enum {
+ IBEX_ROM,
+ IBEX_RAM,
+ IBEX_FLASH,
+ IBEX_UART,
+ IBEX_GPIO,
+ IBEX_SPI,
+ IBEX_FLASH_CTRL,
+ IBEX_RV_TIMER,
+ IBEX_AES,
+ IBEX_HMAC,
+ IBEX_PLIC,
+ IBEX_PWRMGR,
+ IBEX_RSTMGR,
+ IBEX_CLKMGR,
+ IBEX_PINMUX,
+ IBEX_ALERT_HANDLER,
+ IBEX_NMI_GEN,
+ IBEX_USBDEV,
+ IBEX_PADCTRL,
+};
+
+#endif
diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h
index 25ce7aa9d5..414992119e 100644
--- a/include/hw/riscv/sifive_e.h
+++ b/include/hw/riscv/sifive_e.h
@@ -47,6 +47,10 @@ typedef struct SiFiveEState {
SiFiveESoCState soc;
} SiFiveEState;
+#define TYPE_RISCV_E_MACHINE MACHINE_TYPE_NAME("sifive_e")
+#define RISCV_E_MACHINE(obj) \
+ OBJECT_CHECK(SiFiveEState, (obj), TYPE_RISCV_E_MACHINE)
+
enum {
SIFIVE_E_DEBUG,
SIFIVE_E_MROM,
diff --git a/include/hw/riscv/spike.h b/include/hw/riscv/spike.h
index dc770421bc..1cd72b85d6 100644
--- a/include/hw/riscv/spike.h
+++ b/include/hw/riscv/spike.h
@@ -39,11 +39,9 @@ enum {
};
#if defined(TARGET_RISCV32)
-#define SPIKE_V1_09_1_CPU TYPE_RISCV_CPU_RV32GCSU_V1_09_1
-#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
+#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_BASE32
#elif defined(TARGET_RISCV64)
-#define SPIKE_V1_09_1_CPU TYPE_RISCV_CPU_RV64GCSU_V1_09_1
-#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_RV64GCSU_V1_10_0
+#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_BASE64
#endif
#endif
diff --git a/include/hw/s390x/pv.h b/include/hw/s390x/pv.h
index 522ca6a04e..aee758bc2d 100644
--- a/include/hw/s390x/pv.h
+++ b/include/hw/s390x/pv.h
@@ -39,7 +39,7 @@ int s390_pv_vm_enable(void);
void s390_pv_vm_disable(void);
int s390_pv_set_sec_parms(uint64_t origin, uint64_t length);
int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak);
-void s390_pv_perf_clear_reset(void);
+void s390_pv_prep_reset(void);
int s390_pv_verify(void);
void s390_pv_unshare(void);
void s390_pv_inject_reset_error(CPUState *cs);
@@ -49,7 +49,7 @@ static inline int s390_pv_vm_enable(void) { return 0; }
static inline void s390_pv_vm_disable(void) {}
static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; }
static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { return 0; }
-static inline void s390_pv_perf_clear_reset(void) {}
+static inline void s390_pv_prep_reset(void) {}
static inline int s390_pv_verify(void) { return 0; }
static inline void s390_pv_unshare(void) {}
static inline void s390_pv_inject_reset_error(CPUState *cs) {};
diff --git a/include/hw/usb/dwc2-regs.h b/include/hw/usb/dwc2-regs.h
new file mode 100644
index 0000000000..40af23a0ba
--- /dev/null
+++ b/include/hw/usb/dwc2-regs.h
@@ -0,0 +1,899 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Imported from the Linux kernel file drivers/usb/dwc2/hw.h, commit
+ * a89bae709b3492b478480a2c9734e7e9393b279c ("usb: dwc2: Move
+ * UTMI_PHY_DATA defines closer")
+ *
+ * hw.h - DesignWare HS OTG Controller hardware definitions
+ *
+ * Copyright 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DWC2_HW_H__
+#define __DWC2_HW_H__
+
+#define HSOTG_REG(x) (x)
+
+#define GOTGCTL HSOTG_REG(0x000)
+#define GOTGCTL_CHIRPEN BIT(27)
+#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22)
+#define GOTGCTL_MULT_VALID_BC_SHIFT 22
+#define GOTGCTL_OTGVER BIT(20)
+#define GOTGCTL_BSESVLD BIT(19)
+#define GOTGCTL_ASESVLD BIT(18)
+#define GOTGCTL_DBNC_SHORT BIT(17)
+#define GOTGCTL_CONID_B BIT(16)
+#define GOTGCTL_DBNCE_FLTR_BYPASS BIT(15)
+#define GOTGCTL_DEVHNPEN BIT(11)
+#define GOTGCTL_HSTSETHNPEN BIT(10)
+#define GOTGCTL_HNPREQ BIT(9)
+#define GOTGCTL_HSTNEGSCS BIT(8)
+#define GOTGCTL_SESREQ BIT(1)
+#define GOTGCTL_SESREQSCS BIT(0)
+
+#define GOTGINT HSOTG_REG(0x004)
+#define GOTGINT_DBNCE_DONE BIT(19)
+#define GOTGINT_A_DEV_TOUT_CHG BIT(18)
+#define GOTGINT_HST_NEG_DET BIT(17)
+#define GOTGINT_HST_NEG_SUC_STS_CHNG BIT(9)
+#define GOTGINT_SES_REQ_SUC_STS_CHNG BIT(8)
+#define GOTGINT_SES_END_DET BIT(2)
+
+#define GAHBCFG HSOTG_REG(0x008)
+#define GAHBCFG_AHB_SINGLE BIT(23)
+#define GAHBCFG_NOTI_ALL_DMA_WRIT BIT(22)
+#define GAHBCFG_REM_MEM_SUPP BIT(21)
+#define GAHBCFG_P_TXF_EMP_LVL BIT(8)
+#define GAHBCFG_NP_TXF_EMP_LVL BIT(7)
+#define GAHBCFG_DMA_EN BIT(5)
+#define GAHBCFG_HBSTLEN_MASK (0xf << 1)
+#define GAHBCFG_HBSTLEN_SHIFT 1
+#define GAHBCFG_HBSTLEN_SINGLE 0
+#define GAHBCFG_HBSTLEN_INCR 1
+#define GAHBCFG_HBSTLEN_INCR4 3
+#define GAHBCFG_HBSTLEN_INCR8 5
+#define GAHBCFG_HBSTLEN_INCR16 7
+#define GAHBCFG_GLBL_INTR_EN BIT(0)
+#define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \
+ GAHBCFG_NP_TXF_EMP_LVL | \
+ GAHBCFG_DMA_EN | \
+ GAHBCFG_GLBL_INTR_EN)
+
+#define GUSBCFG HSOTG_REG(0x00C)
+#define GUSBCFG_FORCEDEVMODE BIT(30)
+#define GUSBCFG_FORCEHOSTMODE BIT(29)
+#define GUSBCFG_TXENDDELAY BIT(28)
+#define GUSBCFG_ICTRAFFICPULLREMOVE BIT(27)
+#define GUSBCFG_ICUSBCAP BIT(26)
+#define GUSBCFG_ULPI_INT_PROT_DIS BIT(25)
+#define GUSBCFG_INDICATORPASSTHROUGH BIT(24)
+#define GUSBCFG_INDICATORCOMPLEMENT BIT(23)
+#define GUSBCFG_TERMSELDLPULSE BIT(22)
+#define GUSBCFG_ULPI_INT_VBUS_IND BIT(21)
+#define GUSBCFG_ULPI_EXT_VBUS_DRV BIT(20)
+#define GUSBCFG_ULPI_CLK_SUSP_M BIT(19)
+#define GUSBCFG_ULPI_AUTO_RES BIT(18)
+#define GUSBCFG_ULPI_FS_LS BIT(17)
+#define GUSBCFG_OTG_UTMI_FS_SEL BIT(16)
+#define GUSBCFG_PHY_LP_CLK_SEL BIT(15)
+#define GUSBCFG_USBTRDTIM_MASK (0xf << 10)
+#define GUSBCFG_USBTRDTIM_SHIFT 10
+#define GUSBCFG_HNPCAP BIT(9)
+#define GUSBCFG_SRPCAP BIT(8)
+#define GUSBCFG_DDRSEL BIT(7)
+#define GUSBCFG_PHYSEL BIT(6)
+#define GUSBCFG_FSINTF BIT(5)
+#define GUSBCFG_ULPI_UTMI_SEL BIT(4)
+#define GUSBCFG_PHYIF16 BIT(3)
+#define GUSBCFG_PHYIF8 (0 << 3)
+#define GUSBCFG_TOUTCAL_MASK (0x7 << 0)
+#define GUSBCFG_TOUTCAL_SHIFT 0
+#define GUSBCFG_TOUTCAL_LIMIT 0x7
+#define GUSBCFG_TOUTCAL(_x) ((_x) << 0)
+
+#define GRSTCTL HSOTG_REG(0x010)
+#define GRSTCTL_AHBIDLE BIT(31)
+#define GRSTCTL_DMAREQ BIT(30)
+#define GRSTCTL_TXFNUM_MASK (0x1f << 6)
+#define GRSTCTL_TXFNUM_SHIFT 6
+#define GRSTCTL_TXFNUM_LIMIT 0x1f
+#define GRSTCTL_TXFNUM(_x) ((_x) << 6)
+#define GRSTCTL_TXFFLSH BIT(5)
+#define GRSTCTL_RXFFLSH BIT(4)
+#define GRSTCTL_IN_TKNQ_FLSH BIT(3)
+#define GRSTCTL_FRMCNTRRST BIT(2)
+#define GRSTCTL_HSFTRST BIT(1)
+#define GRSTCTL_CSFTRST BIT(0)
+
+#define GINTSTS HSOTG_REG(0x014)
+#define GINTMSK HSOTG_REG(0x018)
+#define GINTSTS_WKUPINT BIT(31)
+#define GINTSTS_SESSREQINT BIT(30)
+#define GINTSTS_DISCONNINT BIT(29)
+#define GINTSTS_CONIDSTSCHNG BIT(28)
+#define GINTSTS_LPMTRANRCVD BIT(27)
+#define GINTSTS_PTXFEMP BIT(26)
+#define GINTSTS_HCHINT BIT(25)
+#define GINTSTS_PRTINT BIT(24)
+#define GINTSTS_RESETDET BIT(23)
+#define GINTSTS_FET_SUSP BIT(22)
+#define GINTSTS_INCOMPL_IP BIT(21)
+#define GINTSTS_INCOMPL_SOOUT BIT(21)
+#define GINTSTS_INCOMPL_SOIN BIT(20)
+#define GINTSTS_OEPINT BIT(19)
+#define GINTSTS_IEPINT BIT(18)
+#define GINTSTS_EPMIS BIT(17)
+#define GINTSTS_RESTOREDONE BIT(16)
+#define GINTSTS_EOPF BIT(15)
+#define GINTSTS_ISOUTDROP BIT(14)
+#define GINTSTS_ENUMDONE BIT(13)
+#define GINTSTS_USBRST BIT(12)
+#define GINTSTS_USBSUSP BIT(11)
+#define GINTSTS_ERLYSUSP BIT(10)
+#define GINTSTS_I2CINT BIT(9)
+#define GINTSTS_ULPI_CK_INT BIT(8)
+#define GINTSTS_GOUTNAKEFF BIT(7)
+#define GINTSTS_GINNAKEFF BIT(6)
+#define GINTSTS_NPTXFEMP BIT(5)
+#define GINTSTS_RXFLVL BIT(4)
+#define GINTSTS_SOF BIT(3)
+#define GINTSTS_OTGINT BIT(2)
+#define GINTSTS_MODEMIS BIT(1)
+#define GINTSTS_CURMODE_HOST BIT(0)
+
+#define GRXSTSR HSOTG_REG(0x01C)
+#define GRXSTSP HSOTG_REG(0x020)
+#define GRXSTS_FN_MASK (0x7f << 25)
+#define GRXSTS_FN_SHIFT 25
+#define GRXSTS_PKTSTS_MASK (0xf << 17)
+#define GRXSTS_PKTSTS_SHIFT 17
+#define GRXSTS_PKTSTS_GLOBALOUTNAK 1
+#define GRXSTS_PKTSTS_OUTRX 2
+#define GRXSTS_PKTSTS_HCHIN 2
+#define GRXSTS_PKTSTS_OUTDONE 3
+#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3
+#define GRXSTS_PKTSTS_SETUPDONE 4
+#define GRXSTS_PKTSTS_DATATOGGLEERR 5
+#define GRXSTS_PKTSTS_SETUPRX 6
+#define GRXSTS_PKTSTS_HCHHALTED 7
+#define GRXSTS_HCHNUM_MASK (0xf << 0)
+#define GRXSTS_HCHNUM_SHIFT 0
+#define GRXSTS_DPID_MASK (0x3 << 15)
+#define GRXSTS_DPID_SHIFT 15
+#define GRXSTS_BYTECNT_MASK (0x7ff << 4)
+#define GRXSTS_BYTECNT_SHIFT 4
+#define GRXSTS_EPNUM_MASK (0xf << 0)
+#define GRXSTS_EPNUM_SHIFT 0
+
+#define GRXFSIZ HSOTG_REG(0x024)
+#define GRXFSIZ_DEPTH_MASK (0xffff << 0)
+#define GRXFSIZ_DEPTH_SHIFT 0
+
+#define GNPTXFSIZ HSOTG_REG(0x028)
+/* Use FIFOSIZE_* constants to access this register */
+
+#define GNPTXSTS HSOTG_REG(0x02C)
+#define GNPTXSTS_NP_TXQ_TOP_MASK (0x7f << 24)
+#define GNPTXSTS_NP_TXQ_TOP_SHIFT 24
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK (0xff << 16)
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT 16
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v) (((_v) >> 16) & 0xff)
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK (0xffff << 0)
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT 0
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v) (((_v) >> 0) & 0xffff)
+
+#define GI2CCTL HSOTG_REG(0x0030)
+#define GI2CCTL_BSYDNE BIT(31)
+#define GI2CCTL_RW BIT(30)
+#define GI2CCTL_I2CDATSE0 BIT(28)
+#define GI2CCTL_I2CDEVADDR_MASK (0x3 << 26)
+#define GI2CCTL_I2CDEVADDR_SHIFT 26
+#define GI2CCTL_I2CSUSPCTL BIT(25)
+#define GI2CCTL_ACK BIT(24)
+#define GI2CCTL_I2CEN BIT(23)
+#define GI2CCTL_ADDR_MASK (0x7f << 16)
+#define GI2CCTL_ADDR_SHIFT 16
+#define GI2CCTL_REGADDR_MASK (0xff << 8)
+#define GI2CCTL_REGADDR_SHIFT 8
+#define GI2CCTL_RWDATA_MASK (0xff << 0)
+#define GI2CCTL_RWDATA_SHIFT 0
+
+#define GPVNDCTL HSOTG_REG(0x0034)
+#define GGPIO HSOTG_REG(0x0038)
+#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16)
+
+#define GUID HSOTG_REG(0x003c)
+#define GSNPSID HSOTG_REG(0x0040)
+#define GHWCFG1 HSOTG_REG(0x0044)
+#define GSNPSID_ID_MASK GENMASK(31, 16)
+
+#define GHWCFG2 HSOTG_REG(0x0048)
+#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31)
+#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1f << 26)
+#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT 26
+#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24)
+#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT 24
+#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22)
+#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT 22
+#define GHWCFG2_MULTI_PROC_INT BIT(20)
+#define GHWCFG2_DYNAMIC_FIFO BIT(19)
+#define GHWCFG2_PERIO_EP_SUPPORTED BIT(18)
+#define GHWCFG2_NUM_HOST_CHAN_MASK (0xf << 14)
+#define GHWCFG2_NUM_HOST_CHAN_SHIFT 14
+#define GHWCFG2_NUM_DEV_EP_MASK (0xf << 10)
+#define GHWCFG2_NUM_DEV_EP_SHIFT 10
+#define GHWCFG2_FS_PHY_TYPE_MASK (0x3 << 8)
+#define GHWCFG2_FS_PHY_TYPE_SHIFT 8
+#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0
+#define GHWCFG2_FS_PHY_TYPE_DEDICATED 1
+#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI 2
+#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI 3
+#define GHWCFG2_HS_PHY_TYPE_MASK (0x3 << 6)
+#define GHWCFG2_HS_PHY_TYPE_SHIFT 6
+#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
+#define GHWCFG2_HS_PHY_TYPE_UTMI 1
+#define GHWCFG2_HS_PHY_TYPE_ULPI 2
+#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
+#define GHWCFG2_POINT2POINT BIT(5)
+#define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3)
+#define GHWCFG2_ARCHITECTURE_SHIFT 3
+#define GHWCFG2_SLAVE_ONLY_ARCH 0
+#define GHWCFG2_EXT_DMA_ARCH 1
+#define GHWCFG2_INT_DMA_ARCH 2
+#define GHWCFG2_OP_MODE_MASK (0x7 << 0)
+#define GHWCFG2_OP_MODE_SHIFT 0
+#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE 0
+#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE 1
+#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE 2
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
+#define GHWCFG2_OP_MODE_UNDEFINED 7
+
+#define GHWCFG3 HSOTG_REG(0x004c)
+#define GHWCFG3_DFIFO_DEPTH_MASK (0xffff << 16)
+#define GHWCFG3_DFIFO_DEPTH_SHIFT 16
+#define GHWCFG3_OTG_LPM_EN BIT(15)
+#define GHWCFG3_BC_SUPPORT BIT(14)
+#define GHWCFG3_OTG_ENABLE_HSIC BIT(13)
+#define GHWCFG3_ADP_SUPP BIT(12)
+#define GHWCFG3_SYNCH_RESET_TYPE BIT(11)
+#define GHWCFG3_OPTIONAL_FEATURES BIT(10)
+#define GHWCFG3_VENDOR_CTRL_IF BIT(9)
+#define GHWCFG3_I2C BIT(8)
+#define GHWCFG3_OTG_FUNC BIT(7)
+#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4)
+#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT 4
+#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xf << 0)
+#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT 0
+
+#define GHWCFG4 HSOTG_REG(0x0050)
+#define GHWCFG4_DESC_DMA_DYN BIT(31)
+#define GHWCFG4_DESC_DMA BIT(30)
+#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
+#define GHWCFG4_NUM_IN_EPS_SHIFT 26
+#define GHWCFG4_DED_FIFO_EN BIT(25)
+#define GHWCFG4_DED_FIFO_SHIFT 25
+#define GHWCFG4_SESSION_END_FILT_EN BIT(24)
+#define GHWCFG4_B_VALID_FILT_EN BIT(23)
+#define GHWCFG4_A_VALID_FILT_EN BIT(22)
+#define GHWCFG4_VBUS_VALID_FILT_EN BIT(21)
+#define GHWCFG4_IDDIG_FILT_EN BIT(20)
+#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xf << 16)
+#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14)
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
+#define GHWCFG4_ACG_SUPPORTED BIT(12)
+#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11)
+#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10)
+#define GHWCFG4_XHIBER BIT(7)
+#define GHWCFG4_HIBER BIT(6)
+#define GHWCFG4_MIN_AHB_FREQ BIT(5)
+#define GHWCFG4_POWER_OPTIMIZ BIT(4)
+#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xf << 0)
+#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0
+
+#define GLPMCFG HSOTG_REG(0x0054)
+#define GLPMCFG_INVSELHSIC BIT(31)
+#define GLPMCFG_HSICCON BIT(30)
+#define GLPMCFG_RSTRSLPSTS BIT(29)
+#define GLPMCFG_ENBESL BIT(28)
+#define GLPMCFG_LPM_RETRYCNT_STS_MASK (0x7 << 25)
+#define GLPMCFG_LPM_RETRYCNT_STS_SHIFT 25
+#define GLPMCFG_SNDLPM BIT(24)
+#define GLPMCFG_RETRY_CNT_MASK (0x7 << 21)
+#define GLPMCFG_RETRY_CNT_SHIFT 21
+#define GLPMCFG_LPM_REJECT_CTRL_CONTROL BIT(21)
+#define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22)
+#define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17)
+#define GLPMCFG_LPM_CHNL_INDX_SHIFT 17
+#define GLPMCFG_L1RESUMEOK BIT(16)
+#define GLPMCFG_SLPSTS BIT(15)
+#define GLPMCFG_COREL1RES_MASK (0x3 << 13)
+#define GLPMCFG_COREL1RES_SHIFT 13
+#define GLPMCFG_HIRD_THRES_MASK (0x1f << 8)
+#define GLPMCFG_HIRD_THRES_SHIFT 8
+#define GLPMCFG_HIRD_THRES_EN (0x10 << 8)
+#define GLPMCFG_ENBLSLPM BIT(7)
+#define GLPMCFG_BREMOTEWAKE BIT(6)
+#define GLPMCFG_HIRD_MASK (0xf << 2)
+#define GLPMCFG_HIRD_SHIFT 2
+#define GLPMCFG_APPL1RES BIT(1)
+#define GLPMCFG_LPMCAP BIT(0)
+
+#define GPWRDN HSOTG_REG(0x0058)
+#define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24)
+#define GPWRDN_MULT_VAL_ID_BC_SHIFT 24
+#define GPWRDN_ADP_INT BIT(23)
+#define GPWRDN_BSESSVLD BIT(22)
+#define GPWRDN_IDSTS BIT(21)
+#define GPWRDN_LINESTATE_MASK (0x3 << 19)
+#define GPWRDN_LINESTATE_SHIFT 19
+#define GPWRDN_STS_CHGINT_MSK BIT(18)
+#define GPWRDN_STS_CHGINT BIT(17)
+#define GPWRDN_SRP_DET_MSK BIT(16)
+#define GPWRDN_SRP_DET BIT(15)
+#define GPWRDN_CONNECT_DET_MSK BIT(14)
+#define GPWRDN_CONNECT_DET BIT(13)
+#define GPWRDN_DISCONN_DET_MSK BIT(12)
+#define GPWRDN_DISCONN_DET BIT(11)
+#define GPWRDN_RST_DET_MSK BIT(10)
+#define GPWRDN_RST_DET BIT(9)
+#define GPWRDN_LNSTSCHG_MSK BIT(8)
+#define GPWRDN_LNSTSCHG BIT(7)
+#define GPWRDN_DIS_VBUS BIT(6)
+#define GPWRDN_PWRDNSWTCH BIT(5)
+#define GPWRDN_PWRDNRSTN BIT(4)
+#define GPWRDN_PWRDNCLMP BIT(3)
+#define GPWRDN_RESTORE BIT(2)
+#define GPWRDN_PMUACTV BIT(1)
+#define GPWRDN_PMUINTSEL BIT(0)
+
+#define GDFIFOCFG HSOTG_REG(0x005c)
+#define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16)
+#define GDFIFOCFG_EPINFOBASE_SHIFT 16
+#define GDFIFOCFG_GDFIFOCFG_MASK (0xffff << 0)
+#define GDFIFOCFG_GDFIFOCFG_SHIFT 0
+
+#define ADPCTL HSOTG_REG(0x0060)
+#define ADPCTL_AR_MASK (0x3 << 27)
+#define ADPCTL_AR_SHIFT 27
+#define ADPCTL_ADP_TMOUT_INT_MSK BIT(26)
+#define ADPCTL_ADP_SNS_INT_MSK BIT(25)
+#define ADPCTL_ADP_PRB_INT_MSK BIT(24)
+#define ADPCTL_ADP_TMOUT_INT BIT(23)
+#define ADPCTL_ADP_SNS_INT BIT(22)
+#define ADPCTL_ADP_PRB_INT BIT(21)
+#define ADPCTL_ADPENA BIT(20)
+#define ADPCTL_ADPRES BIT(19)
+#define ADPCTL_ENASNS BIT(18)
+#define ADPCTL_ENAPRB BIT(17)
+#define ADPCTL_RTIM_MASK (0x7ff << 6)
+#define ADPCTL_RTIM_SHIFT 6
+#define ADPCTL_PRB_PER_MASK (0x3 << 4)
+#define ADPCTL_PRB_PER_SHIFT 4
+#define ADPCTL_PRB_DELTA_MASK (0x3 << 2)
+#define ADPCTL_PRB_DELTA_SHIFT 2
+#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0)
+#define ADPCTL_PRB_DSCHRG_SHIFT 0
+
+#define GREFCLK HSOTG_REG(0x0064)
+#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15)
+#define GREFCLK_REFCLKPER_SHIFT 15
+#define GREFCLK_REF_CLK_MODE BIT(14)
+#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff)
+#define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0
+
+#define GINTMSK2 HSOTG_REG(0x0068)
+#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0)
+
+#define GINTSTS2 HSOTG_REG(0x006c)
+#define GINTSTS2_WKUP_ALERT_INT BIT(0)
+
+#define HPTXFSIZ HSOTG_REG(0x100)
+/* Use FIFOSIZE_* constants to access this register */
+
+#define DPTXFSIZN(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4))
+/* Use FIFOSIZE_* constants to access this register */
+
+/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */
+#define FIFOSIZE_DEPTH_MASK (0xffff << 16)
+#define FIFOSIZE_DEPTH_SHIFT 16
+#define FIFOSIZE_STARTADDR_MASK (0xffff << 0)
+#define FIFOSIZE_STARTADDR_SHIFT 0
+#define FIFOSIZE_DEPTH_GET(_x) (((_x) >> 16) & 0xffff)
+
+/* Device mode registers */
+
+#define DCFG HSOTG_REG(0x800)
+#define DCFG_DESCDMA_EN BIT(23)
+#define DCFG_EPMISCNT_MASK (0x1f << 18)
+#define DCFG_EPMISCNT_SHIFT 18
+#define DCFG_EPMISCNT_LIMIT 0x1f
+#define DCFG_EPMISCNT(_x) ((_x) << 18)
+#define DCFG_IPG_ISOC_SUPPORDED BIT(17)
+#define DCFG_PERFRINT_MASK (0x3 << 11)
+#define DCFG_PERFRINT_SHIFT 11
+#define DCFG_PERFRINT_LIMIT 0x3
+#define DCFG_PERFRINT(_x) ((_x) << 11)
+#define DCFG_DEVADDR_MASK (0x7f << 4)
+#define DCFG_DEVADDR_SHIFT 4
+#define DCFG_DEVADDR_LIMIT 0x7f
+#define DCFG_DEVADDR(_x) ((_x) << 4)
+#define DCFG_NZ_STS_OUT_HSHK BIT(2)
+#define DCFG_DEVSPD_MASK (0x3 << 0)
+#define DCFG_DEVSPD_SHIFT 0
+#define DCFG_DEVSPD_HS 0
+#define DCFG_DEVSPD_FS 1
+#define DCFG_DEVSPD_LS 2
+#define DCFG_DEVSPD_FS48 3
+
+#define DCTL HSOTG_REG(0x804)
+#define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19)
+#define DCTL_PWRONPRGDONE BIT(11)
+#define DCTL_CGOUTNAK BIT(10)
+#define DCTL_SGOUTNAK BIT(9)
+#define DCTL_CGNPINNAK BIT(8)
+#define DCTL_SGNPINNAK BIT(7)
+#define DCTL_TSTCTL_MASK (0x7 << 4)
+#define DCTL_TSTCTL_SHIFT 4
+#define DCTL_GOUTNAKSTS BIT(3)
+#define DCTL_GNPINNAKSTS BIT(2)
+#define DCTL_SFTDISCON BIT(1)
+#define DCTL_RMTWKUPSIG BIT(0)
+
+#define DSTS HSOTG_REG(0x808)
+#define DSTS_SOFFN_MASK (0x3fff << 8)
+#define DSTS_SOFFN_SHIFT 8
+#define DSTS_SOFFN_LIMIT 0x3fff
+#define DSTS_SOFFN(_x) ((_x) << 8)
+#define DSTS_ERRATICERR BIT(3)
+#define DSTS_ENUMSPD_MASK (0x3 << 1)
+#define DSTS_ENUMSPD_SHIFT 1
+#define DSTS_ENUMSPD_HS 0
+#define DSTS_ENUMSPD_FS 1
+#define DSTS_ENUMSPD_LS 2
+#define DSTS_ENUMSPD_FS48 3
+#define DSTS_SUSPSTS BIT(0)
+
+#define DIEPMSK HSOTG_REG(0x810)
+#define DIEPMSK_NAKMSK BIT(13)
+#define DIEPMSK_BNAININTRMSK BIT(9)
+#define DIEPMSK_TXFIFOUNDRNMSK BIT(8)
+#define DIEPMSK_TXFIFOEMPTY BIT(7)
+#define DIEPMSK_INEPNAKEFFMSK BIT(6)
+#define DIEPMSK_INTKNEPMISMSK BIT(5)
+#define DIEPMSK_INTKNTXFEMPMSK BIT(4)
+#define DIEPMSK_TIMEOUTMSK BIT(3)
+#define DIEPMSK_AHBERRMSK BIT(2)
+#define DIEPMSK_EPDISBLDMSK BIT(1)
+#define DIEPMSK_XFERCOMPLMSK BIT(0)
+
+#define DOEPMSK HSOTG_REG(0x814)
+#define DOEPMSK_BNAMSK BIT(9)
+#define DOEPMSK_BACK2BACKSETUP BIT(6)
+#define DOEPMSK_STSPHSERCVDMSK BIT(5)
+#define DOEPMSK_OUTTKNEPDISMSK BIT(4)
+#define DOEPMSK_SETUPMSK BIT(3)
+#define DOEPMSK_AHBERRMSK BIT(2)
+#define DOEPMSK_EPDISBLDMSK BIT(1)
+#define DOEPMSK_XFERCOMPLMSK BIT(0)
+
+#define DAINT HSOTG_REG(0x818)
+#define DAINTMSK HSOTG_REG(0x81C)
+#define DAINT_OUTEP_SHIFT 16
+#define DAINT_OUTEP(_x) (1 << ((_x) + 16))
+#define DAINT_INEP(_x) (1 << (_x))
+
+#define DTKNQR1 HSOTG_REG(0x820)
+#define DTKNQR2 HSOTG_REG(0x824)
+#define DTKNQR3 HSOTG_REG(0x830)
+#define DTKNQR4 HSOTG_REG(0x834)
+#define DIEPEMPMSK HSOTG_REG(0x834)
+
+#define DVBUSDIS HSOTG_REG(0x828)
+#define DVBUSPULSE HSOTG_REG(0x82C)
+
+#define DIEPCTL0 HSOTG_REG(0x900)
+#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20))
+
+#define DOEPCTL0 HSOTG_REG(0xB00)
+#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0] - MPS setting different for EP0
+ */
+#define D0EPCTL_MPS_MASK (0x3 << 0)
+#define D0EPCTL_MPS_SHIFT 0
+#define D0EPCTL_MPS_64 0
+#define D0EPCTL_MPS_32 1
+#define D0EPCTL_MPS_16 2
+#define D0EPCTL_MPS_8 3
+
+#define DXEPCTL_EPENA BIT(31)
+#define DXEPCTL_EPDIS BIT(30)
+#define DXEPCTL_SETD1PID BIT(29)
+#define DXEPCTL_SETODDFR BIT(29)
+#define DXEPCTL_SETD0PID BIT(28)
+#define DXEPCTL_SETEVENFR BIT(28)
+#define DXEPCTL_SNAK BIT(27)
+#define DXEPCTL_CNAK BIT(26)
+#define DXEPCTL_TXFNUM_MASK (0xf << 22)
+#define DXEPCTL_TXFNUM_SHIFT 22
+#define DXEPCTL_TXFNUM_LIMIT 0xf
+#define DXEPCTL_TXFNUM(_x) ((_x) << 22)
+#define DXEPCTL_STALL BIT(21)
+#define DXEPCTL_SNP BIT(20)
+#define DXEPCTL_EPTYPE_MASK (0x3 << 18)
+#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18)
+#define DXEPCTL_EPTYPE_ISO (0x1 << 18)
+#define DXEPCTL_EPTYPE_BULK (0x2 << 18)
+#define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18)
+
+#define DXEPCTL_NAKSTS BIT(17)
+#define DXEPCTL_DPID BIT(16)
+#define DXEPCTL_EOFRNUM BIT(16)
+#define DXEPCTL_USBACTEP BIT(15)
+#define DXEPCTL_NEXTEP_MASK (0xf << 11)
+#define DXEPCTL_NEXTEP_SHIFT 11
+#define DXEPCTL_NEXTEP_LIMIT 0xf
+#define DXEPCTL_NEXTEP(_x) ((_x) << 11)
+#define DXEPCTL_MPS_MASK (0x7ff << 0)
+#define DXEPCTL_MPS_SHIFT 0
+#define DXEPCTL_MPS_LIMIT 0x7ff
+#define DXEPCTL_MPS(_x) ((_x) << 0)
+
+#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
+#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
+#define DXEPINT_SETUP_RCVD BIT(15)
+#define DXEPINT_NYETINTRPT BIT(14)
+#define DXEPINT_NAKINTRPT BIT(13)
+#define DXEPINT_BBLEERRINTRPT BIT(12)
+#define DXEPINT_PKTDRPSTS BIT(11)
+#define DXEPINT_BNAINTR BIT(9)
+#define DXEPINT_TXFIFOUNDRN BIT(8)
+#define DXEPINT_OUTPKTERR BIT(8)
+#define DXEPINT_TXFEMP BIT(7)
+#define DXEPINT_INEPNAKEFF BIT(6)
+#define DXEPINT_BACK2BACKSETUP BIT(6)
+#define DXEPINT_INTKNEPMIS BIT(5)
+#define DXEPINT_STSPHSERCVD BIT(5)
+#define DXEPINT_INTKNTXFEMP BIT(4)
+#define DXEPINT_OUTTKNEPDIS BIT(4)
+#define DXEPINT_TIMEOUT BIT(3)
+#define DXEPINT_SETUP BIT(3)
+#define DXEPINT_AHBERR BIT(2)
+#define DXEPINT_EPDISBLD BIT(1)
+#define DXEPINT_XFERCOMPL BIT(0)
+
+#define DIEPTSIZ0 HSOTG_REG(0x910)
+#define DIEPTSIZ0_PKTCNT_MASK (0x3 << 19)
+#define DIEPTSIZ0_PKTCNT_SHIFT 19
+#define DIEPTSIZ0_PKTCNT_LIMIT 0x3
+#define DIEPTSIZ0_PKTCNT(_x) ((_x) << 19)
+#define DIEPTSIZ0_XFERSIZE_MASK (0x7f << 0)
+#define DIEPTSIZ0_XFERSIZE_SHIFT 0
+#define DIEPTSIZ0_XFERSIZE_LIMIT 0x7f
+#define DIEPTSIZ0_XFERSIZE(_x) ((_x) << 0)
+
+#define DOEPTSIZ0 HSOTG_REG(0xB10)
+#define DOEPTSIZ0_SUPCNT_MASK (0x3 << 29)
+#define DOEPTSIZ0_SUPCNT_SHIFT 29
+#define DOEPTSIZ0_SUPCNT_LIMIT 0x3
+#define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29)
+#define DOEPTSIZ0_PKTCNT BIT(19)
+#define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0)
+#define DOEPTSIZ0_XFERSIZE_SHIFT 0
+
+#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20))
+#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20))
+#define DXEPTSIZ_MC_MASK (0x3 << 29)
+#define DXEPTSIZ_MC_SHIFT 29
+#define DXEPTSIZ_MC_LIMIT 0x3
+#define DXEPTSIZ_MC(_x) ((_x) << 29)
+#define DXEPTSIZ_PKTCNT_MASK (0x3ff << 19)
+#define DXEPTSIZ_PKTCNT_SHIFT 19
+#define DXEPTSIZ_PKTCNT_LIMIT 0x3ff
+#define DXEPTSIZ_PKTCNT_GET(_v) (((_v) >> 19) & 0x3ff)
+#define DXEPTSIZ_PKTCNT(_x) ((_x) << 19)
+#define DXEPTSIZ_XFERSIZE_MASK (0x7ffff << 0)
+#define DXEPTSIZ_XFERSIZE_SHIFT 0
+#define DXEPTSIZ_XFERSIZE_LIMIT 0x7ffff
+#define DXEPTSIZ_XFERSIZE_GET(_v) (((_v) >> 0) & 0x7ffff)
+#define DXEPTSIZ_XFERSIZE(_x) ((_x) << 0)
+
+#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20))
+#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20))
+
+#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20))
+
+#define PCGCTL HSOTG_REG(0x0e00)
+#define PCGCTL_IF_DEV_MODE BIT(31)
+#define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29)
+#define PCGCTL_P2HD_PRT_SPD_SHIFT 29
+#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27)
+#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
+#define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20)
+#define PCGCTL_MAC_DEV_ADDR_SHIFT 20
+#define PCGCTL_MAX_TERMSEL BIT(19)
+#define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17)
+#define PCGCTL_MAX_XCVRSELECT_SHIFT 17
+#define PCGCTL_PORT_POWER BIT(16)
+#define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14)
+#define PCGCTL_PRT_CLK_SEL_SHIFT 14
+#define PCGCTL_ESS_REG_RESTORED BIT(13)
+#define PCGCTL_EXTND_HIBER_SWITCH BIT(12)
+#define PCGCTL_EXTND_HIBER_PWRCLMP BIT(11)
+#define PCGCTL_ENBL_EXTND_HIBER BIT(10)
+#define PCGCTL_RESTOREMODE BIT(9)
+#define PCGCTL_RESETAFTSUSP BIT(8)
+#define PCGCTL_DEEP_SLEEP BIT(7)
+#define PCGCTL_PHY_IN_SLEEP BIT(6)
+#define PCGCTL_ENBL_SLEEP_GATING BIT(5)
+#define PCGCTL_RSTPDWNMODULE BIT(3)
+#define PCGCTL_PWRCLMP BIT(2)
+#define PCGCTL_GATEHCLK BIT(1)
+#define PCGCTL_STOPPCLK BIT(0)
+
+#define PCGCCTL1 HSOTG_REG(0xe04)
+#define PCGCCTL1_TIMER (0x3 << 1)
+#define PCGCCTL1_GATEEN BIT(0)
+
+#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+/* Host Mode Registers */
+
+#define HCFG HSOTG_REG(0x0400)
+#define HCFG_MODECHTIMEN BIT(31)
+#define HCFG_PERSCHEDENA BIT(26)
+#define HCFG_FRLISTEN_MASK (0x3 << 24)
+#define HCFG_FRLISTEN_SHIFT 24
+#define HCFG_FRLISTEN_8 (0 << 24)
+#define FRLISTEN_8_SIZE 8
+#define HCFG_FRLISTEN_16 BIT(24)
+#define FRLISTEN_16_SIZE 16
+#define HCFG_FRLISTEN_32 (2 << 24)
+#define FRLISTEN_32_SIZE 32
+#define HCFG_FRLISTEN_64 (3 << 24)
+#define FRLISTEN_64_SIZE 64
+#define HCFG_DESCDMA BIT(23)
+#define HCFG_RESVALID_MASK (0xff << 8)
+#define HCFG_RESVALID_SHIFT 8
+#define HCFG_ENA32KHZ BIT(7)
+#define HCFG_FSLSSUPP BIT(2)
+#define HCFG_FSLSPCLKSEL_MASK (0x3 << 0)
+#define HCFG_FSLSPCLKSEL_SHIFT 0
+#define HCFG_FSLSPCLKSEL_30_60_MHZ 0
+#define HCFG_FSLSPCLKSEL_48_MHZ 1
+#define HCFG_FSLSPCLKSEL_6_MHZ 2
+
+#define HFIR HSOTG_REG(0x0404)
+#define HFIR_FRINT_MASK (0xffff << 0)
+#define HFIR_FRINT_SHIFT 0
+#define HFIR_RLDCTRL BIT(16)
+
+#define HFNUM HSOTG_REG(0x0408)
+#define HFNUM_FRREM_MASK (0xffff << 16)
+#define HFNUM_FRREM_SHIFT 16
+#define HFNUM_FRNUM_MASK (0xffff << 0)
+#define HFNUM_FRNUM_SHIFT 0
+#define HFNUM_MAX_FRNUM 0x3fff
+
+#define HPTXSTS HSOTG_REG(0x0410)
+#define TXSTS_QTOP_ODD BIT(31)
+#define TXSTS_QTOP_CHNEP_MASK (0xf << 27)
+#define TXSTS_QTOP_CHNEP_SHIFT 27
+#define TXSTS_QTOP_TOKEN_MASK (0x3 << 25)
+#define TXSTS_QTOP_TOKEN_SHIFT 25
+#define TXSTS_QTOP_TERMINATE BIT(24)
+#define TXSTS_QSPCAVAIL_MASK (0xff << 16)
+#define TXSTS_QSPCAVAIL_SHIFT 16
+#define TXSTS_FSPCAVAIL_MASK (0xffff << 0)
+#define TXSTS_FSPCAVAIL_SHIFT 0
+
+#define HAINT HSOTG_REG(0x0414)
+#define HAINTMSK HSOTG_REG(0x0418)
+#define HFLBADDR HSOTG_REG(0x041c)
+
+#define HPRT0 HSOTG_REG(0x0440)
+#define HPRT0_SPD_MASK (0x3 << 17)
+#define HPRT0_SPD_SHIFT 17
+#define HPRT0_SPD_HIGH_SPEED 0
+#define HPRT0_SPD_FULL_SPEED 1
+#define HPRT0_SPD_LOW_SPEED 2
+#define HPRT0_TSTCTL_MASK (0xf << 13)
+#define HPRT0_TSTCTL_SHIFT 13
+#define HPRT0_PWR BIT(12)
+#define HPRT0_LNSTS_MASK (0x3 << 10)
+#define HPRT0_LNSTS_SHIFT 10
+#define HPRT0_RST BIT(8)
+#define HPRT0_SUSP BIT(7)
+#define HPRT0_RES BIT(6)
+#define HPRT0_OVRCURRCHG BIT(5)
+#define HPRT0_OVRCURRACT BIT(4)
+#define HPRT0_ENACHG BIT(3)
+#define HPRT0_ENA BIT(2)
+#define HPRT0_CONNDET BIT(1)
+#define HPRT0_CONNSTS BIT(0)
+
+#define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch))
+#define HCCHAR_CHENA BIT(31)
+#define HCCHAR_CHDIS BIT(30)
+#define HCCHAR_ODDFRM BIT(29)
+#define HCCHAR_DEVADDR_MASK (0x7f << 22)
+#define HCCHAR_DEVADDR_SHIFT 22
+#define HCCHAR_MULTICNT_MASK (0x3 << 20)
+#define HCCHAR_MULTICNT_SHIFT 20
+#define HCCHAR_EPTYPE_MASK (0x3 << 18)
+#define HCCHAR_EPTYPE_SHIFT 18
+#define HCCHAR_LSPDDEV BIT(17)
+#define HCCHAR_EPDIR BIT(15)
+#define HCCHAR_EPNUM_MASK (0xf << 11)
+#define HCCHAR_EPNUM_SHIFT 11
+#define HCCHAR_MPS_MASK (0x7ff << 0)
+#define HCCHAR_MPS_SHIFT 0
+
+#define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch))
+#define HCSPLT_SPLTENA BIT(31)
+#define HCSPLT_COMPSPLT BIT(16)
+#define HCSPLT_XACTPOS_MASK (0x3 << 14)
+#define HCSPLT_XACTPOS_SHIFT 14
+#define HCSPLT_XACTPOS_MID 0
+#define HCSPLT_XACTPOS_END 1
+#define HCSPLT_XACTPOS_BEGIN 2
+#define HCSPLT_XACTPOS_ALL 3
+#define HCSPLT_HUBADDR_MASK (0x7f << 7)
+#define HCSPLT_HUBADDR_SHIFT 7
+#define HCSPLT_PRTADDR_MASK (0x7f << 0)
+#define HCSPLT_PRTADDR_SHIFT 0
+
+#define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch))
+#define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch))
+#define HCINTMSK_RESERVED14_31 (0x3ffff << 14)
+#define HCINTMSK_FRM_LIST_ROLL BIT(13)
+#define HCINTMSK_XCS_XACT BIT(12)
+#define HCINTMSK_BNA BIT(11)
+#define HCINTMSK_DATATGLERR BIT(10)
+#define HCINTMSK_FRMOVRUN BIT(9)
+#define HCINTMSK_BBLERR BIT(8)
+#define HCINTMSK_XACTERR BIT(7)
+#define HCINTMSK_NYET BIT(6)
+#define HCINTMSK_ACK BIT(5)
+#define HCINTMSK_NAK BIT(4)
+#define HCINTMSK_STALL BIT(3)
+#define HCINTMSK_AHBERR BIT(2)
+#define HCINTMSK_CHHLTD BIT(1)
+#define HCINTMSK_XFERCOMPL BIT(0)
+
+#define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch))
+#define TSIZ_DOPNG BIT(31)
+#define TSIZ_SC_MC_PID_MASK (0x3 << 29)
+#define TSIZ_SC_MC_PID_SHIFT 29
+#define TSIZ_SC_MC_PID_DATA0 0
+#define TSIZ_SC_MC_PID_DATA2 1
+#define TSIZ_SC_MC_PID_DATA1 2
+#define TSIZ_SC_MC_PID_MDATA 3
+#define TSIZ_SC_MC_PID_SETUP 3
+#define TSIZ_PKTCNT_MASK (0x3ff << 19)
+#define TSIZ_PKTCNT_SHIFT 19
+#define TSIZ_NTD_MASK (0xff << 8)
+#define TSIZ_NTD_SHIFT 8
+#define TSIZ_SCHINFO_MASK (0xff << 0)
+#define TSIZ_SCHINFO_SHIFT 0
+#define TSIZ_XFERSIZE_MASK (0x7ffff << 0)
+#define TSIZ_XFERSIZE_SHIFT 0
+
+#define HCDMA(_ch) HSOTG_REG(0x0514 + 0x20 * (_ch))
+
+#define HCDMAB(_ch) HSOTG_REG(0x051c + 0x20 * (_ch))
+
+#define HCFIFO(_ch) HSOTG_REG(0x1000 + 0x1000 * (_ch))
+
+/**
+ * struct dwc2_dma_desc - DMA descriptor structure,
+ * used for both host and gadget modes
+ *
+ * @status: DMA descriptor status quadlet
+ * @buf: DMA descriptor data buffer pointer
+ *
+ * DMA Descriptor structure contains two quadlets:
+ * Status quadlet and Data buffer pointer.
+ */
+struct dwc2_dma_desc {
+ uint32_t status;
+ uint32_t buf;
+} __packed;
+
+/* Host Mode DMA descriptor status quadlet */
+
+#define HOST_DMA_A BIT(31)
+#define HOST_DMA_STS_MASK (0x3 << 28)
+#define HOST_DMA_STS_SHIFT 28
+#define HOST_DMA_STS_PKTERR BIT(28)
+#define HOST_DMA_EOL BIT(26)
+#define HOST_DMA_IOC BIT(25)
+#define HOST_DMA_SUP BIT(24)
+#define HOST_DMA_ALT_QTD BIT(23)
+#define HOST_DMA_QTD_OFFSET_MASK (0x3f << 17)
+#define HOST_DMA_QTD_OFFSET_SHIFT 17
+#define HOST_DMA_ISOC_NBYTES_MASK (0xfff << 0)
+#define HOST_DMA_ISOC_NBYTES_SHIFT 0
+#define HOST_DMA_NBYTES_MASK (0x1ffff << 0)
+#define HOST_DMA_NBYTES_SHIFT 0
+#define HOST_DMA_NBYTES_LIMIT 131071
+
+/* Device Mode DMA descriptor status quadlet */
+
+#define DEV_DMA_BUFF_STS_MASK (0x3 << 30)
+#define DEV_DMA_BUFF_STS_SHIFT 30
+#define DEV_DMA_BUFF_STS_HREADY 0
+#define DEV_DMA_BUFF_STS_DMABUSY 1
+#define DEV_DMA_BUFF_STS_DMADONE 2
+#define DEV_DMA_BUFF_STS_HBUSY 3
+#define DEV_DMA_STS_MASK (0x3 << 28)
+#define DEV_DMA_STS_SHIFT 28
+#define DEV_DMA_STS_SUCC 0
+#define DEV_DMA_STS_BUFF_FLUSH 1
+#define DEV_DMA_STS_BUFF_ERR 3
+#define DEV_DMA_L BIT(27)
+#define DEV_DMA_SHORT BIT(26)
+#define DEV_DMA_IOC BIT(25)
+#define DEV_DMA_SR BIT(24)
+#define DEV_DMA_MTRF BIT(23)
+#define DEV_DMA_ISOC_PID_MASK (0x3 << 23)
+#define DEV_DMA_ISOC_PID_SHIFT 23
+#define DEV_DMA_ISOC_PID_DATA0 0
+#define DEV_DMA_ISOC_PID_DATA2 1
+#define DEV_DMA_ISOC_PID_DATA1 2
+#define DEV_DMA_ISOC_PID_MDATA 3
+#define DEV_DMA_ISOC_FRNUM_MASK (0x7ff << 12)
+#define DEV_DMA_ISOC_FRNUM_SHIFT 12
+#define DEV_DMA_ISOC_TX_NBYTES_MASK (0xfff << 0)
+#define DEV_DMA_ISOC_TX_NBYTES_LIMIT 0xfff
+#define DEV_DMA_ISOC_RX_NBYTES_MASK (0x7ff << 0)
+#define DEV_DMA_ISOC_RX_NBYTES_LIMIT 0x7ff
+#define DEV_DMA_ISOC_NBYTES_SHIFT 0
+#define DEV_DMA_NBYTES_MASK (0xffff << 0)
+#define DEV_DMA_NBYTES_SHIFT 0
+#define DEV_DMA_NBYTES_LIMIT 0xffff
+
+#define MAX_DMA_DESC_NUM_GENERIC 64
+#define MAX_DMA_DESC_NUM_HS_ISOC 256
+
+#endif /* __DWC2_HW_H__ */
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 30667631bc..eafa39f560 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -1199,7 +1199,6 @@ static inline int vmstate_register(VMStateIf *obj, int instance_id,
void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd,
void *opaque);
-struct MemoryRegion;
void vmstate_register_ram(struct MemoryRegion *memory, DeviceState *dev);
void vmstate_unregister_ram(struct MemoryRegion *memory, DeviceState *dev);
void vmstate_register_ram_global(struct MemoryRegion *memory);
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index e33ca5a911..c986cfd28b 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -96,6 +96,7 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict);
void hmp_info_numa(Monitor *mon, const QDict *qdict);
void hmp_info_memory_devices(Monitor *mon, const QDict *qdict);
void hmp_qom_list(Monitor *mon, const QDict *qdict);
+void hmp_qom_get(Monitor *mon, const QDict *qdict);
void hmp_qom_set(Monitor *mon, const QDict *qdict);
void hmp_info_qom_tree(Monitor *mon, const QDict *dict);
void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 26c0c802d1..3efccdba7e 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -15,6 +15,8 @@ extern const char *qemu_name;
extern QemuUUID qemu_uuid;
extern bool qemu_uuid_set;
+void qemu_add_data_dir(const char *path);
+
void qemu_add_exit_notifier(Notifier *notify);
void qemu_remove_exit_notifier(Notifier *notify);
diff --git a/include/tcg/tcg-op-gvec.h b/include/tcg/tcg-op-gvec.h
index cea6497341..c69a7de984 100644
--- a/include/tcg/tcg-op-gvec.h
+++ b/include/tcg/tcg-op-gvec.h
@@ -334,6 +334,10 @@ void tcg_gen_gvec_shri(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t shift, uint32_t oprsz, uint32_t maxsz);
void tcg_gen_gvec_sari(unsigned vece, uint32_t dofs, uint32_t aofs,
int64_t shift, uint32_t oprsz, uint32_t maxsz);
+void tcg_gen_gvec_rotli(unsigned vece, uint32_t dofs, uint32_t aofs,
+ int64_t shift, uint32_t oprsz, uint32_t maxsz);
+void tcg_gen_gvec_rotri(unsigned vece, uint32_t dofs, uint32_t aofs,
+ int64_t shift, uint32_t oprsz, uint32_t maxsz);
void tcg_gen_gvec_shls(unsigned vece, uint32_t dofs, uint32_t aofs,
TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz);
@@ -341,6 +345,8 @@ void tcg_gen_gvec_shrs(unsigned vece, uint32_t dofs, uint32_t aofs,
TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz);
void tcg_gen_gvec_sars(unsigned vece, uint32_t dofs, uint32_t aofs,
TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz);
+void tcg_gen_gvec_rotls(unsigned vece, uint32_t dofs, uint32_t aofs,
+ TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz);
/*
* Perform vector shift by vector element, modulo the element size.
@@ -352,6 +358,10 @@ void tcg_gen_gvec_shrv(unsigned vece, uint32_t dofs, uint32_t aofs,
uint32_t bofs, uint32_t oprsz, uint32_t maxsz);
void tcg_gen_gvec_sarv(unsigned vece, uint32_t dofs, uint32_t aofs,
uint32_t bofs, uint32_t oprsz, uint32_t maxsz);
+void tcg_gen_gvec_rotlv(unsigned vece, uint32_t dofs, uint32_t aofs,
+ uint32_t bofs, uint32_t oprsz, uint32_t maxsz);
+void tcg_gen_gvec_rotrv(unsigned vece, uint32_t dofs, uint32_t aofs,
+ uint32_t bofs, uint32_t oprsz, uint32_t maxsz);
void tcg_gen_gvec_cmp(TCGCond cond, unsigned vece, uint32_t dofs,
uint32_t aofs, uint32_t bofs,
@@ -388,5 +398,7 @@ void tcg_gen_vec_shr8i_i64(TCGv_i64 d, TCGv_i64 a, int64_t);
void tcg_gen_vec_shr16i_i64(TCGv_i64 d, TCGv_i64 a, int64_t);
void tcg_gen_vec_sar8i_i64(TCGv_i64 d, TCGv_i64 a, int64_t);
void tcg_gen_vec_sar16i_i64(TCGv_i64 d, TCGv_i64 a, int64_t);
+void tcg_gen_vec_rotl8i_i64(TCGv_i64 d, TCGv_i64 a, int64_t c);
+void tcg_gen_vec_rotl16i_i64(TCGv_i64 d, TCGv_i64 a, int64_t c);
#endif
diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h
index e3399d6a5e..5abf17fecc 100644
--- a/include/tcg/tcg-op.h
+++ b/include/tcg/tcg-op.h
@@ -999,14 +999,19 @@ void tcg_gen_umax_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b);
void tcg_gen_shli_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i);
void tcg_gen_shri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i);
void tcg_gen_sari_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i);
+void tcg_gen_rotli_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i);
+void tcg_gen_rotri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i);
void tcg_gen_shls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s);
void tcg_gen_shrs_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s);
void tcg_gen_sars_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s);
+void tcg_gen_rotls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s);
void tcg_gen_shlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s);
void tcg_gen_shrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s);
void tcg_gen_sarv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s);
+void tcg_gen_rotlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s);
+void tcg_gen_rotrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec s);
void tcg_gen_cmp_vec(TCGCond cond, unsigned vece, TCGv_vec r,
TCGv_vec a, TCGv_vec b);
diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
index 9288a04946..e3929b80d2 100644
--- a/include/tcg/tcg-opc.h
+++ b/include/tcg/tcg-opc.h
@@ -248,14 +248,18 @@ DEF(not_vec, 1, 1, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_not_vec))
DEF(shli_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_shi_vec))
DEF(shri_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_shi_vec))
DEF(sari_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_shi_vec))
+DEF(rotli_vec, 1, 1, 1, IMPLVEC | IMPL(TCG_TARGET_HAS_roti_vec))
DEF(shls_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec))
DEF(shrs_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec))
DEF(sars_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shs_vec))
+DEF(rotls_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_rots_vec))
DEF(shlv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shv_vec))
DEF(shrv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shv_vec))
DEF(sarv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_shv_vec))
+DEF(rotlv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_rotv_vec))
+DEF(rotrv_vec, 1, 2, 0, IMPLVEC | IMPL(TCG_TARGET_HAS_rotv_vec))
DEF(cmp_vec, 1, 2, 1, IMPLVEC)
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index c48bd76b0a..380014ed80 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -182,6 +182,9 @@ typedef uint64_t TCGRegSet;
#define TCG_TARGET_HAS_not_vec 0
#define TCG_TARGET_HAS_andc_vec 0
#define TCG_TARGET_HAS_orc_vec 0
+#define TCG_TARGET_HAS_roti_vec 0
+#define TCG_TARGET_HAS_rots_vec 0
+#define TCG_TARGET_HAS_rotv_vec 0
#define TCG_TARGET_HAS_shi_vec 0
#define TCG_TARGET_HAS_shs_vec 0
#define TCG_TARGET_HAS_shv_vec 0
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 01a9323a63..ebc663ea0b 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2073,12 +2073,14 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
exit(EXIT_FAILURE);
}
} else {
+#if HOST_LONG_BITS < TARGET_ABI_BITS
if ((guest_hiaddr - guest_base) > ~(uintptr_t)0) {
error_report("%s: requires more virtual address space "
"than the host can provide (0x%" PRIx64 ")",
image_name, (uint64_t)guest_hiaddr - guest_base);
exit(EXIT_FAILURE);
}
+#endif
}
/*
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 5b27f8603e..df71e15a25 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -267,6 +267,7 @@ void cpu_loop(CPUPPCState *env)
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
+ case POWERPC_EXCP_SYSCALL_VECTORED:
cpu_abort(cs, "Syscall exception while in user mode. "
"Aborting\n");
break;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 2d8125fa53..97de9fb5c9 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7653,30 +7653,33 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return -TARGET_ERESTARTSYS;
}
- cpu_list_lock();
+ pthread_mutex_lock(&clone_lock);
if (CPU_NEXT(first_cpu)) {
- TaskState *ts;
+ TaskState *ts = cpu->opaque;
- /* Remove the CPU from the list. */
- QTAILQ_REMOVE_RCU(&cpus, cpu, node);
+ object_property_set_bool(OBJECT(cpu), false, "realized", NULL);
+ object_unref(OBJECT(cpu));
+ /*
+ * At this point the CPU should be unrealized and removed
+ * from cpu lists. We can clean-up the rest of the thread
+ * data without the lock held.
+ */
- cpu_list_unlock();
+ pthread_mutex_unlock(&clone_lock);
- ts = cpu->opaque;
if (ts->child_tidptr) {
put_user_u32(0, ts->child_tidptr);
do_sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
NULL, NULL, 0);
}
thread_cpu = NULL;
- object_unref(OBJECT(cpu));
g_free(ts);
rcu_unregister_thread();
pthread_exit(NULL);
}
- cpu_list_unlock();
+ pthread_mutex_unlock(&clone_lock);
preexit_cleanup(cpu_env, arg1);
_exit(arg1);
return 0; /* avoid warning */
diff --git a/memory.c b/memory.c
index fd6f3d6aca..91ceaf9fcf 100644
--- a/memory.c
+++ b/memory.c
@@ -2197,15 +2197,21 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp
qemu_ram_resize(mr->ram_block, newsize, errp);
}
+void memory_region_msync(MemoryRegion *mr, hwaddr addr, hwaddr size)
+{
+ if (mr->ram_block) {
+ qemu_ram_msync(mr->ram_block, addr, size);
+ }
+}
-void memory_region_do_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size)
+void memory_region_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size)
{
/*
* Might be extended case needed to cover
* different types of memory regions
*/
- if (mr->ram_block && mr->dirty_log_mask) {
- qemu_ram_writeback(mr->ram_block, addr, size);
+ if (mr->dirty_log_mask) {
+ memory_region_msync(mr, addr, size);
}
}
diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
index 7eafface61..47bc0f650c 100644
--- a/migration/block-dirty-bitmap.c
+++ b/migration/block-dirty-bitmap.c
@@ -268,57 +268,118 @@ static void dirty_bitmap_mig_cleanup(void)
}
/* Called with iothread lock taken. */
-static int init_dirty_bitmap_migration(void)
+static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name)
{
- BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
DirtyBitmapMigBitmapState *dbms;
Error *local_err = NULL;
+ bitmap = bdrv_dirty_bitmap_first(bs);
+ if (!bitmap) {
+ return 0;
+ }
+
+ if (!bs_name || strcmp(bs_name, "") == 0) {
+ error_report("Bitmap '%s' in unnamed node can't be migrated",
+ bdrv_dirty_bitmap_name(bitmap));
+ return -1;
+ }
+
+ if (bs_name[0] == '#') {
+ error_report("Bitmap '%s' in a node with auto-generated "
+ "name '%s' can't be migrated",
+ bdrv_dirty_bitmap_name(bitmap), bs_name);
+ return -1;
+ }
+
+ FOR_EACH_DIRTY_BITMAP(bs, bitmap) {
+ if (!bdrv_dirty_bitmap_name(bitmap)) {
+ continue;
+ }
+
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, &local_err)) {
+ error_report_err(local_err);
+ return -1;
+ }
+
+ bdrv_ref(bs);
+ bdrv_dirty_bitmap_set_busy(bitmap, true);
+
+ dbms = g_new0(DirtyBitmapMigBitmapState, 1);
+ dbms->bs = bs;
+ dbms->node_name = bs_name;
+ dbms->bitmap = bitmap;
+ dbms->total_sectors = bdrv_nb_sectors(bs);
+ dbms->sectors_per_chunk = CHUNK_SIZE * 8 *
+ bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
+ if (bdrv_dirty_bitmap_enabled(bitmap)) {
+ dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED;
+ }
+ if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
+ dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT;
+ }
+
+ QSIMPLEQ_INSERT_TAIL(&dirty_bitmap_mig_state.dbms_list,
+ dbms, entry);
+ }
+
+ return 0;
+}
+
+/* Called with iothread lock taken. */
+static int init_dirty_bitmap_migration(void)
+{
+ BlockDriverState *bs;
+ DirtyBitmapMigBitmapState *dbms;
+ GHashTable *handled_by_blk = g_hash_table_new(NULL, NULL);
+ BlockBackend *blk;
+
dirty_bitmap_mig_state.bulk_completed = false;
dirty_bitmap_mig_state.prev_bs = NULL;
dirty_bitmap_mig_state.prev_bitmap = NULL;
dirty_bitmap_mig_state.no_bitmaps = false;
- for (bs = bdrv_next_all_states(NULL); bs; bs = bdrv_next_all_states(bs)) {
- const char *name = bdrv_get_device_or_node_name(bs);
+ /*
+ * Use blockdevice name for direct (or filtered) children of named block
+ * backends.
+ */
+ for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
+ const char *name = blk_name(blk);
- FOR_EACH_DIRTY_BITMAP(bs, bitmap) {
- if (!bdrv_dirty_bitmap_name(bitmap)) {
- continue;
- }
+ if (!name || strcmp(name, "") == 0) {
+ continue;
+ }
- if (!name || strcmp(name, "") == 0) {
- error_report("Found bitmap '%s' in unnamed node %p. It can't "
- "be migrated", bdrv_dirty_bitmap_name(bitmap), bs);
- goto fail;
+ bs = blk_bs(blk);
+
+ /* Skip filters without bitmaps */
+ while (bs && bs->drv && bs->drv->is_filter &&
+ !bdrv_has_named_bitmaps(bs))
+ {
+ if (bs->backing) {
+ bs = bs->backing->bs;
+ } else if (bs->file) {
+ bs = bs->file->bs;
+ } else {
+ bs = NULL;
}
+ }
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT,
- &local_err)) {
- error_report_err(local_err);
+ if (bs && bs->drv && !bs->drv->is_filter) {
+ if (add_bitmaps_to_list(bs, name)) {
goto fail;
}
+ g_hash_table_add(handled_by_blk, bs);
+ }
+ }
- bdrv_ref(bs);
- bdrv_dirty_bitmap_set_busy(bitmap, true);
-
- dbms = g_new0(DirtyBitmapMigBitmapState, 1);
- dbms->bs = bs;
- dbms->node_name = name;
- dbms->bitmap = bitmap;
- dbms->total_sectors = bdrv_nb_sectors(bs);
- dbms->sectors_per_chunk = CHUNK_SIZE * 8 *
- bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
- if (bdrv_dirty_bitmap_enabled(bitmap)) {
- dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED;
- }
- if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
- dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT;
- }
+ for (bs = bdrv_next_all_states(NULL); bs; bs = bdrv_next_all_states(bs)) {
+ if (g_hash_table_contains(handled_by_blk, bs)) {
+ continue;
+ }
- QSIMPLEQ_INSERT_TAIL(&dirty_bitmap_mig_state.dbms_list,
- dbms, entry);
+ if (add_bitmaps_to_list(bs, bdrv_get_node_name(bs))) {
+ goto fail;
}
}
@@ -331,9 +392,12 @@ static int init_dirty_bitmap_migration(void)
dirty_bitmap_mig_state.no_bitmaps = true;
}
+ g_hash_table_destroy(handled_by_blk);
+
return 0;
fail:
+ g_hash_table_destroy(handled_by_blk);
dirty_bitmap_mig_cleanup();
return -1;
diff --git a/migration/colo.c b/migration/colo.c
index d015d4f84e..ea7d1e9d4e 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -436,11 +436,6 @@ static int colo_do_checkpoint_transaction(MigrationState *s,
goto out;
}
- colo_notify_compares_event(NULL, COLO_EVENT_CHECKPOINT, &local_err);
- if (local_err) {
- goto out;
- }
-
/* Disable block migration */
migrate_set_block_enabled(false, &local_err);
if (local_err) {
@@ -502,6 +497,12 @@ static int colo_do_checkpoint_transaction(MigrationState *s,
goto out;
}
+ qemu_event_reset(&s->colo_checkpoint_event);
+ colo_notify_compares_event(NULL, COLO_EVENT_CHECKPOINT, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
colo_receive_check_message(s->rp_state.from_dst_file,
COLO_MESSAGE_VMSTATE_LOADED, &local_err);
if (local_err) {
@@ -589,7 +590,7 @@ static void colo_process_checkpoint(MigrationState *s)
goto out;
}
- qemu_sem_wait(&s->colo_checkpoint_sem);
+ qemu_event_wait(&s->colo_checkpoint_event);
if (s->state != MIGRATION_STATUS_COLO) {
goto out;
@@ -637,7 +638,7 @@ out:
colo_compare_unregister_notifier(&packets_compare_notifier);
timer_del(s->colo_delay_timer);
timer_free(s->colo_delay_timer);
- qemu_sem_destroy(&s->colo_checkpoint_sem);
+ qemu_event_destroy(&s->colo_checkpoint_event);
/*
* Must be called after failover BH is completed,
@@ -654,7 +655,7 @@ void colo_checkpoint_notify(void *opaque)
MigrationState *s = opaque;
int64_t next_notify_time;
- qemu_sem_post(&s->colo_checkpoint_sem);
+ qemu_event_set(&s->colo_checkpoint_event);
s->colo_checkpoint_time = qemu_clock_get_ms(QEMU_CLOCK_HOST);
next_notify_time = s->colo_checkpoint_time +
s->parameters.x_checkpoint_delay;
@@ -664,7 +665,7 @@ void colo_checkpoint_notify(void *opaque)
void migrate_start_colo_process(MigrationState *s)
{
qemu_mutex_unlock_iothread();
- qemu_sem_init(&s->colo_checkpoint_sem, 0);
+ qemu_event_init(&s->colo_checkpoint_event, false);
s->colo_delay_timer = timer_new_ms(QEMU_CLOCK_HOST,
colo_checkpoint_notify, s);
@@ -704,7 +705,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis,
}
qemu_mutex_lock_iothread();
- cpu_synchronize_all_pre_loadvm();
+ cpu_synchronize_all_states();
ret = qemu_loadvm_state_main(mis->from_src_file, mis);
qemu_mutex_unlock_iothread();
@@ -747,9 +748,11 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis,
qemu_mutex_lock_iothread();
vmstate_loading = true;
+ colo_flush_ram_cache();
ret = qemu_load_device_state(fb);
if (ret < 0) {
error_setg(errp, "COLO: load device state failed");
+ vmstate_loading = false;
qemu_mutex_unlock_iothread();
return;
}
@@ -758,6 +761,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis,
replication_get_error_all(&local_err);
if (local_err) {
error_propagate(errp, local_err);
+ vmstate_loading = false;
qemu_mutex_unlock_iothread();
return;
}
@@ -766,6 +770,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis,
replication_do_checkpoint_all(&local_err);
if (local_err) {
error_propagate(errp, local_err);
+ vmstate_loading = false;
qemu_mutex_unlock_iothread();
return;
}
@@ -777,6 +782,7 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis,
if (local_err) {
error_propagate(errp, local_err);
+ vmstate_loading = false;
qemu_mutex_unlock_iothread();
return;
}
@@ -787,9 +793,6 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis,
qemu_mutex_unlock_iothread();
if (failover_get_state() == FAILOVER_STATUS_RELAUNCH) {
- failover_set_state(FAILOVER_STATUS_RELAUNCH,
- FAILOVER_STATUS_NONE);
- failover_request_active(NULL);
return;
}
@@ -888,6 +891,14 @@ void *colo_process_incoming_thread(void *opaque)
error_report_err(local_err);
break;
}
+
+ if (failover_get_state() == FAILOVER_STATUS_RELAUNCH) {
+ failover_set_state(FAILOVER_STATUS_RELAUNCH,
+ FAILOVER_STATUS_NONE);
+ failover_request_active(NULL);
+ break;
+ }
+
if (failover_get_state() != FAILOVER_STATUS_NONE) {
error_report("failover request");
break;
@@ -895,8 +906,6 @@ void *colo_process_incoming_thread(void *opaque)
}
out:
- vmstate_loading = false;
-
/*
* There are only two reasons we can get here, some error happened
* or the user triggered failover.
diff --git a/migration/migration.c b/migration/migration.c
index 0bb042a0f7..b63ad91d34 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -3361,6 +3361,10 @@ bool migration_rate_limit(void)
bool urgent = false;
migration_update_counters(s, now);
if (qemu_file_rate_limit(s->to_dst_file)) {
+
+ if (qemu_file_get_error(s->to_dst_file)) {
+ return false;
+ }
/*
* Wait for a delay to do rate limiting OR
* something urgent to post the semaphore.
diff --git a/migration/migration.h b/migration/migration.h
index 507284e563..f617960522 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -215,8 +215,8 @@ struct MigrationState
/* The semaphore is used to notify COLO thread that failover is finished */
QemuSemaphore colo_exit_sem;
- /* The semaphore is used to notify COLO thread to do checkpoint */
- QemuSemaphore colo_checkpoint_sem;
+ /* The event is used to notify COLO thread to do checkpoint */
+ QemuEvent colo_checkpoint_event;
int64_t colo_checkpoint_time;
QEMUTimer *colo_delay_timer;
diff --git a/migration/ram.c b/migration/ram.c
index 859f835f1a..41cc530d9d 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3360,7 +3360,7 @@ static bool postcopy_is_running(void)
* Flush content of RAM cache into SVM's memory.
* Only flush the pages that be dirtied by PVM or SVM or both.
*/
-static void colo_flush_ram_cache(void)
+void colo_flush_ram_cache(void)
{
RAMBlock *block = NULL;
void *dst_host;
@@ -3632,9 +3632,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
}
trace_ram_load_complete(ret, seq_iter);
- if (!ret && migration_incoming_in_colo_state()) {
- colo_flush_ram_cache();
- }
return ret;
}
diff --git a/migration/ram.h b/migration/ram.h
index 5ceaff7cb4..2eeaacfa13 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -65,6 +65,7 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb);
/* ram cache */
int colo_init_ram_cache(void);
+void colo_flush_ram_cache(void);
void colo_release_ram_cache(void);
void colo_incoming_start_dirty_log(void);
diff --git a/migration/rdma.c b/migration/rdma.c
index 967fda5b0c..ec45d33ba3 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -4056,7 +4056,9 @@ void rdma_start_incoming_migration(const char *host_port, Error **errp)
return;
err:
error_propagate(errp, local_err);
- g_free(rdma->host);
+ if (rdma) {
+ g_free(rdma->host);
+ }
g_free(rdma);
g_free(rdma_return_path);
}
@@ -4092,20 +4094,20 @@ void rdma_start_outgoing_migration(void *opaque,
rdma_return_path = qemu_rdma_data_init(host_port, errp);
if (rdma_return_path == NULL) {
- goto err;
+ goto return_path_err;
}
ret = qemu_rdma_source_init(rdma_return_path,
s->enabled_capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp);
if (ret) {
- goto err;
+ goto return_path_err;
}
ret = qemu_rdma_connect(rdma_return_path, errp);
if (ret) {
- goto err;
+ goto return_path_err;
}
rdma->return_path = rdma_return_path;
@@ -4118,6 +4120,8 @@ void rdma_start_outgoing_migration(void *opaque,
s->to_dst_file = qemu_fopen_rdma(rdma, "wb");
migrate_fd_connect(s, NULL);
return;
+return_path_err:
+ qemu_rdma_cleanup(rdma);
err:
g_free(rdma);
g_free(rdma_return_path);
diff --git a/python/qemu/.flake8 b/python/qemu/.flake8
new file mode 100644
index 0000000000..45d8146f3f
--- /dev/null
+++ b/python/qemu/.flake8
@@ -0,0 +1,2 @@
+[flake8]
+extend-ignore = E722 # Pylint handles this, but smarter. \ No newline at end of file
diff --git a/python/qemu/accel.py b/python/qemu/accel.py
index 36ae85791e..7fabe62920 100644
--- a/python/qemu/accel.py
+++ b/python/qemu/accel.py
@@ -23,11 +23,12 @@ LOG = logging.getLogger(__name__)
# Mapping host architecture to any additional architectures it can
# support which often includes its 32 bit cousin.
ADDITIONAL_ARCHES = {
- "x86_64" : "i386",
- "aarch64" : "armhf",
- "ppc64le" : "ppc64",
+ "x86_64": "i386",
+ "aarch64": "armhf",
+ "ppc64le": "ppc64",
}
+
def list_accel(qemu_bin):
"""
List accelerators enabled in the QEMU binary.
@@ -47,6 +48,7 @@ def list_accel(qemu_bin):
# Skip the first line which is the header.
return [acc.strip() for acc in out.splitlines()[1:]]
+
def kvm_available(target_arch=None, qemu_bin=None):
"""
Check if KVM is available using the following heuristic:
@@ -69,6 +71,7 @@ def kvm_available(target_arch=None, qemu_bin=None):
return False
return True
+
def tcg_available(qemu_bin):
"""
Check if TCG is available.
diff --git a/python/qemu/machine.py b/python/qemu/machine.py
index b9a98e2c86..041c615052 100644
--- a/python/qemu/machine.py
+++ b/python/qemu/machine.py
@@ -24,11 +24,14 @@ import subprocess
import shutil
import socket
import tempfile
+from typing import Optional, Type
+from types import TracebackType
from . import qmp
LOG = logging.getLogger(__name__)
+
class QEMUMachineError(Exception):
"""
Exception called when an error in QEMUMachine happens.
@@ -54,15 +57,16 @@ class MonitorResponseError(qmp.QMPError):
desc = reply["error"]["desc"]
except KeyError:
desc = reply
- super(MonitorResponseError, self).__init__(desc)
+ super().__init__(desc)
self.reply = reply
-class QEMUMachine(object):
+class QEMUMachine:
"""
A QEMU VM
- Use this object as a context manager to ensure the QEMU process terminates::
+ Use this object as a context manager to ensure
+ the QEMU process terminates::
with VM(binary) as vm:
...
@@ -119,15 +123,14 @@ class QEMUMachine(object):
self._console_socket = None
self._remove_files = []
- # just in case logging wasn't configured by the main script:
- logging.basicConfig()
-
def __enter__(self):
return self
- def __exit__(self, exc_type, exc_val, exc_tb):
+ def __exit__(self,
+ exc_type: Optional[Type[BaseException]],
+ exc_val: Optional[BaseException],
+ exc_tb: Optional[TracebackType]) -> None:
self.shutdown()
- return False
def add_monitor_null(self):
"""
@@ -188,8 +191,10 @@ class QEMUMachine(object):
fd_param.append(str(fd))
devnull = open(os.path.devnull, 'rb')
- proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT, close_fds=False)
+ proc = subprocess.Popen(
+ fd_param, stdin=devnull, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, close_fds=False
+ )
output = proc.communicate()[0]
if output:
LOG.debug(output)
@@ -242,7 +247,7 @@ class QEMUMachine(object):
'chardev=mon,mode=control'])
if self._machine is not None:
args.extend(['-machine', self._machine])
- for i in range(self._console_index):
+ for _ in range(self._console_index):
args.extend(['-serial', 'null'])
if self._console_set:
self._console_address = os.path.join(self._sock_dir,
@@ -342,7 +347,7 @@ class QEMUMachine(object):
self._load_io_log()
self._post_shutdown()
- def shutdown(self, has_quit=False):
+ def shutdown(self, has_quit=False, hard=False):
"""
Terminate the VM and clean up
"""
@@ -354,7 +359,9 @@ class QEMUMachine(object):
self._console_socket = None
if self.is_running():
- if self._qmp:
+ if hard:
+ self._popen.kill()
+ elif self._qmp:
try:
if not has_quit:
self._qmp.cmd('quit')
@@ -368,16 +375,20 @@ class QEMUMachine(object):
self._post_shutdown()
exitcode = self.exitcode()
- if exitcode is not None and exitcode < 0:
+ if exitcode is not None and exitcode < 0 and \
+ not (exitcode == -9 and hard):
msg = 'qemu received signal %i: %s'
if self._qemu_full_args:
command = ' '.join(self._qemu_full_args)
else:
command = ''
- LOG.warning(msg, -exitcode, command)
+ LOG.warning(msg, -int(exitcode), command)
self._launched = False
+ def kill(self):
+ self.shutdown(hard=True)
+
def set_qmp_monitor(self, enabled=True):
"""
Set the QMP monitor.
@@ -482,7 +493,8 @@ class QEMUMachine(object):
def events_wait(self, events, timeout=60.0):
"""
- events_wait waits for and returns a named event from QMP with a timeout.
+ events_wait waits for and returns a named event
+ from QMP with a timeout.
events: a sequence of (name, match_criteria) tuples.
The match criteria are optional and may be None.
diff --git a/python/qemu/pylintrc b/python/qemu/pylintrc
new file mode 100644
index 0000000000..5d6ae7367d
--- /dev/null
+++ b/python/qemu/pylintrc
@@ -0,0 +1,58 @@
+[MASTER]
+
+[MESSAGES CONTROL]
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once). You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable=too-many-arguments,
+ too-many-instance-attributes,
+ too-many-public-methods,
+
+[REPORTS]
+
+[REFACTORING]
+
+[MISCELLANEOUS]
+
+[LOGGING]
+
+[BASIC]
+
+# Good variable names which should always be accepted, separated by a comma.
+good-names=i,
+ j,
+ k,
+ ex,
+ Run,
+ _,
+ fd,
+
+[VARIABLES]
+
+[STRING]
+
+[SPELLING]
+
+[FORMAT]
+
+[SIMILARITIES]
+
+# Ignore imports when computing similarities.
+ignore-imports=yes
+
+[TYPECHECK]
+
+[CLASSES]
+
+[IMPORTS]
+
+[DESIGN]
+
+[EXCEPTIONS]
diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py
index d6c9b2f4b1..e64b6b5faa 100644
--- a/python/qemu/qmp.py
+++ b/python/qemu/qmp.py
@@ -11,6 +11,12 @@ import json
import errno
import socket
import logging
+from typing import (
+ Optional,
+ TextIO,
+ Type,
+)
+from types import TracebackType
class QMPError(Exception):
@@ -61,7 +67,7 @@ class QEMUMonitorProtocol:
self.__events = []
self.__address = address
self.__sock = self.__get_sock()
- self.__sockfile = None
+ self.__sockfile: Optional[TextIO] = None
self._nickname = nickname
if self._nickname:
self.logger = logging.getLogger('QMP').getChild(self._nickname)
@@ -88,6 +94,7 @@ class QEMUMonitorProtocol:
raise QMPCapabilitiesError
def __json_read(self, only_event=False):
+ assert self.__sockfile is not None
while True:
data = self.__sockfile.readline()
if not data:
@@ -114,14 +121,14 @@ class QEMUMonitorProtocol:
"""
# Check for new events regardless and pull them into the cache:
- self.__sock.setblocking(0)
+ self.__sock.setblocking(False)
try:
self.__json_read()
except OSError as err:
if err.errno == errno.EAGAIN:
# No data available
pass
- self.__sock.setblocking(1)
+ self.__sock.setblocking(True)
# Wait for new events, if needed.
# if wait is 0.0, this means "no wait" and is also implicitly false.
@@ -142,10 +149,14 @@ class QEMUMonitorProtocol:
# Implement context manager enter function.
return self
- def __exit__(self, exc_type, exc_value, exc_traceback):
+ def __exit__(self,
+ # pylint: disable=duplicate-code
+ # see https://github.com/PyCQA/pylint/issues/3619
+ exc_type: Optional[Type[BaseException]],
+ exc_val: Optional[BaseException],
+ exc_tb: Optional[TracebackType]) -> None:
# Implement context manager exit function.
self.close()
- return False
def connect(self, negotiate=True):
"""
@@ -157,7 +168,7 @@ class QEMUMonitorProtocol:
@raise QMPCapabilitiesError if fails to negotiate capabilities
"""
self.__sock.connect(self.__address)
- self.__sockfile = self.__sock.makefile()
+ self.__sockfile = self.__sock.makefile(mode='r')
if negotiate:
return self.__negotiate_capabilities()
return None
@@ -168,8 +179,8 @@ class QEMUMonitorProtocol:
@param timeout: timeout in seconds (nonnegative float number, or
None). The value passed will set the behavior of the
- underneath QMP socket as described in [1]. Default value
- is set to 15.0.
+ underneath QMP socket as described in [1].
+ Default value is set to 15.0.
@return QMP greeting dict
@raise OSError on socket connection errors
@raise QMPConnectError if the greeting is not received
@@ -180,7 +191,7 @@ class QEMUMonitorProtocol:
"""
self.__sock.settimeout(timeout)
self.__sock, _ = self.__sock.accept()
- self.__sockfile = self.__sock.makefile()
+ self.__sockfile = self.__sock.makefile(mode='r')
return self.__negotiate_capabilities()
def cmd_obj(self, qmp_cmd):
diff --git a/python/qemu/qtest.py b/python/qemu/qtest.py
index d24ad04256..888c8bd2f6 100644
--- a/python/qemu/qtest.py
+++ b/python/qemu/qtest.py
@@ -1,5 +1,11 @@
-# QEMU qtest library
-#
+"""
+QEMU qtest library
+
+qtest offers the QEMUQtestProtocol and QEMUQTestMachine classes, which
+offer a connection to QEMU's qtest protocol socket, and a qtest-enabled
+subclass of QEMUMachine, respectively.
+"""
+
# Copyright (C) 2015 Red Hat Inc.
#
# Authors:
@@ -13,26 +19,29 @@
import socket
import os
+from typing import Optional, TextIO
from .machine import QEMUMachine
-class QEMUQtestProtocol(object):
- def __init__(self, address, server=False):
- """
- Create a QEMUQtestProtocol object.
+class QEMUQtestProtocol:
+ """
+ QEMUQtestProtocol implements a connection to a qtest socket.
- @param address: QEMU address, can be either a unix socket path (string)
- or a tuple in the form ( address, port ) for a TCP
- connection
- @param server: server mode, listens on the socket (bool)
- @raise socket.error on socket connection errors
- @note No connection is established, this is done by the connect() or
- accept() methods
- """
+ :param address: QEMU address, can be either a unix socket path (string)
+ or a tuple in the form ( address, port ) for a TCP
+ connection
+ :param server: server mode, listens on the socket (bool)
+ :raise socket.error: on socket connection errors
+
+ .. note::
+ No conection is estabalished by __init__(), this is done
+ by the connect() or accept() methods.
+ """
+ def __init__(self, address, server=False):
self._address = address
self._sock = self._get_sock()
- self._sockfile = None
+ self._sockfile: Optional[TextIO] = None
if server:
self._sock.bind(self._address)
self._sock.listen(1)
@@ -51,7 +60,7 @@ class QEMUQtestProtocol(object):
@raise socket.error on socket connection errors
"""
self._sock.connect(self._address)
- self._sockfile = self._sock.makefile()
+ self._sockfile = self._sock.makefile(mode='r')
def accept(self):
"""
@@ -60,7 +69,7 @@ class QEMUQtestProtocol(object):
@raise socket.error on socket connection errors
"""
self._sock, _ = self._sock.accept()
- self._sockfile = self._sock.makefile()
+ self._sockfile = self._sock.makefile(mode='r')
def cmd(self, qtest_cmd):
"""
@@ -68,20 +77,27 @@ class QEMUQtestProtocol(object):
@param qtest_cmd: qtest command text to be sent
"""
+ assert self._sockfile is not None
self._sock.sendall((qtest_cmd + "\n").encode('utf-8'))
resp = self._sockfile.readline()
return resp
def close(self):
+ """Close this socket."""
self._sock.close()
- self._sockfile.close()
+ if self._sockfile:
+ self._sockfile.close()
+ self._sockfile = None
def settimeout(self, timeout):
+ """Set a timeout, in seconds."""
self._sock.settimeout(timeout)
class QEMUQtestMachine(QEMUMachine):
- '''A QEMU VM'''
+ """
+ A QEMU VM, with a qtest socket available.
+ """
def __init__(self, binary, args=None, name=None, test_dir="/var/tmp",
socket_scm_helper=None, sock_dir=None):
@@ -89,31 +105,38 @@ class QEMUQtestMachine(QEMUMachine):
name = "qemu-%d" % os.getpid()
if sock_dir is None:
sock_dir = test_dir
- super(QEMUQtestMachine,
- self).__init__(binary, args, name=name, test_dir=test_dir,
- socket_scm_helper=socket_scm_helper,
- sock_dir=sock_dir)
+ super().__init__(binary, args, name=name, test_dir=test_dir,
+ socket_scm_helper=socket_scm_helper,
+ sock_dir=sock_dir)
self._qtest = None
self._qtest_path = os.path.join(sock_dir, name + "-qtest.sock")
def _base_args(self):
- args = super(QEMUQtestMachine, self)._base_args()
+ args = super()._base_args()
args.extend(['-qtest', 'unix:path=' + self._qtest_path,
'-accel', 'qtest'])
return args
def _pre_launch(self):
- super(QEMUQtestMachine, self)._pre_launch()
+ super()._pre_launch()
self._qtest = QEMUQtestProtocol(self._qtest_path, server=True)
- def _post_launch(self):
- super(QEMUQtestMachine, self)._post_launch()
+ def _post_launch(self) -> None:
+ assert self._qtest is not None
+ super()._post_launch()
self._qtest.accept()
def _post_shutdown(self):
- super(QEMUQtestMachine, self)._post_shutdown()
+ super()._post_shutdown()
self._remove_if_exists(self._qtest_path)
- def qtest(self, cmd):
- '''Send a qtest command to guest'''
+ def qtest(self, cmd: str) -> str:
+ """
+ Send a qtest command to the guest.
+
+ :param cmd: qtest command to send
+ :return: qtest server response
+ """
+ if self._qtest is None:
+ raise RuntimeError("qtest socket not available")
return self._qtest.cmd(cmd)
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 6fbacddab2..0e1c6a59f2 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -636,18 +636,24 @@
# efficiently so file size may be smaller than virtual disk size.
#
# The values are upper bounds that are guaranteed to fit the new image file.
-# Subsequent modification, such as internal snapshot or bitmap creation, may
-# require additional space and is not covered here.
+# Subsequent modification, such as internal snapshot or further bitmap
+# creation, may require additional space and is not covered here.
#
-# @required: Size required for a new image file, in bytes.
+# @required: Size required for a new image file, in bytes, when copying just
+# allocated guest-visible contents.
#
# @fully-allocated: Image file size, in bytes, once data has been written
-# to all sectors.
+# to all sectors, when copying just guest-visible contents.
+#
+# @bitmaps: Additional size required if all the top-level bitmap metadata
+# in the source image were to be copied to the destination,
+# present only when source and destination both support
+# persistent bitmaps. (since 5.1)
#
# Since: 2.10
##
{ 'struct': 'BlockMeasureInfo',
- 'data': {'required': 'int', 'fully-allocated': 'int'} }
+ 'data': {'required': 'int', 'fully-allocated': 'int', '*bitmaps': 'int'} }
##
# @query-block:
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index a87d3cb264..10b910b67c 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -46,9 +46,9 @@ SRST
ERST
DEF("convert", img_convert,
- "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
+ "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
SRST
-.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
+.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
ERST
DEF("create", img_create,
diff --git a/qemu-img.c b/qemu-img.c
index 2d30682f12..d7e846e607 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -78,6 +78,7 @@ enum {
OPTION_ENABLE = 272,
OPTION_DISABLE = 273,
OPTION_MERGE = 274,
+ OPTION_BITMAPS = 275,
};
typedef enum OutputFormat {
@@ -191,6 +192,7 @@ static void QEMU_NORETURN help(void)
" hiding corruption that has already occurred.\n"
"\n"
"Parameters to convert subcommand:\n"
+ " '--bitmaps' copies all top-level persistent bitmaps to destination\n"
" '-m' specifies how many coroutines work in parallel during the convert\n"
" process (defaults to 8)\n"
" '-W' allow to write to the target out of order rather than sequential\n"
@@ -1638,6 +1640,24 @@ out4:
return ret;
}
+/* Convenience wrapper around qmp_block_dirty_bitmap_merge */
+static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name,
+ const char *src_node, const char *src_name,
+ Error **errp)
+{
+ BlockDirtyBitmapMergeSource *merge_src;
+ BlockDirtyBitmapMergeSourceList *list;
+
+ merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
+ merge_src->type = QTYPE_QDICT;
+ merge_src->u.external.node = g_strdup(src_node);
+ merge_src->u.external.name = g_strdup(src_name);
+ list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
+ list->value = merge_src;
+ qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp);
+ qapi_free_BlockDirtyBitmapMergeSourceList(list);
+}
+
enum ImgConvertBlockStatus {
BLK_DATA,
BLK_ZERO,
@@ -2121,6 +2141,39 @@ static int convert_do_copy(ImgConvertState *s)
return s->ret;
}
+static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst)
+{
+ BdrvDirtyBitmap *bm;
+ Error *err = NULL;
+
+ FOR_EACH_DIRTY_BITMAP(src, bm) {
+ const char *name;
+
+ if (!bdrv_dirty_bitmap_get_persistence(bm)) {
+ continue;
+ }
+ name = bdrv_dirty_bitmap_name(bm);
+ qmp_block_dirty_bitmap_add(dst->node_name, name,
+ true, bdrv_dirty_bitmap_granularity(bm),
+ true, true,
+ true, !bdrv_dirty_bitmap_enabled(bm),
+ &err);
+ if (err) {
+ error_reportf_err(err, "Failed to create bitmap %s: ", name);
+ return -1;
+ }
+
+ do_dirty_bitmap_merge(dst->node_name, name, src->node_name, name,
+ &err);
+ if (err) {
+ error_reportf_err(err, "Failed to populate bitmap %s: ", name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
#define MAX_BUF_SECTORS 32768
static int img_convert(int argc, char **argv)
@@ -2142,6 +2195,7 @@ static int img_convert(int argc, char **argv)
int64_t ret = -EINVAL;
bool force_share = false;
bool explict_min_sparse = false;
+ bool bitmaps = false;
ImgConvertState s = (ImgConvertState) {
/* Need at least 4k of zeros for sparse detection */
@@ -2161,6 +2215,7 @@ static int img_convert(int argc, char **argv)
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
{"salvage", no_argument, 0, OPTION_SALVAGE},
{"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
+ {"bitmaps", no_argument, 0, OPTION_BITMAPS},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
@@ -2286,6 +2341,9 @@ static int img_convert(int argc, char **argv)
*/
s.has_zero_init = true;
break;
+ case OPTION_BITMAPS:
+ bitmaps = true;
+ break;
}
}
@@ -2347,7 +2405,6 @@ static int img_convert(int argc, char **argv)
goto fail_getopt;
}
-
/* ret is still -EINVAL until here */
ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
if (ret < 0) {
@@ -2507,6 +2564,20 @@ static int img_convert(int argc, char **argv)
}
}
+ /* Determine if bitmaps need copying */
+ if (bitmaps) {
+ if (s.src_num > 1) {
+ error_report("Copying bitmaps only possible with single source");
+ ret = -1;
+ goto out;
+ }
+ if (!bdrv_supports_persistent_dirty_bitmap(blk_bs(s.src[0]))) {
+ error_report("Source lacks bitmap support");
+ ret = -1;
+ goto out;
+ }
+ }
+
/*
* The later open call will need any decryption secrets, and
* bdrv_create() will purge "opts", so extract them now before
@@ -2515,9 +2586,7 @@ static int img_convert(int argc, char **argv)
if (!skip_create) {
open_opts = qdict_new();
qemu_opt_foreach(opts, img_add_key_secrets, open_opts, &error_abort);
- }
- if (!skip_create) {
/* Create the new image */
ret = bdrv_create(drv, out_filename, opts, &local_err);
if (ret < 0) {
@@ -2555,6 +2624,13 @@ static int img_convert(int argc, char **argv)
}
out_bs = blk_bs(s.target);
+ if (bitmaps && !bdrv_supports_persistent_dirty_bitmap(out_bs)) {
+ error_report("Format driver '%s' does not support bitmaps",
+ out_bs->drv->format_name);
+ ret = -1;
+ goto out;
+ }
+
if (s.compressed && !block_driver_can_compress(out_bs->drv)) {
error_report("Compression not supported for this file format");
ret = -1;
@@ -2614,6 +2690,12 @@ static int img_convert(int argc, char **argv)
}
ret = convert_do_copy(&s);
+
+ /* Now copy the bitmaps */
+ if (bitmaps && ret == 0) {
+ ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs);
+ }
+
out:
if (!ret) {
qemu_progress_print(100, 0);
@@ -4714,21 +4796,11 @@ static int img_bitmap(int argc, char **argv)
qmp_block_dirty_bitmap_disable(bs->node_name, bitmap, &err);
op = "disable";
break;
- case BITMAP_MERGE: {
- BlockDirtyBitmapMergeSource *merge_src;
- BlockDirtyBitmapMergeSourceList *list;
-
- merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
- merge_src->type = QTYPE_QDICT;
- merge_src->u.external.node = g_strdup(src_bs->node_name);
- merge_src->u.external.name = g_strdup(act->src);
- list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
- list->value = merge_src;
- qmp_block_dirty_bitmap_merge(bs->node_name, bitmap, list, &err);
- qapi_free_BlockDirtyBitmapMergeSourceList(list);
+ case BITMAP_MERGE:
+ do_dirty_bitmap_merge(bs->node_name, bitmap, src_bs->node_name,
+ act->src, &err);
op = "merge";
break;
- }
default:
g_assert_not_reached();
}
@@ -5302,6 +5374,9 @@ static int img_measure(int argc, char **argv)
if (output_format == OFORMAT_HUMAN) {
printf("required size: %" PRIu64 "\n", info->required);
printf("fully allocated size: %" PRIu64 "\n", info->fully_allocated);
+ if (info->has_bitmaps) {
+ printf("bitmaps size: %" PRIu64 "\n", info->bitmaps);
+ }
} else {
dump_json_block_measure_info(info);
}
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 306e44fb0a..d2657b8db5 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -856,8 +856,7 @@ int main(int argc, char **argv)
}
tlscreds = nbd_get_tls_creds(tlscredsid, list, &local_err);
if (local_err) {
- error_report("Failed to get TLS creds %s",
- error_get_pretty(local_err));
+ error_reportf_err(local_err, "Failed to get TLS creds: ");
exit(EXIT_FAILURE);
}
} else {
@@ -983,8 +982,8 @@ int main(int argc, char **argv)
&local_err);
if (sioc == NULL) {
object_unref(OBJECT(server));
- error_report("Failed to use socket activation: %s",
- error_get_pretty(local_err));
+ error_reportf_err(local_err,
+ "Failed to use socket activation: ");
exit(EXIT_FAILURE);
}
qio_net_listener_add(server, sioc);
diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c
index cd08233a4c..f704b6949a 100644
--- a/qom/qom-hmp-cmds.c
+++ b/qom/qom-hmp-cmds.c
@@ -12,6 +12,8 @@
#include "qapi/error.h"
#include "qapi/qapi-commands-qom.h"
#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
+#include "qapi/qmp/qstring.h"
#include "qom/object.h"
void hmp_qom_list(Monitor *mon, const QDict *qdict)
@@ -46,19 +48,29 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict)
const char *property = qdict_get_str(qdict, "property");
const char *value = qdict_get_str(qdict, "value");
Error *err = NULL;
- bool ambiguous = false;
- Object *obj;
+ QObject *obj;
- obj = object_resolve_path(path, &ambiguous);
- if (obj == NULL) {
- error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", path);
- } else {
- if (ambiguous) {
- monitor_printf(mon, "Warning: Path '%s' is ambiguous\n", path);
- }
- object_property_parse(obj, value, property, &err);
+ obj = qobject_from_json(value, &err);
+ if (err == NULL) {
+ qmp_qom_set(path, property, obj, &err);
+ }
+
+ hmp_handle_error(mon, err);
+}
+
+void hmp_qom_get(Monitor *mon, const QDict *qdict)
+{
+ const char *path = qdict_get_str(qdict, "path");
+ const char *property = qdict_get_str(qdict, "property");
+ Error *err = NULL;
+ QObject *obj = qmp_qom_get(path, property, &err);
+
+ if (err == NULL) {
+ QString *str = qobject_to_json_pretty(obj);
+ monitor_printf(mon, "%s\n", qstring_get_str(str));
+ qobject_unref(str);
}
+
hmp_handle_error(mon, err);
}
diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py
index 96a31d3974..95838cbff3 100755
--- a/scripts/analyze-migration.py
+++ b/scripts/analyze-migration.py
@@ -25,11 +25,6 @@ import struct
import sys
-MIN_PYTHON = (3, 2)
-if sys.version_info < MIN_PYTHON:
- sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON)
-
-
def mkdir_p(path):
try:
os.makedirs(path)
diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index 46ab917807..f9d204aa36 100755
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -75,13 +75,6 @@ def output(*args):
output_fd.write(a)
-if sys.version_info >= (3, 4):
- re_fullmatch = re.fullmatch
-else:
- def re_fullmatch(pat, str):
- return re.match('^' + pat + '$', str)
-
-
def output_autogen():
output('/* This file is autogenerated by scripts/decodetree.py. */\n\n')
@@ -428,18 +421,18 @@ def parse_field(lineno, name, toks):
width = 0
func = None
for t in toks:
- if re_fullmatch('!function=' + re_ident, t):
+ if re.fullmatch('!function=' + re_ident, t):
if func:
error(lineno, 'duplicate function')
func = t.split('=')
func = func[1]
continue
- if re_fullmatch('[0-9]+:s[0-9]+', t):
+ if re.fullmatch('[0-9]+:s[0-9]+', t):
# Signed field extract
subtoks = t.split(':s')
sign = True
- elif re_fullmatch('[0-9]+:[0-9]+', t):
+ elif re.fullmatch('[0-9]+:[0-9]+', t):
# Unsigned field extract
subtoks = t.split(':')
sign = False
@@ -488,11 +481,11 @@ def parse_arguments(lineno, name, toks):
flds = []
extern = False
for t in toks:
- if re_fullmatch('!extern', t):
+ if re.fullmatch('!extern', t):
extern = True
anyextern = True
continue
- if not re_fullmatch(re_ident, t):
+ if not re.fullmatch(re_ident, t):
error(lineno, 'invalid argument set token "{0}"'.format(t))
if t in flds:
error(lineno, 'duplicate argument "{0}"'.format(t))
@@ -621,13 +614,13 @@ def parse_generic(lineno, is_format, name, toks):
continue
# 'Foo=%Bar' imports a field with a different name.
- if re_fullmatch(re_ident + '=%' + re_ident, t):
+ if re.fullmatch(re_ident + '=%' + re_ident, t):
(fname, iname) = t.split('=%')
flds = add_field_byname(lineno, flds, fname, iname)
continue
# 'Foo=number' sets an argument field to a constant value
- if re_fullmatch(re_ident + '=[+-]?[0-9]+', t):
+ if re.fullmatch(re_ident + '=[+-]?[0-9]+', t):
(fname, value) = t.split('=')
value = int(value)
flds = add_field(lineno, flds, fname, ConstField(value))
@@ -635,7 +628,7 @@ def parse_generic(lineno, is_format, name, toks):
# Pattern of 0s, 1s, dots and dashes indicate required zeros,
# required ones, or dont-cares.
- if re_fullmatch('[01.-]+', t):
+ if re.fullmatch('[01.-]+', t):
shift = len(t)
fms = t.replace('0', '1')
fms = fms.replace('.', '0')
@@ -652,7 +645,7 @@ def parse_generic(lineno, is_format, name, toks):
fixedmask = (fixedmask << shift) | fms
undefmask = (undefmask << shift) | ubm
# Otherwise, fieldname:fieldwidth
- elif re_fullmatch(re_ident + ':s?[0-9]+', t):
+ elif re.fullmatch(re_ident + ':s?[0-9]+', t):
(fname, flen) = t.split(':')
sign = False
if flen[0] == 's':
diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap
index 971ed0e721..6fe66d5f57 100755
--- a/scripts/kvm/vmxcap
+++ b/scripts/kvm/vmxcap
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# tool for querying VMX capabilities
#
@@ -275,5 +275,6 @@ controls = [
),
]
-for c in controls:
- c.show()
+if __name__ == '__main__':
+ for c in controls:
+ c.show()
diff --git a/scripts/modules/module_block.py b/scripts/modules/module_block.py
index f23191fac1..1109df827d 100644
--- a/scripts/modules/module_block.py
+++ b/scripts/modules/module_block.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# Module information generator
#
@@ -80,19 +80,20 @@ def print_bottom(fheader):
#endif
''')
-# First argument: output file
-# All other arguments: modules source files (.c)
-output_file = sys.argv[1]
-with open(output_file, 'w') as fheader:
- print_top(fheader)
+if __name__ == '__main__':
+ # First argument: output file
+ # All other arguments: modules source files (.c)
+ output_file = sys.argv[1]
+ with open(output_file, 'w') as fheader:
+ print_top(fheader)
- for filename in sys.argv[2:]:
- if os.path.isfile(filename):
- process_file(fheader, filename)
- else:
- print("File " + filename + " does not exist.", file=sys.stderr)
- sys.exit(1)
+ for filename in sys.argv[2:]:
+ if os.path.isfile(filename):
+ process_file(fheader, filename)
+ else:
+ print("File " + filename + " does not exist.", file=sys.stderr)
+ sys.exit(1)
- print_bottom(fheader)
+ print_bottom(fheader)
-sys.exit(0)
+ sys.exit(0)
diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py
index f2a305c42e..e0bfa7b5a4 100644
--- a/scripts/qemu-gdb.py
+++ b/scripts/qemu-gdb.py
@@ -1,5 +1,5 @@
-#!/usr/bin/python
-
+#!/usr/bin/env python3
+#
# GDB debugging support
#
# Copyright 2012 Red Hat, Inc. and/or its affiliates
diff --git a/scripts/qemugdb/__init__.py b/scripts/qemugdb/__init__.py
index 969f552b26..da8ff612e5 100644
--- a/scripts/qemugdb/__init__.py
+++ b/scripts/qemugdb/__init__.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#
# GDB debugging support
#
# Copyright (c) 2015 Linaro Ltd
diff --git a/scripts/qemugdb/aio.py b/scripts/qemugdb/aio.py
index 2ba00c4444..d7c1ba0c28 100644
--- a/scripts/qemugdb/aio.py
+++ b/scripts/qemugdb/aio.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#
# GDB debugging support: aio/iohandler debug
#
# Copyright (c) 2015 Red Hat, Inc.
diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py
index 41e079d0e2..db61389022 100644
--- a/scripts/qemugdb/coroutine.py
+++ b/scripts/qemugdb/coroutine.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#
# GDB debugging support
#
# Copyright 2012 Red Hat, Inc. and/or its affiliates
diff --git a/scripts/qemugdb/mtree.py b/scripts/qemugdb/mtree.py
index 3030a60d3f..8fe42c3c12 100644
--- a/scripts/qemugdb/mtree.py
+++ b/scripts/qemugdb/mtree.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#
# GDB debugging support
#
# Copyright 2012 Red Hat, Inc. and/or its affiliates
@@ -84,4 +83,3 @@ class MtreeCommand(gdb.Command):
while not isnull(subregion):
self.print_item(subregion, addr, level)
subregion = subregion['subregions_link']['tqe_next']
-
diff --git a/scripts/qemugdb/tcg.py b/scripts/qemugdb/tcg.py
index 18880fc9a7..16c03c06a9 100644
--- a/scripts/qemugdb/tcg.py
+++ b/scripts/qemugdb/tcg.py
@@ -1,4 +1,3 @@
-#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# GDB debugging support, TCG status
diff --git a/scripts/qemugdb/timers.py b/scripts/qemugdb/timers.py
index f0e132d27a..46537b27cf 100644
--- a/scripts/qemugdb/timers.py
+++ b/scripts/qemugdb/timers.py
@@ -1,4 +1,3 @@
-#!/usr/bin/python
# -*- coding: utf-8 -*-
# GDB debugging support
#
diff --git a/scripts/qmp/qmp b/scripts/qmp/qmp
index 0625fc2aba..8e52e4a54d 100755
--- a/scripts/qmp/qmp
+++ b/scripts/qmp/qmp
@@ -11,7 +11,9 @@
# See the COPYING file in the top-level directory.
import sys, os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
def print_response(rsp, prefix=[]):
if type(rsp) == list:
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index a01d31de1e..c5eef06f3f 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -77,9 +77,6 @@ import re
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu import qmp
-if sys.version_info[0] == 2:
- input = raw_input
-
class QMPCompleter(list):
def complete(self, text, state):
for cmd in self:
diff --git a/scripts/qmp/qom-fuse b/scripts/qmp/qom-fuse
index 6bada2c33d..5fa6b3bf64 100755
--- a/scripts/qmp/qom-fuse
+++ b/scripts/qmp/qom-fuse
@@ -15,7 +15,9 @@ import fuse, stat
from fuse import Fuse
import os, posix
from errno import *
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
fuse.fuse_python_api = (0, 2)
diff --git a/scripts/qmp/qom-get b/scripts/qmp/qom-get
index 007b4cd442..666df71832 100755
--- a/scripts/qmp/qom-get
+++ b/scripts/qmp/qom-get
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
##
# QEMU Object Model test tools
#
@@ -13,7 +13,9 @@
import sys
import os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
cmd, args = sys.argv[0], sys.argv[1:]
socket_path = None
diff --git a/scripts/qmp/qom-list b/scripts/qmp/qom-list
index 03bda3446b..5074fd939f 100755
--- a/scripts/qmp/qom-list
+++ b/scripts/qmp/qom-list
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
##
# QEMU Object Model test tools
#
@@ -13,7 +13,9 @@
import sys
import os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
cmd, args = sys.argv[0], sys.argv[1:]
socket_path = None
diff --git a/scripts/qmp/qom-set b/scripts/qmp/qom-set
index c37fe78b00..240a78187f 100755
--- a/scripts/qmp/qom-set
+++ b/scripts/qmp/qom-set
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
##
# QEMU Object Model test tools
#
@@ -13,7 +13,9 @@
import sys
import os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
cmd, args = sys.argv[0], sys.argv[1:]
socket_path = None
diff --git a/scripts/qmp/qom-tree b/scripts/qmp/qom-tree
index 1c8acf61e7..25b0781323 100755
--- a/scripts/qmp/qom-tree
+++ b/scripts/qmp/qom-tree
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
##
# QEMU Object Model test tools
#
@@ -15,7 +15,9 @@
import sys
import os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
cmd, args = sys.argv[0], sys.argv[1:]
socket_path = None
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
index 181ed4a186..57ad830d54 100644
--- a/scsi/qemu-pr-helper.c
+++ b/scsi/qemu-pr-helper.c
@@ -1030,8 +1030,8 @@ int main(int argc, char **argv)
server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
&local_err);
if (server_ioc == NULL) {
- error_report("Failed to use socket activation: %s",
- error_get_pretty(local_err));
+ error_reportf_err(local_err,
+ "Failed to use socket activation: ");
exit(EXIT_FAILURE);
}
}
diff --git a/softmmu/vl.c b/softmmu/vl.c
index ae5451bc23..05d1a4cb6b 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -1993,7 +1993,7 @@ char *qemu_find_file(int type, const char *name)
return NULL;
}
-static void qemu_add_data_dir(const char *path)
+void qemu_add_data_dir(const char *path)
{
int i;
diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c
index f800266727..c76806dc8d 100644
--- a/target/arm/crypto_helper.c
+++ b/target/arm/crypto_helper.c
@@ -13,7 +13,9 @@
#include "cpu.h"
#include "exec/helper-proto.h"
+#include "tcg/tcg-gvec-desc.h"
#include "crypto/aes.h"
+#include "vec_internal.h"
union CRYPTO_STATE {
uint8_t bytes[16];
@@ -22,25 +24,35 @@ union CRYPTO_STATE {
};
#ifdef HOST_WORDS_BIGENDIAN
-#define CR_ST_BYTE(state, i) (state.bytes[(15 - (i)) ^ 8])
-#define CR_ST_WORD(state, i) (state.words[(3 - (i)) ^ 2])
+#define CR_ST_BYTE(state, i) ((state).bytes[(15 - (i)) ^ 8])
+#define CR_ST_WORD(state, i) ((state).words[(3 - (i)) ^ 2])
#else
-#define CR_ST_BYTE(state, i) (state.bytes[i])
-#define CR_ST_WORD(state, i) (state.words[i])
+#define CR_ST_BYTE(state, i) ((state).bytes[i])
+#define CR_ST_WORD(state, i) ((state).words[i])
#endif
-void HELPER(crypto_aese)(void *vd, void *vm, uint32_t decrypt)
+/*
+ * The caller has not been converted to full gvec, and so only
+ * modifies the low 16 bytes of the vector register.
+ */
+static void clear_tail_16(void *vd, uint32_t desc)
+{
+ int opr_sz = simd_oprsz(desc);
+ int max_sz = simd_maxsz(desc);
+
+ assert(opr_sz == 16);
+ clear_tail(vd, opr_sz, max_sz);
+}
+
+static void do_crypto_aese(uint64_t *rd, uint64_t *rn,
+ uint64_t *rm, bool decrypt)
{
static uint8_t const * const sbox[2] = { AES_sbox, AES_isbox };
static uint8_t const * const shift[2] = { AES_shifts, AES_ishifts };
- uint64_t *rd = vd;
- uint64_t *rm = vm;
union CRYPTO_STATE rk = { .l = { rm[0], rm[1] } };
- union CRYPTO_STATE st = { .l = { rd[0], rd[1] } };
+ union CRYPTO_STATE st = { .l = { rn[0], rn[1] } };
int i;
- assert(decrypt < 2);
-
/* xor state vector with round key */
rk.l[0] ^= st.l[0];
rk.l[1] ^= st.l[1];
@@ -54,7 +66,18 @@ void HELPER(crypto_aese)(void *vd, void *vm, uint32_t decrypt)
rd[1] = st.l[1];
}
-void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t decrypt)
+void HELPER(crypto_aese)(void *vd, void *vn, void *vm, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+ bool decrypt = simd_data(desc);
+
+ for (i = 0; i < opr_sz; i += 16) {
+ do_crypto_aese(vd + i, vn + i, vm + i, decrypt);
+ }
+ clear_tail(vd, opr_sz, simd_maxsz(desc));
+}
+
+static void do_crypto_aesmc(uint64_t *rd, uint64_t *rm, bool decrypt)
{
static uint32_t const mc[][256] = { {
/* MixColumns lookup table */
@@ -190,13 +213,9 @@ void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t decrypt)
0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d,
} };
- uint64_t *rd = vd;
- uint64_t *rm = vm;
union CRYPTO_STATE st = { .l = { rm[0], rm[1] } };
int i;
- assert(decrypt < 2);
-
for (i = 0; i < 16; i += 4) {
CR_ST_WORD(st, i >> 2) =
mc[decrypt][CR_ST_BYTE(st, i)] ^
@@ -209,6 +228,17 @@ void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t decrypt)
rd[1] = st.l[1];
}
+void HELPER(crypto_aesmc)(void *vd, void *vm, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+ bool decrypt = simd_data(desc);
+
+ for (i = 0; i < opr_sz; i += 16) {
+ do_crypto_aesmc(vd + i, vm + i, decrypt);
+ }
+ clear_tail(vd, opr_sz, simd_maxsz(desc));
+}
+
/*
* SHA-1 logical functions
*/
@@ -228,52 +258,77 @@ static uint32_t maj(uint32_t x, uint32_t y, uint32_t z)
return (x & y) | ((x | y) & z);
}
-void HELPER(crypto_sha1_3reg)(void *vd, void *vn, void *vm, uint32_t op)
+void HELPER(crypto_sha1su0)(void *vd, void *vn, void *vm, uint32_t desc)
+{
+ uint64_t *d = vd, *n = vn, *m = vm;
+ uint64_t d0, d1;
+
+ d0 = d[1] ^ d[0] ^ m[0];
+ d1 = n[0] ^ d[1] ^ m[1];
+ d[0] = d0;
+ d[1] = d1;
+
+ clear_tail_16(vd, desc);
+}
+
+static inline void crypto_sha1_3reg(uint64_t *rd, uint64_t *rn,
+ uint64_t *rm, uint32_t desc,
+ uint32_t (*fn)(union CRYPTO_STATE *d))
{
- uint64_t *rd = vd;
- uint64_t *rn = vn;
- uint64_t *rm = vm;
union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
union CRYPTO_STATE n = { .l = { rn[0], rn[1] } };
union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
+ int i;
- if (op == 3) { /* sha1su0 */
- d.l[0] ^= d.l[1] ^ m.l[0];
- d.l[1] ^= n.l[0] ^ m.l[1];
- } else {
- int i;
-
- for (i = 0; i < 4; i++) {
- uint32_t t;
-
- switch (op) {
- case 0: /* sha1c */
- t = cho(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3));
- break;
- case 1: /* sha1p */
- t = par(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3));
- break;
- case 2: /* sha1m */
- t = maj(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3));
- break;
- default:
- g_assert_not_reached();
- }
- t += rol32(CR_ST_WORD(d, 0), 5) + CR_ST_WORD(n, 0)
- + CR_ST_WORD(m, i);
-
- CR_ST_WORD(n, 0) = CR_ST_WORD(d, 3);
- CR_ST_WORD(d, 3) = CR_ST_WORD(d, 2);
- CR_ST_WORD(d, 2) = ror32(CR_ST_WORD(d, 1), 2);
- CR_ST_WORD(d, 1) = CR_ST_WORD(d, 0);
- CR_ST_WORD(d, 0) = t;
- }
+ for (i = 0; i < 4; i++) {
+ uint32_t t = fn(&d);
+
+ t += rol32(CR_ST_WORD(d, 0), 5) + CR_ST_WORD(n, 0)
+ + CR_ST_WORD(m, i);
+
+ CR_ST_WORD(n, 0) = CR_ST_WORD(d, 3);
+ CR_ST_WORD(d, 3) = CR_ST_WORD(d, 2);
+ CR_ST_WORD(d, 2) = ror32(CR_ST_WORD(d, 1), 2);
+ CR_ST_WORD(d, 1) = CR_ST_WORD(d, 0);
+ CR_ST_WORD(d, 0) = t;
}
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(rd, desc);
+}
+
+static uint32_t do_sha1c(union CRYPTO_STATE *d)
+{
+ return cho(CR_ST_WORD(*d, 1), CR_ST_WORD(*d, 2), CR_ST_WORD(*d, 3));
+}
+
+void HELPER(crypto_sha1c)(void *vd, void *vn, void *vm, uint32_t desc)
+{
+ crypto_sha1_3reg(vd, vn, vm, desc, do_sha1c);
+}
+
+static uint32_t do_sha1p(union CRYPTO_STATE *d)
+{
+ return par(CR_ST_WORD(*d, 1), CR_ST_WORD(*d, 2), CR_ST_WORD(*d, 3));
+}
+
+void HELPER(crypto_sha1p)(void *vd, void *vn, void *vm, uint32_t desc)
+{
+ crypto_sha1_3reg(vd, vn, vm, desc, do_sha1p);
}
-void HELPER(crypto_sha1h)(void *vd, void *vm)
+static uint32_t do_sha1m(union CRYPTO_STATE *d)
+{
+ return maj(CR_ST_WORD(*d, 1), CR_ST_WORD(*d, 2), CR_ST_WORD(*d, 3));
+}
+
+void HELPER(crypto_sha1m)(void *vd, void *vn, void *vm, uint32_t desc)
+{
+ crypto_sha1_3reg(vd, vn, vm, desc, do_sha1m);
+}
+
+void HELPER(crypto_sha1h)(void *vd, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rm = vm;
@@ -284,9 +339,11 @@ void HELPER(crypto_sha1h)(void *vd, void *vm)
rd[0] = m.l[0];
rd[1] = m.l[1];
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sha1su1)(void *vd, void *vm)
+void HELPER(crypto_sha1su1)(void *vd, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rm = vm;
@@ -300,6 +357,8 @@ void HELPER(crypto_sha1su1)(void *vd, void *vm)
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(vd, desc);
}
/*
@@ -327,7 +386,7 @@ static uint32_t s1(uint32_t x)
return ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10);
}
-void HELPER(crypto_sha256h)(void *vd, void *vn, void *vm)
+void HELPER(crypto_sha256h)(void *vd, void *vn, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -358,9 +417,11 @@ void HELPER(crypto_sha256h)(void *vd, void *vn, void *vm)
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sha256h2)(void *vd, void *vn, void *vm)
+void HELPER(crypto_sha256h2)(void *vd, void *vn, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -383,9 +444,11 @@ void HELPER(crypto_sha256h2)(void *vd, void *vn, void *vm)
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sha256su0)(void *vd, void *vm)
+void HELPER(crypto_sha256su0)(void *vd, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rm = vm;
@@ -399,9 +462,11 @@ void HELPER(crypto_sha256su0)(void *vd, void *vm)
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sha256su1)(void *vd, void *vn, void *vm)
+void HELPER(crypto_sha256su1)(void *vd, void *vn, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -417,6 +482,8 @@ void HELPER(crypto_sha256su1)(void *vd, void *vn, void *vm)
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(vd, desc);
}
/*
@@ -453,7 +520,7 @@ static uint64_t s1_512(uint64_t x)
return ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6);
}
-void HELPER(crypto_sha512h)(void *vd, void *vn, void *vm)
+void HELPER(crypto_sha512h)(void *vd, void *vn, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -466,9 +533,11 @@ void HELPER(crypto_sha512h)(void *vd, void *vn, void *vm)
rd[0] = d0;
rd[1] = d1;
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sha512h2)(void *vd, void *vn, void *vm)
+void HELPER(crypto_sha512h2)(void *vd, void *vn, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -481,9 +550,11 @@ void HELPER(crypto_sha512h2)(void *vd, void *vn, void *vm)
rd[0] = d0;
rd[1] = d1;
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sha512su0)(void *vd, void *vn)
+void HELPER(crypto_sha512su0)(void *vd, void *vn, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -495,9 +566,11 @@ void HELPER(crypto_sha512su0)(void *vd, void *vn)
rd[0] = d0;
rd[1] = d1;
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sha512su1)(void *vd, void *vn, void *vm)
+void HELPER(crypto_sha512su1)(void *vd, void *vn, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -505,9 +578,11 @@ void HELPER(crypto_sha512su1)(void *vd, void *vn, void *vm)
rd[0] += s1_512(rn[0]) + rm[0];
rd[1] += s1_512(rn[1]) + rm[1];
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sm3partw1)(void *vd, void *vn, void *vm)
+void HELPER(crypto_sm3partw1)(void *vd, void *vn, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -531,9 +606,11 @@ void HELPER(crypto_sm3partw1)(void *vd, void *vn, void *vm)
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sm3partw2)(void *vd, void *vn, void *vm)
+void HELPER(crypto_sm3partw2)(void *vd, void *vn, void *vm, uint32_t desc)
{
uint64_t *rd = vd;
uint64_t *rn = vn;
@@ -551,17 +628,18 @@ void HELPER(crypto_sm3partw2)(void *vd, void *vn, void *vm)
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(vd, desc);
}
-void HELPER(crypto_sm3tt)(void *vd, void *vn, void *vm, uint32_t imm2,
- uint32_t opcode)
+static inline void QEMU_ALWAYS_INLINE
+crypto_sm3tt(uint64_t *rd, uint64_t *rn, uint64_t *rm,
+ uint32_t desc, uint32_t opcode)
{
- uint64_t *rd = vd;
- uint64_t *rn = vn;
- uint64_t *rm = vm;
union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
union CRYPTO_STATE n = { .l = { rn[0], rn[1] } };
union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
+ uint32_t imm2 = simd_data(desc);
uint32_t t;
assert(imm2 < 4);
@@ -576,7 +654,7 @@ void HELPER(crypto_sm3tt)(void *vd, void *vn, void *vm, uint32_t imm2,
/* SM3TT2B */
t = cho(CR_ST_WORD(d, 3), CR_ST_WORD(d, 2), CR_ST_WORD(d, 1));
} else {
- g_assert_not_reached();
+ qemu_build_not_reached();
}
t += CR_ST_WORD(d, 0) + CR_ST_WORD(m, imm2);
@@ -601,8 +679,21 @@ void HELPER(crypto_sm3tt)(void *vd, void *vn, void *vm, uint32_t imm2,
rd[0] = d.l[0];
rd[1] = d.l[1];
+
+ clear_tail_16(rd, desc);
}
+#define DO_SM3TT(NAME, OPCODE) \
+ void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \
+ { crypto_sm3tt(vd, vn, vm, desc, OPCODE); }
+
+DO_SM3TT(crypto_sm3tt1a, 0)
+DO_SM3TT(crypto_sm3tt1b, 1)
+DO_SM3TT(crypto_sm3tt2a, 2)
+DO_SM3TT(crypto_sm3tt2b, 3)
+
+#undef DO_SM3TT
+
static uint8_t const sm4_sbox[] = {
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
@@ -638,12 +729,10 @@ static uint8_t const sm4_sbox[] = {
0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
};
-void HELPER(crypto_sm4e)(void *vd, void *vn)
+static void do_crypto_sm4e(uint64_t *rd, uint64_t *rn, uint64_t *rm)
{
- uint64_t *rd = vd;
- uint64_t *rn = vn;
- union CRYPTO_STATE d = { .l = { rd[0], rd[1] } };
- union CRYPTO_STATE n = { .l = { rn[0], rn[1] } };
+ union CRYPTO_STATE d = { .l = { rn[0], rn[1] } };
+ union CRYPTO_STATE n = { .l = { rm[0], rm[1] } };
uint32_t t, i;
for (i = 0; i < 4; i++) {
@@ -665,11 +754,18 @@ void HELPER(crypto_sm4e)(void *vd, void *vn)
rd[1] = d.l[1];
}
-void HELPER(crypto_sm4ekey)(void *vd, void *vn, void* vm)
+void HELPER(crypto_sm4e)(void *vd, void *vn, void *vm, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+
+ for (i = 0; i < opr_sz; i += 16) {
+ do_crypto_sm4e(vd + i, vn + i, vm + i);
+ }
+ clear_tail(vd, opr_sz, simd_maxsz(desc));
+}
+
+static void do_crypto_sm4ekey(uint64_t *rd, uint64_t *rn, uint64_t *rm)
{
- uint64_t *rd = vd;
- uint64_t *rn = vn;
- uint64_t *rm = vm;
union CRYPTO_STATE d;
union CRYPTO_STATE n = { .l = { rn[0], rn[1] } };
union CRYPTO_STATE m = { .l = { rm[0], rm[1] } };
@@ -693,3 +789,24 @@ void HELPER(crypto_sm4ekey)(void *vd, void *vn, void* vm)
rd[0] = d.l[0];
rd[1] = d.l[1];
}
+
+void HELPER(crypto_sm4ekey)(void *vd, void *vn, void* vm, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+
+ for (i = 0; i < opr_sz; i += 16) {
+ do_crypto_sm4ekey(vd + i, vn + i, vm + i);
+ }
+ clear_tail(vd, opr_sz, simd_maxsz(desc));
+}
+
+void HELPER(crypto_rax1)(void *vd, void *vn, void *vm, uint32_t desc)
+{
+ intptr_t i, opr_sz = simd_oprsz(desc);
+ uint64_t *d = vd, *n = vn, *m = vm;
+
+ for (i = 0; i < opr_sz / 8; ++i) {
+ d[i] = n[i] ^ rol64(m[i], 1);
+ }
+ clear_tail(vd, opr_sz, simd_maxsz(desc));
+}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index a92ae55672..972a766730 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6813,7 +6813,7 @@ static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
mr = memory_region_from_host(haddr, &offset);
if (mr) {
- memory_region_do_writeback(mr, offset, dline_size);
+ memory_region_writeback(mr, offset, dline_size);
}
}
}
diff --git a/target/arm/helper.h b/target/arm/helper.h
index 49336dc432..2a20c8174c 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -510,29 +510,40 @@ DEF_HELPER_FLAGS_2(neon_qzip8, TCG_CALL_NO_RWG, void, ptr, ptr)
DEF_HELPER_FLAGS_2(neon_qzip16, TCG_CALL_NO_RWG, void, ptr, ptr)
DEF_HELPER_FLAGS_2(neon_qzip32, TCG_CALL_NO_RWG, void, ptr, ptr)
-DEF_HELPER_FLAGS_3(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(crypto_aesmc, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
-DEF_HELPER_FLAGS_4(crypto_sha1_3reg, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
-DEF_HELPER_FLAGS_2(crypto_sha1h, TCG_CALL_NO_RWG, void, ptr, ptr)
-DEF_HELPER_FLAGS_2(crypto_sha1su1, TCG_CALL_NO_RWG, void, ptr, ptr)
-
-DEF_HELPER_FLAGS_3(crypto_sha256h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
-DEF_HELPER_FLAGS_3(crypto_sha256h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
-DEF_HELPER_FLAGS_2(crypto_sha256su0, TCG_CALL_NO_RWG, void, ptr, ptr)
-DEF_HELPER_FLAGS_3(crypto_sha256su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
-
-DEF_HELPER_FLAGS_3(crypto_sha512h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
-DEF_HELPER_FLAGS_3(crypto_sha512h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
-DEF_HELPER_FLAGS_2(crypto_sha512su0, TCG_CALL_NO_RWG, void, ptr, ptr)
-DEF_HELPER_FLAGS_3(crypto_sha512su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
-
-DEF_HELPER_FLAGS_5(crypto_sm3tt, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32)
-DEF_HELPER_FLAGS_3(crypto_sm3partw1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
-DEF_HELPER_FLAGS_3(crypto_sm3partw2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
-
-DEF_HELPER_FLAGS_2(crypto_sm4e, TCG_CALL_NO_RWG, void, ptr, ptr)
-DEF_HELPER_FLAGS_3(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr)
+DEF_HELPER_FLAGS_4(crypto_sha1su0, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sha1c, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sha1p, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sha1m, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(crypto_sha1h, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(crypto_sha1su1, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+
+DEF_HELPER_FLAGS_4(crypto_sha256h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sha256h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(crypto_sha256su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sha256su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+
+DEF_HELPER_FLAGS_4(crypto_sha512h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sha512h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_3(crypto_sha512su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sha512su1, TCG_CALL_NO_RWG,
+ void, ptr, ptr, ptr, i32)
+
+DEF_HELPER_FLAGS_4(crypto_sm3tt1a, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sm3tt1b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sm3tt2a, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sm3tt2b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sm3partw1, TCG_CALL_NO_RWG,
+ void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sm3partw2, TCG_CALL_NO_RWG,
+ void, ptr, ptr, ptr, i32)
+
+DEF_HELPER_FLAGS_4(crypto_sm4e, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+
+DEF_HELPER_FLAGS_4(crypto_rax1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
index 8beb1db768..bd1b0e13f7 100644
--- a/target/arm/neon-dp.decode
+++ b/target/arm/neon-dp.decode
@@ -165,14 +165,16 @@ VPADD_3s 1111 001 0 0 . .. .... .... 1011 . . . 1 .... @3same_q0
VQRDMLAH_3s 1111 001 1 0 . .. .... .... 1011 ... 1 .... @3same
-SHA1_3s 1111 001 0 0 . optype:2 .... .... 1100 . 1 . 0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-SHA256H_3s 1111 001 1 0 . 00 .... .... 1100 . 1 . 0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-SHA256H2_3s 1111 001 1 0 . 01 .... .... 1100 . 1 . 0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-SHA256SU1_3s 1111 001 1 0 . 10 .... .... 1100 . 1 . 0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
+@3same_crypto .... .... .... .... .... .... .... .... \
+ &3same vm=%vm_dp vn=%vn_dp vd=%vd_dp size=0 q=1
+
+SHA1C_3s 1111 001 0 0 . 00 .... .... 1100 . 1 . 0 .... @3same_crypto
+SHA1P_3s 1111 001 0 0 . 01 .... .... 1100 . 1 . 0 .... @3same_crypto
+SHA1M_3s 1111 001 0 0 . 10 .... .... 1100 . 1 . 0 .... @3same_crypto
+SHA1SU0_3s 1111 001 0 0 . 11 .... .... 1100 . 1 . 0 .... @3same_crypto
+SHA256H_3s 1111 001 1 0 . 00 .... .... 1100 . 1 . 0 .... @3same_crypto
+SHA256H2_3s 1111 001 1 0 . 01 .... .... 1100 . 1 . 0 .... @3same_crypto
+SHA256SU1_3s 1111 001 1 0 . 10 .... .... 1100 . 1 . 0 .... @3same_crypto
VFMA_fp_3s 1111 001 0 0 . 0 . .... .... 1100 ... 1 .... @3same_fp
VFMS_fp_3s 1111 001 0 0 . 1 . .... .... 1100 ... 1 .... @3same_fp
@@ -199,3 +201,199 @@ VRECPS_fp_3s 1111 001 0 0 . 0 . .... .... 1111 ... 1 .... @3same_fp
VRSQRTS_fp_3s 1111 001 0 0 . 1 . .... .... 1111 ... 1 .... @3same_fp
VMAXNM_fp_3s 1111 001 1 0 . 0 . .... .... 1111 ... 1 .... @3same_fp
VMINNM_fp_3s 1111 001 1 0 . 1 . .... .... 1111 ... 1 .... @3same_fp
+
+######################################################################
+# 2-reg-and-shift grouping:
+# 1111 001 U 1 D immH:3 immL:3 Vd:4 opc:4 L Q M 1 Vm:4
+######################################################################
+&2reg_shift vm vd q shift size
+
+# Right shifts are encoded as N - shift, where N is the element size in bits.
+%neon_rshift_i6 16:6 !function=rsub_64
+%neon_rshift_i5 16:5 !function=rsub_32
+%neon_rshift_i4 16:4 !function=rsub_16
+%neon_rshift_i3 16:3 !function=rsub_8
+
+@2reg_shr_d .... ... . . . ...... .... .... 1 q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=3 shift=%neon_rshift_i6
+@2reg_shr_s .... ... . . . 1 ..... .... .... 0 q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=2 shift=%neon_rshift_i5
+@2reg_shr_h .... ... . . . 01 .... .... .... 0 q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=1 shift=%neon_rshift_i4
+@2reg_shr_b .... ... . . . 001 ... .... .... 0 q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=0 shift=%neon_rshift_i3
+
+@2reg_shl_d .... ... . . . shift:6 .... .... 1 q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=3
+@2reg_shl_s .... ... . . . 1 shift:5 .... .... 0 q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=2
+@2reg_shl_h .... ... . . . 01 shift:4 .... .... 0 q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=1
+@2reg_shl_b .... ... . . . 001 shift:3 .... .... 0 q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=0
+
+# Narrowing right shifts: here the Q bit is part of the opcode decode
+@2reg_shrn_d .... ... . . . 1 ..... .... .... 0 . . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=3 q=0 \
+ shift=%neon_rshift_i5
+@2reg_shrn_s .... ... . . . 01 .... .... .... 0 . . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=2 q=0 \
+ shift=%neon_rshift_i4
+@2reg_shrn_h .... ... . . . 001 ... .... .... 0 . . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=1 q=0 \
+ shift=%neon_rshift_i3
+
+# Long left shifts: again Q is part of opcode decode
+@2reg_shll_s .... ... . . . 1 shift:5 .... .... 0 . . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=2 q=0
+@2reg_shll_h .... ... . . . 01 shift:4 .... .... 0 . . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=1 q=0
+@2reg_shll_b .... ... . . . 001 shift:3 .... .... 0 . . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=0 q=0
+
+# We use size=0 for fp32 and size=1 for fp16 to match the 3-same encodings.
+@2reg_vcvt .... ... . . . 1 ..... .... .... . q:1 . . .... \
+ &2reg_shift vm=%vm_dp vd=%vd_dp size=0 shift=%neon_rshift_i5
+
+VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_d
+VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_s
+VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_h
+VSHR_S_2sh 1111 001 0 1 . ...... .... 0000 . . . 1 .... @2reg_shr_b
+
+VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_d
+VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_s
+VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_h
+VSHR_U_2sh 1111 001 1 1 . ...... .... 0000 . . . 1 .... @2reg_shr_b
+
+VSRA_S_2sh 1111 001 0 1 . ...... .... 0001 . . . 1 .... @2reg_shr_d
+VSRA_S_2sh 1111 001 0 1 . ...... .... 0001 . . . 1 .... @2reg_shr_s
+VSRA_S_2sh 1111 001 0 1 . ...... .... 0001 . . . 1 .... @2reg_shr_h
+VSRA_S_2sh 1111 001 0 1 . ...... .... 0001 . . . 1 .... @2reg_shr_b
+
+VSRA_U_2sh 1111 001 1 1 . ...... .... 0001 . . . 1 .... @2reg_shr_d
+VSRA_U_2sh 1111 001 1 1 . ...... .... 0001 . . . 1 .... @2reg_shr_s
+VSRA_U_2sh 1111 001 1 1 . ...... .... 0001 . . . 1 .... @2reg_shr_h
+VSRA_U_2sh 1111 001 1 1 . ...... .... 0001 . . . 1 .... @2reg_shr_b
+
+VRSHR_S_2sh 1111 001 0 1 . ...... .... 0010 . . . 1 .... @2reg_shr_d
+VRSHR_S_2sh 1111 001 0 1 . ...... .... 0010 . . . 1 .... @2reg_shr_s
+VRSHR_S_2sh 1111 001 0 1 . ...... .... 0010 . . . 1 .... @2reg_shr_h
+VRSHR_S_2sh 1111 001 0 1 . ...... .... 0010 . . . 1 .... @2reg_shr_b
+
+VRSHR_U_2sh 1111 001 1 1 . ...... .... 0010 . . . 1 .... @2reg_shr_d
+VRSHR_U_2sh 1111 001 1 1 . ...... .... 0010 . . . 1 .... @2reg_shr_s
+VRSHR_U_2sh 1111 001 1 1 . ...... .... 0010 . . . 1 .... @2reg_shr_h
+VRSHR_U_2sh 1111 001 1 1 . ...... .... 0010 . . . 1 .... @2reg_shr_b
+
+VRSRA_S_2sh 1111 001 0 1 . ...... .... 0011 . . . 1 .... @2reg_shr_d
+VRSRA_S_2sh 1111 001 0 1 . ...... .... 0011 . . . 1 .... @2reg_shr_s
+VRSRA_S_2sh 1111 001 0 1 . ...... .... 0011 . . . 1 .... @2reg_shr_h
+VRSRA_S_2sh 1111 001 0 1 . ...... .... 0011 . . . 1 .... @2reg_shr_b
+
+VRSRA_U_2sh 1111 001 1 1 . ...... .... 0011 . . . 1 .... @2reg_shr_d
+VRSRA_U_2sh 1111 001 1 1 . ...... .... 0011 . . . 1 .... @2reg_shr_s
+VRSRA_U_2sh 1111 001 1 1 . ...... .... 0011 . . . 1 .... @2reg_shr_h
+VRSRA_U_2sh 1111 001 1 1 . ...... .... 0011 . . . 1 .... @2reg_shr_b
+
+VSRI_2sh 1111 001 1 1 . ...... .... 0100 . . . 1 .... @2reg_shr_d
+VSRI_2sh 1111 001 1 1 . ...... .... 0100 . . . 1 .... @2reg_shr_s
+VSRI_2sh 1111 001 1 1 . ...... .... 0100 . . . 1 .... @2reg_shr_h
+VSRI_2sh 1111 001 1 1 . ...... .... 0100 . . . 1 .... @2reg_shr_b
+
+VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_d
+VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s
+VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h
+VSHL_2sh 1111 001 0 1 . ...... .... 0101 . . . 1 .... @2reg_shl_b
+
+VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_d
+VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s
+VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h
+VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_b
+
+VQSHLU_64_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_d
+VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_s
+VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_h
+VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_b
+
+VQSHL_S_64_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d
+VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s
+VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h
+VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b
+
+VQSHL_U_64_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d
+VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s
+VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h
+VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b
+
+VSHRN_64_2sh 1111 001 0 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_d
+VSHRN_32_2sh 1111 001 0 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_s
+VSHRN_16_2sh 1111 001 0 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_h
+
+VRSHRN_64_2sh 1111 001 0 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_d
+VRSHRN_32_2sh 1111 001 0 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_s
+VRSHRN_16_2sh 1111 001 0 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_h
+
+VQSHRUN_64_2sh 1111 001 1 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_d
+VQSHRUN_32_2sh 1111 001 1 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_s
+VQSHRUN_16_2sh 1111 001 1 1 . ...... .... 1000 . 0 . 1 .... @2reg_shrn_h
+
+VQRSHRUN_64_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_d
+VQRSHRUN_32_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_s
+VQRSHRUN_16_2sh 1111 001 1 1 . ...... .... 1000 . 1 . 1 .... @2reg_shrn_h
+
+# VQSHRN with signed input
+VQSHRN_S64_2sh 1111 001 0 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_d
+VQSHRN_S32_2sh 1111 001 0 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_s
+VQSHRN_S16_2sh 1111 001 0 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_h
+
+# VQRSHRN with signed input
+VQRSHRN_S64_2sh 1111 001 0 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_d
+VQRSHRN_S32_2sh 1111 001 0 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_s
+VQRSHRN_S16_2sh 1111 001 0 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_h
+
+# VQSHRN with unsigned input
+VQSHRN_U64_2sh 1111 001 1 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_d
+VQSHRN_U32_2sh 1111 001 1 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_s
+VQSHRN_U16_2sh 1111 001 1 1 . ...... .... 1001 . 0 . 1 .... @2reg_shrn_h
+
+# VQRSHRN with unsigned input
+VQRSHRN_U64_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_d
+VQRSHRN_U32_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_s
+VQRSHRN_U16_2sh 1111 001 1 1 . ...... .... 1001 . 1 . 1 .... @2reg_shrn_h
+
+VSHLL_S_2sh 1111 001 0 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_s
+VSHLL_S_2sh 1111 001 0 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_h
+VSHLL_S_2sh 1111 001 0 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_b
+
+VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_s
+VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_h
+VSHLL_U_2sh 1111 001 1 1 . ...... .... 1010 . 0 . 1 .... @2reg_shll_b
+
+# VCVT fixed<->float conversions
+# TODO: FP16 fixed<->float conversions are opc==0b1100 and 0b1101
+VCVT_SF_2sh 1111 001 0 1 . ...... .... 1110 0 . . 1 .... @2reg_vcvt
+VCVT_UF_2sh 1111 001 1 1 . ...... .... 1110 0 . . 1 .... @2reg_vcvt
+VCVT_FS_2sh 1111 001 0 1 . ...... .... 1111 0 . . 1 .... @2reg_vcvt
+VCVT_FU_2sh 1111 001 1 1 . ...... .... 1111 0 . . 1 .... @2reg_vcvt
+
+######################################################################
+# 1-reg-and-modified-immediate grouping:
+# 1111 001 i 1 D 000 imm:3 Vd:4 cmode:4 0 Q op 1 Vm:4
+######################################################################
+
+&1reg_imm vd q imm cmode op
+
+%asimd_imm_value 24:1 16:3 0:4
+
+@1reg_imm .... ... . . . ... ... .... .... . q:1 . . .... \
+ &1reg_imm imm=%asimd_imm_value vd=%vd_dp
+
+# The cmode/op bits here decode VORR/VBIC/VMOV/VMNV, but
+# not in a way we can conveniently represent in decodetree without
+# a lot of repetition:
+# VORR: op=0, (cmode & 1) && cmode < 12
+# VBIC: op=1, (cmode & 1) && cmode < 12
+# VMOV: everything else
+# So we have a single decode line and check the cmode/op in the
+# trans function.
+Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 874f3eb4f9..a0e72ad694 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -571,6 +571,15 @@ static void gen_gvec_fn4(DisasContext *s, bool is_q, int rd, int rn, int rm,
is_q ? 16 : 8, vec_full_reg_size(s));
}
+/* Expand a 2-operand operation using an out-of-line helper. */
+static void gen_gvec_op2_ool(DisasContext *s, bool is_q, int rd,
+ int rn, int data, gen_helper_gvec_2 *fn)
+{
+ tcg_gen_gvec_2_ool(vec_full_reg_offset(s, rd),
+ vec_full_reg_offset(s, rn),
+ is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
+}
+
/* Expand a 3-operand operation using an out-of-line helper. */
static void gen_gvec_op3_ool(DisasContext *s, bool is_q, int rd,
int rn, int rm, int data, gen_helper_gvec_3 *fn)
@@ -13403,9 +13412,8 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn)
int rn = extract32(insn, 5, 5);
int rd = extract32(insn, 0, 5);
int decrypt;
- TCGv_ptr tcg_rd_ptr, tcg_rn_ptr;
- TCGv_i32 tcg_decrypt;
- CryptoThreeOpIntFn *genfn;
+ gen_helper_gvec_2 *genfn2 = NULL;
+ gen_helper_gvec_3 *genfn3 = NULL;
if (!dc_isar_feature(aa64_aes, s) || size != 0) {
unallocated_encoding(s);
@@ -13415,19 +13423,19 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn)
switch (opcode) {
case 0x4: /* AESE */
decrypt = 0;
- genfn = gen_helper_crypto_aese;
+ genfn3 = gen_helper_crypto_aese;
break;
case 0x6: /* AESMC */
decrypt = 0;
- genfn = gen_helper_crypto_aesmc;
+ genfn2 = gen_helper_crypto_aesmc;
break;
case 0x5: /* AESD */
decrypt = 1;
- genfn = gen_helper_crypto_aese;
+ genfn3 = gen_helper_crypto_aese;
break;
case 0x7: /* AESIMC */
decrypt = 1;
- genfn = gen_helper_crypto_aesmc;
+ genfn2 = gen_helper_crypto_aesmc;
break;
default:
unallocated_encoding(s);
@@ -13437,16 +13445,11 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn)
if (!fp_access_check(s)) {
return;
}
-
- tcg_rd_ptr = vec_full_reg_ptr(s, rd);
- tcg_rn_ptr = vec_full_reg_ptr(s, rn);
- tcg_decrypt = tcg_const_i32(decrypt);
-
- genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_decrypt);
-
- tcg_temp_free_ptr(tcg_rd_ptr);
- tcg_temp_free_ptr(tcg_rn_ptr);
- tcg_temp_free_i32(tcg_decrypt);
+ if (genfn2) {
+ gen_gvec_op2_ool(s, true, rd, rn, decrypt, genfn2);
+ } else {
+ gen_gvec_op3_ool(s, true, rd, rd, rn, decrypt, genfn3);
+ }
}
/* Crypto three-reg SHA
@@ -13462,8 +13465,7 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
int rm = extract32(insn, 16, 5);
int rn = extract32(insn, 5, 5);
int rd = extract32(insn, 0, 5);
- CryptoThreeOpFn *genfn;
- TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr;
+ gen_helper_gvec_3 *genfn;
bool feature;
if (size != 0) {
@@ -13473,10 +13475,19 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
switch (opcode) {
case 0: /* SHA1C */
+ genfn = gen_helper_crypto_sha1c;
+ feature = dc_isar_feature(aa64_sha1, s);
+ break;
case 1: /* SHA1P */
+ genfn = gen_helper_crypto_sha1p;
+ feature = dc_isar_feature(aa64_sha1, s);
+ break;
case 2: /* SHA1M */
+ genfn = gen_helper_crypto_sha1m;
+ feature = dc_isar_feature(aa64_sha1, s);
+ break;
case 3: /* SHA1SU0 */
- genfn = NULL;
+ genfn = gen_helper_crypto_sha1su0;
feature = dc_isar_feature(aa64_sha1, s);
break;
case 4: /* SHA256H */
@@ -13504,24 +13515,7 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
if (!fp_access_check(s)) {
return;
}
-
- tcg_rd_ptr = vec_full_reg_ptr(s, rd);
- tcg_rn_ptr = vec_full_reg_ptr(s, rn);
- tcg_rm_ptr = vec_full_reg_ptr(s, rm);
-
- if (genfn) {
- genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr);
- } else {
- TCGv_i32 tcg_opcode = tcg_const_i32(opcode);
-
- gen_helper_crypto_sha1_3reg(tcg_rd_ptr, tcg_rn_ptr,
- tcg_rm_ptr, tcg_opcode);
- tcg_temp_free_i32(tcg_opcode);
- }
-
- tcg_temp_free_ptr(tcg_rd_ptr);
- tcg_temp_free_ptr(tcg_rn_ptr);
- tcg_temp_free_ptr(tcg_rm_ptr);
+ gen_gvec_op3_ool(s, true, rd, rn, rm, 0, genfn);
}
/* Crypto two-reg SHA
@@ -13536,9 +13530,8 @@ static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
int opcode = extract32(insn, 12, 5);
int rn = extract32(insn, 5, 5);
int rd = extract32(insn, 0, 5);
- CryptoTwoOpFn *genfn;
+ gen_helper_gvec_2 *genfn;
bool feature;
- TCGv_ptr tcg_rd_ptr, tcg_rn_ptr;
if (size != 0) {
unallocated_encoding(s);
@@ -13571,14 +13564,33 @@ static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
if (!fp_access_check(s)) {
return;
}
+ gen_gvec_op2_ool(s, true, rd, rn, 0, genfn);
+}
- tcg_rd_ptr = vec_full_reg_ptr(s, rd);
- tcg_rn_ptr = vec_full_reg_ptr(s, rn);
+static void gen_rax1_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
+{
+ tcg_gen_rotli_i64(d, m, 1);
+ tcg_gen_xor_i64(d, d, n);
+}
- genfn(tcg_rd_ptr, tcg_rn_ptr);
+static void gen_rax1_vec(unsigned vece, TCGv_vec d, TCGv_vec n, TCGv_vec m)
+{
+ tcg_gen_rotli_vec(vece, d, m, 1);
+ tcg_gen_xor_vec(vece, d, d, n);
+}
- tcg_temp_free_ptr(tcg_rd_ptr);
- tcg_temp_free_ptr(tcg_rn_ptr);
+void gen_gvec_rax1(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
+{
+ static const TCGOpcode vecop_list[] = { INDEX_op_rotli_vec, 0 };
+ static const GVecGen3 op = {
+ .fni8 = gen_rax1_i64,
+ .fniv = gen_rax1_vec,
+ .opt_opc = vecop_list,
+ .fno = gen_helper_crypto_rax1,
+ .vece = MO_64,
+ };
+ tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &op);
}
/* Crypto three-reg SHA512
@@ -13595,25 +13607,26 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn)
int rn = extract32(insn, 5, 5);
int rd = extract32(insn, 0, 5);
bool feature;
- CryptoThreeOpFn *genfn;
+ gen_helper_gvec_3 *oolfn = NULL;
+ GVecGen3Fn *gvecfn = NULL;
if (o == 0) {
switch (opcode) {
case 0: /* SHA512H */
feature = dc_isar_feature(aa64_sha512, s);
- genfn = gen_helper_crypto_sha512h;
+ oolfn = gen_helper_crypto_sha512h;
break;
case 1: /* SHA512H2 */
feature = dc_isar_feature(aa64_sha512, s);
- genfn = gen_helper_crypto_sha512h2;
+ oolfn = gen_helper_crypto_sha512h2;
break;
case 2: /* SHA512SU1 */
feature = dc_isar_feature(aa64_sha512, s);
- genfn = gen_helper_crypto_sha512su1;
+ oolfn = gen_helper_crypto_sha512su1;
break;
case 3: /* RAX1 */
feature = dc_isar_feature(aa64_sha3, s);
- genfn = NULL;
+ gvecfn = gen_gvec_rax1;
break;
default:
g_assert_not_reached();
@@ -13622,15 +13635,15 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn)
switch (opcode) {
case 0: /* SM3PARTW1 */
feature = dc_isar_feature(aa64_sm3, s);
- genfn = gen_helper_crypto_sm3partw1;
+ oolfn = gen_helper_crypto_sm3partw1;
break;
case 1: /* SM3PARTW2 */
feature = dc_isar_feature(aa64_sm3, s);
- genfn = gen_helper_crypto_sm3partw2;
+ oolfn = gen_helper_crypto_sm3partw2;
break;
case 2: /* SM4EKEY */
feature = dc_isar_feature(aa64_sm4, s);
- genfn = gen_helper_crypto_sm4ekey;
+ oolfn = gen_helper_crypto_sm4ekey;
break;
default:
unallocated_encoding(s);
@@ -13647,41 +13660,10 @@ static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn)
return;
}
- if (genfn) {
- TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr;
-
- tcg_rd_ptr = vec_full_reg_ptr(s, rd);
- tcg_rn_ptr = vec_full_reg_ptr(s, rn);
- tcg_rm_ptr = vec_full_reg_ptr(s, rm);
-
- genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr);
-
- tcg_temp_free_ptr(tcg_rd_ptr);
- tcg_temp_free_ptr(tcg_rn_ptr);
- tcg_temp_free_ptr(tcg_rm_ptr);
+ if (oolfn) {
+ gen_gvec_op3_ool(s, true, rd, rn, rm, 0, oolfn);
} else {
- TCGv_i64 tcg_op1, tcg_op2, tcg_res[2];
- int pass;
-
- tcg_op1 = tcg_temp_new_i64();
- tcg_op2 = tcg_temp_new_i64();
- tcg_res[0] = tcg_temp_new_i64();
- tcg_res[1] = tcg_temp_new_i64();
-
- for (pass = 0; pass < 2; pass++) {
- read_vec_element(s, tcg_op1, rn, pass, MO_64);
- read_vec_element(s, tcg_op2, rm, pass, MO_64);
-
- tcg_gen_rotli_i64(tcg_res[pass], tcg_op2, 1);
- tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
- }
- write_vec_element(s, tcg_res[0], rd, 0, MO_64);
- write_vec_element(s, tcg_res[1], rd, 1, MO_64);
-
- tcg_temp_free_i64(tcg_op1);
- tcg_temp_free_i64(tcg_op2);
- tcg_temp_free_i64(tcg_res[0]);
- tcg_temp_free_i64(tcg_res[1]);
+ gen_gvec_fn3(s, true, rd, rn, rm, gvecfn, MO_64);
}
}
@@ -13696,18 +13678,14 @@ static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn)
int opcode = extract32(insn, 10, 2);
int rn = extract32(insn, 5, 5);
int rd = extract32(insn, 0, 5);
- TCGv_ptr tcg_rd_ptr, tcg_rn_ptr;
bool feature;
- CryptoTwoOpFn *genfn;
switch (opcode) {
case 0: /* SHA512SU0 */
feature = dc_isar_feature(aa64_sha512, s);
- genfn = gen_helper_crypto_sha512su0;
break;
case 1: /* SM4E */
feature = dc_isar_feature(aa64_sm4, s);
- genfn = gen_helper_crypto_sm4e;
break;
default:
unallocated_encoding(s);
@@ -13723,13 +13701,16 @@ static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn)
return;
}
- tcg_rd_ptr = vec_full_reg_ptr(s, rd);
- tcg_rn_ptr = vec_full_reg_ptr(s, rn);
-
- genfn(tcg_rd_ptr, tcg_rn_ptr);
-
- tcg_temp_free_ptr(tcg_rd_ptr);
- tcg_temp_free_ptr(tcg_rn_ptr);
+ switch (opcode) {
+ case 0: /* SHA512SU0 */
+ gen_gvec_op2_ool(s, true, rd, rn, 0, gen_helper_crypto_sha512su0);
+ break;
+ case 1: /* SM4E */
+ gen_gvec_op3_ool(s, true, rd, rd, rn, 0, gen_helper_crypto_sm4e);
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
/* Crypto four-register
@@ -13885,13 +13866,15 @@ static void disas_crypto_xar(DisasContext *s, uint32_t insn)
*/
static void disas_crypto_three_reg_imm2(DisasContext *s, uint32_t insn)
{
+ static gen_helper_gvec_3 * const fns[4] = {
+ gen_helper_crypto_sm3tt1a, gen_helper_crypto_sm3tt1b,
+ gen_helper_crypto_sm3tt2a, gen_helper_crypto_sm3tt2b,
+ };
int opcode = extract32(insn, 10, 2);
int imm2 = extract32(insn, 12, 2);
int rm = extract32(insn, 16, 5);
int rn = extract32(insn, 5, 5);
int rd = extract32(insn, 0, 5);
- TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr;
- TCGv_i32 tcg_imm2, tcg_opcode;
if (!dc_isar_feature(aa64_sm3, s)) {
unallocated_encoding(s);
@@ -13902,20 +13885,7 @@ static void disas_crypto_three_reg_imm2(DisasContext *s, uint32_t insn)
return;
}
- tcg_rd_ptr = vec_full_reg_ptr(s, rd);
- tcg_rn_ptr = vec_full_reg_ptr(s, rn);
- tcg_rm_ptr = vec_full_reg_ptr(s, rm);
- tcg_imm2 = tcg_const_i32(imm2);
- tcg_opcode = tcg_const_i32(opcode);
-
- gen_helper_crypto_sm3tt(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr, tcg_imm2,
- tcg_opcode);
-
- tcg_temp_free_ptr(tcg_rd_ptr);
- tcg_temp_free_ptr(tcg_rn_ptr);
- tcg_temp_free_ptr(tcg_rm_ptr);
- tcg_temp_free_i32(tcg_imm2);
- tcg_temp_free_i32(tcg_opcode);
+ gen_gvec_op3_ool(s, true, rd, rn, rm, imm2, fns[opcode]);
}
/* C3.6 Data processing - SIMD, inc Crypto
diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h
index f02fbb63a4..da0f59a2ce 100644
--- a/target/arm/translate-a64.h
+++ b/target/arm/translate-a64.h
@@ -115,4 +115,7 @@ static inline int vec_full_reg_size(DisasContext *s)
bool disas_sve(DisasContext *, uint32_t);
+void gen_gvec_rax1(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz);
+
#endif /* TARGET_ARM_TRANSLATE_A64_H */
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
index 3fe65a0b08..664d361260 100644
--- a/target/arm/translate-neon.inc.c
+++ b/target/arm/translate-neon.inc.c
@@ -31,6 +31,24 @@ static inline int plus1(DisasContext *s, int x)
return x + 1;
}
+static inline int rsub_64(DisasContext *s, int x)
+{
+ return 64 - x;
+}
+
+static inline int rsub_32(DisasContext *s, int x)
+{
+ return 32 - x;
+}
+static inline int rsub_16(DisasContext *s, int x)
+{
+ return 16 - x;
+}
+static inline int rsub_8(DisasContext *s, int x)
+{
+ return 8 - x;
+}
+
/* Include the generated Neon decoder */
#include "decode-neon-dp.inc.c"
#include "decode-neon-ls.inc.c"
@@ -661,12 +679,14 @@ DO_3SAME_CMP(VCGE_S, TCG_COND_GE)
DO_3SAME_CMP(VCGE_U, TCG_COND_GEU)
DO_3SAME_CMP(VCEQ, TCG_COND_EQ)
-static void gen_VMUL_p_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
- uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz)
-{
- tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz,
- 0, gen_helper_gvec_pmul_b);
-}
+#define WRAP_OOL_FN(WRAPNAME, FUNC) \
+ static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \
+ uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \
+ { \
+ tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \
+ }
+
+WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b)
static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a)
{
@@ -691,144 +711,34 @@ static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a)
DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc)
DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc)
-static bool trans_SHA1_3s(DisasContext *s, arg_SHA1_3s *a)
-{
- TCGv_ptr ptr1, ptr2, ptr3;
- TCGv_i32 tmp;
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
- !dc_isar_feature(aa32_sha1, s)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vn | a->vm) & 0x10)) {
- return false;
- }
-
- if ((a->vn | a->vm | a->vd) & 1) {
- return false;
- }
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- ptr1 = vfp_reg_ptr(true, a->vd);
- ptr2 = vfp_reg_ptr(true, a->vn);
- ptr3 = vfp_reg_ptr(true, a->vm);
- tmp = tcg_const_i32(a->optype);
- gen_helper_crypto_sha1_3reg(ptr1, ptr2, ptr3, tmp);
- tcg_temp_free_i32(tmp);
- tcg_temp_free_ptr(ptr1);
- tcg_temp_free_ptr(ptr2);
- tcg_temp_free_ptr(ptr3);
-
- return true;
-}
-
-static bool trans_SHA256H_3s(DisasContext *s, arg_SHA256H_3s *a)
-{
- TCGv_ptr ptr1, ptr2, ptr3;
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
- !dc_isar_feature(aa32_sha2, s)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vn | a->vm) & 0x10)) {
- return false;
- }
-
- if ((a->vn | a->vm | a->vd) & 1) {
- return false;
- }
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- ptr1 = vfp_reg_ptr(true, a->vd);
- ptr2 = vfp_reg_ptr(true, a->vn);
- ptr3 = vfp_reg_ptr(true, a->vm);
- gen_helper_crypto_sha256h(ptr1, ptr2, ptr3);
- tcg_temp_free_ptr(ptr1);
- tcg_temp_free_ptr(ptr2);
- tcg_temp_free_ptr(ptr3);
-
- return true;
-}
-
-static bool trans_SHA256H2_3s(DisasContext *s, arg_SHA256H2_3s *a)
-{
- TCGv_ptr ptr1, ptr2, ptr3;
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
- !dc_isar_feature(aa32_sha2, s)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vn | a->vm) & 0x10)) {
- return false;
- }
-
- if ((a->vn | a->vm | a->vd) & 1) {
- return false;
- }
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- ptr1 = vfp_reg_ptr(true, a->vd);
- ptr2 = vfp_reg_ptr(true, a->vn);
- ptr3 = vfp_reg_ptr(true, a->vm);
- gen_helper_crypto_sha256h2(ptr1, ptr2, ptr3);
- tcg_temp_free_ptr(ptr1);
- tcg_temp_free_ptr(ptr2);
- tcg_temp_free_ptr(ptr3);
-
- return true;
-}
-
-static bool trans_SHA256SU1_3s(DisasContext *s, arg_SHA256SU1_3s *a)
-{
- TCGv_ptr ptr1, ptr2, ptr3;
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
- !dc_isar_feature(aa32_sha2, s)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vn | a->vm) & 0x10)) {
- return false;
+#define DO_SHA1(NAME, FUNC) \
+ WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \
+ static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \
+ { \
+ if (!dc_isar_feature(aa32_sha1, s)) { \
+ return false; \
+ } \
+ return do_3same(s, a, gen_##NAME##_3s); \
}
- if ((a->vn | a->vm | a->vd) & 1) {
- return false;
- }
+DO_SHA1(SHA1C, gen_helper_crypto_sha1c)
+DO_SHA1(SHA1P, gen_helper_crypto_sha1p)
+DO_SHA1(SHA1M, gen_helper_crypto_sha1m)
+DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0)
- if (!vfp_access_check(s)) {
- return true;
+#define DO_SHA2(NAME, FUNC) \
+ WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \
+ static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \
+ { \
+ if (!dc_isar_feature(aa32_sha2, s)) { \
+ return false; \
+ } \
+ return do_3same(s, a, gen_##NAME##_3s); \
}
- ptr1 = vfp_reg_ptr(true, a->vd);
- ptr2 = vfp_reg_ptr(true, a->vn);
- ptr3 = vfp_reg_ptr(true, a->vm);
- gen_helper_crypto_sha256su1(ptr1, ptr2, ptr3);
- tcg_temp_free_ptr(ptr1);
- tcg_temp_free_ptr(ptr2);
- tcg_temp_free_ptr(ptr3);
-
- return true;
-}
+DO_SHA2(SHA256H, gen_helper_crypto_sha256h)
+DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2)
+DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1)
#define DO_3SAME_64(INSN, FUNC) \
static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \
@@ -1310,3 +1220,609 @@ static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn)
DO_3S_FP_PAIR(VPADD, gen_helper_vfp_adds)
DO_3S_FP_PAIR(VPMAX, gen_helper_vfp_maxs)
DO_3S_FP_PAIR(VPMIN, gen_helper_vfp_mins)
+
+static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn)
+{
+ /* Handle a 2-reg-shift insn which can be vectorized. */
+ int vec_size = a->q ? 16 : 8;
+ int rd_ofs = neon_reg_offset(a->vd, 0);
+ int rm_ofs = neon_reg_offset(a->vm, 0);
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vm | a->vd) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size);
+ return true;
+}
+
+#define DO_2SH(INSN, FUNC) \
+ static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \
+ { \
+ return do_vector_2sh(s, a, FUNC); \
+ } \
+
+DO_2SH(VSHL, tcg_gen_gvec_shli)
+DO_2SH(VSLI, gen_gvec_sli)
+DO_2SH(VSRI, gen_gvec_sri)
+DO_2SH(VSRA_S, gen_gvec_ssra)
+DO_2SH(VSRA_U, gen_gvec_usra)
+DO_2SH(VRSHR_S, gen_gvec_srshr)
+DO_2SH(VRSHR_U, gen_gvec_urshr)
+DO_2SH(VRSRA_S, gen_gvec_srsra)
+DO_2SH(VRSRA_U, gen_gvec_ursra)
+
+static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a)
+{
+ /* Signed shift out of range results in all-sign-bits */
+ a->shift = MIN(a->shift, (8 << a->size) - 1);
+ return do_vector_2sh(s, a, tcg_gen_gvec_sari);
+}
+
+static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
+{
+ tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0);
+}
+
+static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a)
+{
+ /* Shift out of range is architecturally valid and results in zero. */
+ if (a->shift >= (8 << a->size)) {
+ return do_vector_2sh(s, a, gen_zero_rd_2sh);
+ } else {
+ return do_vector_2sh(s, a, tcg_gen_gvec_shri);
+ }
+}
+
+static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a,
+ NeonGenTwo64OpEnvFn *fn)
+{
+ /*
+ * 2-reg-and-shift operations, size == 3 case, where the
+ * function needs to be passed cpu_env.
+ */
+ TCGv_i64 constimm;
+ int pass;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vm | a->vd) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /*
+ * To avoid excessive duplication of ops we implement shift
+ * by immediate using the variable shift operations.
+ */
+ constimm = tcg_const_i64(dup_const(a->size, a->shift));
+
+ for (pass = 0; pass < a->q + 1; pass++) {
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ neon_load_reg64(tmp, a->vm + pass);
+ fn(tmp, cpu_env, tmp, constimm);
+ neon_store_reg64(tmp, a->vd + pass);
+ }
+ tcg_temp_free_i64(constimm);
+ return true;
+}
+
+static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a,
+ NeonGenTwoOpEnvFn *fn)
+{
+ /*
+ * 2-reg-and-shift operations, size < 3 case, where the
+ * helper needs to be passed cpu_env.
+ */
+ TCGv_i32 constimm;
+ int pass;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vm | a->vd) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /*
+ * To avoid excessive duplication of ops we implement shift
+ * by immediate using the variable shift operations.
+ */
+ constimm = tcg_const_i32(dup_const(a->size, a->shift));
+
+ for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
+ TCGv_i32 tmp = neon_load_reg(a->vm, pass);
+ fn(tmp, cpu_env, tmp, constimm);
+ neon_store_reg(a->vd, pass, tmp);
+ }
+ tcg_temp_free_i32(constimm);
+ return true;
+}
+
+#define DO_2SHIFT_ENV(INSN, FUNC) \
+ static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \
+ { \
+ return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \
+ } \
+ static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \
+ { \
+ static NeonGenTwoOpEnvFn * const fns[] = { \
+ gen_helper_neon_##FUNC##8, \
+ gen_helper_neon_##FUNC##16, \
+ gen_helper_neon_##FUNC##32, \
+ }; \
+ assert(a->size < ARRAY_SIZE(fns)); \
+ return do_2shift_env_32(s, a, fns[a->size]); \
+ }
+
+DO_2SHIFT_ENV(VQSHLU, qshlu_s)
+DO_2SHIFT_ENV(VQSHL_U, qshl_u)
+DO_2SHIFT_ENV(VQSHL_S, qshl_s)
+
+static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
+ NeonGenTwo64OpFn *shiftfn,
+ NeonGenNarrowEnvFn *narrowfn)
+{
+ /* 2-reg-and-shift narrowing-shift operations, size == 3 case */
+ TCGv_i64 constimm, rm1, rm2;
+ TCGv_i32 rd;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if (a->vm & 1) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /*
+ * This is always a right shift, and the shiftfn is always a
+ * left-shift helper, which thus needs the negated shift count.
+ */
+ constimm = tcg_const_i64(-a->shift);
+ rm1 = tcg_temp_new_i64();
+ rm2 = tcg_temp_new_i64();
+
+ /* Load both inputs first to avoid potential overwrite if rm == rd */
+ neon_load_reg64(rm1, a->vm);
+ neon_load_reg64(rm2, a->vm + 1);
+
+ shiftfn(rm1, rm1, constimm);
+ rd = tcg_temp_new_i32();
+ narrowfn(rd, cpu_env, rm1);
+ neon_store_reg(a->vd, 0, rd);
+
+ shiftfn(rm2, rm2, constimm);
+ rd = tcg_temp_new_i32();
+ narrowfn(rd, cpu_env, rm2);
+ neon_store_reg(a->vd, 1, rd);
+
+ tcg_temp_free_i64(rm1);
+ tcg_temp_free_i64(rm2);
+ tcg_temp_free_i64(constimm);
+
+ return true;
+}
+
+static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
+ NeonGenTwoOpFn *shiftfn,
+ NeonGenNarrowEnvFn *narrowfn)
+{
+ /* 2-reg-and-shift narrowing-shift operations, size < 3 case */
+ TCGv_i32 constimm, rm1, rm2, rm3, rm4;
+ TCGv_i64 rtmp;
+ uint32_t imm;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if (a->vm & 1) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /*
+ * This is always a right shift, and the shiftfn is always a
+ * left-shift helper, which thus needs the negated shift count
+ * duplicated into each lane of the immediate value.
+ */
+ if (a->size == 1) {
+ imm = (uint16_t)(-a->shift);
+ imm |= imm << 16;
+ } else {
+ /* size == 2 */
+ imm = -a->shift;
+ }
+ constimm = tcg_const_i32(imm);
+
+ /* Load all inputs first to avoid potential overwrite */
+ rm1 = neon_load_reg(a->vm, 0);
+ rm2 = neon_load_reg(a->vm, 1);
+ rm3 = neon_load_reg(a->vm + 1, 0);
+ rm4 = neon_load_reg(a->vm + 1, 1);
+ rtmp = tcg_temp_new_i64();
+
+ shiftfn(rm1, rm1, constimm);
+ shiftfn(rm2, rm2, constimm);
+
+ tcg_gen_concat_i32_i64(rtmp, rm1, rm2);
+ tcg_temp_free_i32(rm2);
+
+ narrowfn(rm1, cpu_env, rtmp);
+ neon_store_reg(a->vd, 0, rm1);
+
+ shiftfn(rm3, rm3, constimm);
+ shiftfn(rm4, rm4, constimm);
+ tcg_temp_free_i32(constimm);
+
+ tcg_gen_concat_i32_i64(rtmp, rm3, rm4);
+ tcg_temp_free_i32(rm4);
+
+ narrowfn(rm3, cpu_env, rtmp);
+ tcg_temp_free_i64(rtmp);
+ neon_store_reg(a->vd, 1, rm3);
+ return true;
+}
+
+#define DO_2SN_64(INSN, FUNC, NARROWFUNC) \
+ static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \
+ { \
+ return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \
+ }
+#define DO_2SN_32(INSN, FUNC, NARROWFUNC) \
+ static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \
+ { \
+ return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \
+ }
+
+static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
+{
+ tcg_gen_extrl_i64_i32(dest, src);
+}
+
+static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
+{
+ gen_helper_neon_narrow_u16(dest, src);
+}
+
+static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
+{
+ gen_helper_neon_narrow_u8(dest, src);
+}
+
+DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32)
+DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16)
+DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8)
+
+DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32)
+DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16)
+DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8)
+
+DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32)
+DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16)
+DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8)
+
+DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32)
+DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16)
+DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8)
+DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32)
+DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16)
+DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8)
+
+DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32)
+DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16)
+DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8)
+
+DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32)
+DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16)
+DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8)
+
+DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32)
+DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16)
+DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8)
+
+static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a,
+ NeonGenWidenFn *widenfn, bool u)
+{
+ TCGv_i64 tmp;
+ TCGv_i32 rm0, rm1;
+ uint64_t widen_mask = 0;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if (a->vd & 1) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /*
+ * This is a widen-and-shift operation. The shift is always less
+ * than the width of the source type, so after widening the input
+ * vector we can simply shift the whole 64-bit widened register,
+ * and then clear the potential overflow bits resulting from left
+ * bits of the narrow input appearing as right bits of the left
+ * neighbour narrow input. Calculate a mask of bits to clear.
+ */
+ if ((a->shift != 0) && (a->size < 2 || u)) {
+ int esize = 8 << a->size;
+ widen_mask = MAKE_64BIT_MASK(0, esize);
+ widen_mask >>= esize - a->shift;
+ widen_mask = dup_const(a->size + 1, widen_mask);
+ }
+
+ rm0 = neon_load_reg(a->vm, 0);
+ rm1 = neon_load_reg(a->vm, 1);
+ tmp = tcg_temp_new_i64();
+
+ widenfn(tmp, rm0);
+ if (a->shift != 0) {
+ tcg_gen_shli_i64(tmp, tmp, a->shift);
+ tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
+ }
+ neon_store_reg64(tmp, a->vd);
+
+ widenfn(tmp, rm1);
+ if (a->shift != 0) {
+ tcg_gen_shli_i64(tmp, tmp, a->shift);
+ tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
+ }
+ neon_store_reg64(tmp, a->vd + 1);
+ tcg_temp_free_i64(tmp);
+ return true;
+}
+
+static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a)
+{
+ NeonGenWidenFn *widenfn[] = {
+ gen_helper_neon_widen_s8,
+ gen_helper_neon_widen_s16,
+ tcg_gen_ext_i32_i64,
+ };
+ return do_vshll_2sh(s, a, widenfn[a->size], false);
+}
+
+static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a)
+{
+ NeonGenWidenFn *widenfn[] = {
+ gen_helper_neon_widen_u8,
+ gen_helper_neon_widen_u16,
+ tcg_gen_extu_i32_i64,
+ };
+ return do_vshll_2sh(s, a, widenfn[a->size], true);
+}
+
+static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a,
+ NeonGenTwoSingleOPFn *fn)
+{
+ /* FP operations in 2-reg-and-shift group */
+ TCGv_i32 tmp, shiftv;
+ TCGv_ptr fpstatus;
+ int pass;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vm) & 0x10)) {
+ return false;
+ }
+
+ if ((a->vm | a->vd) & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ fpstatus = get_fpstatus_ptr(1);
+ shiftv = tcg_const_i32(a->shift);
+ for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
+ tmp = neon_load_reg(a->vm, pass);
+ fn(tmp, tmp, shiftv, fpstatus);
+ neon_store_reg(a->vd, pass, tmp);
+ }
+ tcg_temp_free_ptr(fpstatus);
+ tcg_temp_free_i32(shiftv);
+ return true;
+}
+
+#define DO_FP_2SH(INSN, FUNC) \
+ static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \
+ { \
+ return do_fp_2sh(s, a, FUNC); \
+ }
+
+DO_FP_2SH(VCVT_SF, gen_helper_vfp_sltos)
+DO_FP_2SH(VCVT_UF, gen_helper_vfp_ultos)
+DO_FP_2SH(VCVT_FS, gen_helper_vfp_tosls_round_to_zero)
+DO_FP_2SH(VCVT_FU, gen_helper_vfp_touls_round_to_zero)
+
+static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
+{
+ /*
+ * Expand the encoded constant.
+ * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
+ * We choose to not special-case this and will behave as if a
+ * valid constant encoding of 0 had been given.
+ * cmode = 15 op = 1 must UNDEF; we assume decode has handled that.
+ */
+ switch (cmode) {
+ case 0: case 1:
+ /* no-op */
+ break;
+ case 2: case 3:
+ imm <<= 8;
+ break;
+ case 4: case 5:
+ imm <<= 16;
+ break;
+ case 6: case 7:
+ imm <<= 24;
+ break;
+ case 8: case 9:
+ imm |= imm << 16;
+ break;
+ case 10: case 11:
+ imm = (imm << 8) | (imm << 24);
+ break;
+ case 12:
+ imm = (imm << 8) | 0xff;
+ break;
+ case 13:
+ imm = (imm << 16) | 0xffff;
+ break;
+ case 14:
+ if (op) {
+ /*
+ * This is the only case where the top and bottom 32 bits
+ * of the encoded constant differ.
+ */
+ uint64_t imm64 = 0;
+ int n;
+
+ for (n = 0; n < 8; n++) {
+ if (imm & (1 << n)) {
+ imm64 |= (0xffULL << (n * 8));
+ }
+ }
+ return imm64;
+ }
+ imm |= (imm << 8) | (imm << 16) | (imm << 24);
+ break;
+ case 15:
+ imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
+ | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
+ break;
+ }
+ if (op) {
+ imm = ~imm;
+ }
+ return dup_const(MO_32, imm);
+}
+
+static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
+ GVecGen2iFn *fn)
+{
+ uint64_t imm;
+ int reg_ofs, vec_size;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
+ return false;
+ }
+
+ if (a->vd & a->q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ reg_ofs = neon_reg_offset(a->vd, 0);
+ vec_size = a->q ? 16 : 8;
+ imm = asimd_imm_const(a->imm, a->cmode, a->op);
+
+ fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size);
+ return true;
+}
+
+static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs,
+ int64_t c, uint32_t oprsz, uint32_t maxsz)
+{
+ tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c);
+}
+
+static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a)
+{
+ /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
+ GVecGen2iFn *fn;
+
+ if ((a->cmode & 1) && a->cmode < 12) {
+ /* for op=1, the imm will be inverted, so BIC becomes AND. */
+ fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori;
+ } else {
+ /* There is one unallocated cmode/op combination in this space */
+ if (a->cmode == 15 && a->op == 1) {
+ return false;
+ }
+ fn = gen_VMOV_1r;
+ }
+ return do_1reg_imm(s, a, fn);
+}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index c8296116d4..bcdfec34d2 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -3011,29 +3011,6 @@ static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1)
}
}
-#define GEN_NEON_INTEGER_OP_ENV(name) do { \
- switch ((size << 1) | u) { \
- case 0: \
- gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \
- break; \
- case 1: \
- gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \
- break; \
- case 2: \
- gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \
- break; \
- case 3: \
- gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \
- break; \
- case 4: \
- gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \
- break; \
- case 5: \
- gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \
- break; \
- default: return 1; \
- }} while (0)
-
static TCGv_i32 neon_load_scratch(int scratch)
{
TCGv_i32 tmp = tcg_temp_new_i32();
@@ -3224,40 +3201,6 @@ static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
}
}
-static inline void gen_neon_shift_narrow(int size, TCGv_i32 var, TCGv_i32 shift,
- int q, int u)
-{
- if (q) {
- if (u) {
- switch (size) {
- case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
- case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
- default: abort();
- }
- } else {
- switch (size) {
- case 1: gen_helper_neon_rshl_s16(var, var, shift); break;
- case 2: gen_helper_neon_rshl_s32(var, var, shift); break;
- default: abort();
- }
- }
- } else {
- if (u) {
- switch (size) {
- case 1: gen_helper_neon_shl_u16(var, var, shift); break;
- case 2: gen_ushl_i32(var, var, shift); break;
- default: abort();
- }
- } else {
- switch (size) {
- case 1: gen_helper_neon_shl_s16(var, var, shift); break;
- case 2: gen_sshl_i32(var, var, shift); break;
- default: abort();
- }
- }
- }
-}
-
static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u)
{
if (u) {
@@ -5250,14 +5193,12 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
int q;
int rd, rn, rm, rd_ofs, rn_ofs, rm_ofs;
int size;
- int shift;
int pass;
- int count;
int u;
int vec_size;
uint32_t imm;
TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5;
- TCGv_ptr ptr1, ptr2;
+ TCGv_ptr ptr1;
TCGv_i64 tmp64;
if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
@@ -5291,433 +5232,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
/* Three register same length: handled by decodetree */
return 1;
} else if (insn & (1 << 4)) {
- if ((insn & 0x00380080) != 0) {
- /* Two registers and shift. */
- op = (insn >> 8) & 0xf;
- if (insn & (1 << 7)) {
- /* 64-bit shift. */
- if (op > 7) {
- return 1;
- }
- size = 3;
- } else {
- size = 2;
- while ((insn & (1 << (size + 19))) == 0)
- size--;
- }
- shift = (insn >> 16) & ((1 << (3 + size)) - 1);
- if (op < 8) {
- /* Shift by immediate:
- VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */
- if (q && ((rd | rm) & 1)) {
- return 1;
- }
- if (!u && (op == 4 || op == 6)) {
- return 1;
- }
- /* Right shifts are encoded as N - shift, where N is the
- element size in bits. */
- if (op <= 4) {
- shift = shift - (1 << (size + 3));
- }
-
- switch (op) {
- case 0: /* VSHR */
- /* Right shift comes here negative. */
- shift = -shift;
- /* Shifts larger than the element size are architecturally
- * valid. Unsigned results in all zeros; signed results
- * in all sign bits.
- */
- if (!u) {
- tcg_gen_gvec_sari(size, rd_ofs, rm_ofs,
- MIN(shift, (8 << size) - 1),
- vec_size, vec_size);
- } else if (shift >= 8 << size) {
- tcg_gen_gvec_dup_imm(MO_8, rd_ofs, vec_size,
- vec_size, 0);
- } else {
- tcg_gen_gvec_shri(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- }
- return 0;
-
- case 1: /* VSRA */
- /* Right shift comes here negative. */
- shift = -shift;
- if (u) {
- gen_gvec_usra(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- } else {
- gen_gvec_ssra(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- }
- return 0;
-
- case 2: /* VRSHR */
- /* Right shift comes here negative. */
- shift = -shift;
- if (u) {
- gen_gvec_urshr(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- } else {
- gen_gvec_srshr(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- }
- return 0;
-
- case 3: /* VRSRA */
- /* Right shift comes here negative. */
- shift = -shift;
- if (u) {
- gen_gvec_ursra(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- } else {
- gen_gvec_srsra(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- }
- return 0;
-
- case 4: /* VSRI */
- if (!u) {
- return 1;
- }
- /* Right shift comes here negative. */
- shift = -shift;
- gen_gvec_sri(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- return 0;
-
- case 5: /* VSHL, VSLI */
- if (u) { /* VSLI */
- gen_gvec_sli(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- } else { /* VSHL */
- tcg_gen_gvec_shli(size, rd_ofs, rm_ofs, shift,
- vec_size, vec_size);
- }
- return 0;
- }
-
- if (size == 3) {
- count = q + 1;
- } else {
- count = q ? 4: 2;
- }
-
- /* To avoid excessive duplication of ops we implement shift
- * by immediate using the variable shift operations.
- */
- imm = dup_const(size, shift);
-
- for (pass = 0; pass < count; pass++) {
- if (size == 3) {
- neon_load_reg64(cpu_V0, rm + pass);
- tcg_gen_movi_i64(cpu_V1, imm);
- switch (op) {
- case 6: /* VQSHLU */
- gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
- cpu_V0, cpu_V1);
- break;
- case 7: /* VQSHL */
- if (u) {
- gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
- cpu_V0, cpu_V1);
- } else {
- gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
- cpu_V0, cpu_V1);
- }
- break;
- default:
- g_assert_not_reached();
- }
- neon_store_reg64(cpu_V0, rd + pass);
- } else { /* size < 3 */
- /* Operands in T0 and T1. */
- tmp = neon_load_reg(rm, pass);
- tmp2 = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp2, imm);
- switch (op) {
- case 6: /* VQSHLU */
- switch (size) {
- case 0:
- gen_helper_neon_qshlu_s8(tmp, cpu_env,
- tmp, tmp2);
- break;
- case 1:
- gen_helper_neon_qshlu_s16(tmp, cpu_env,
- tmp, tmp2);
- break;
- case 2:
- gen_helper_neon_qshlu_s32(tmp, cpu_env,
- tmp, tmp2);
- break;
- default:
- abort();
- }
- break;
- case 7: /* VQSHL */
- GEN_NEON_INTEGER_OP_ENV(qshl);
- break;
- default:
- g_assert_not_reached();
- }
- tcg_temp_free_i32(tmp2);
- neon_store_reg(rd, pass, tmp);
- }
- } /* for pass */
- } else if (op < 10) {
- /* Shift by immediate and narrow:
- VSHRN, VRSHRN, VQSHRN, VQRSHRN. */
- int input_unsigned = (op == 8) ? !u : u;
- if (rm & 1) {
- return 1;
- }
- shift = shift - (1 << (size + 3));
- size++;
- if (size == 3) {
- tmp64 = tcg_const_i64(shift);
- neon_load_reg64(cpu_V0, rm);
- neon_load_reg64(cpu_V1, rm + 1);
- for (pass = 0; pass < 2; pass++) {
- TCGv_i64 in;
- if (pass == 0) {
- in = cpu_V0;
- } else {
- in = cpu_V1;
- }
- if (q) {
- if (input_unsigned) {
- gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);
- } else {
- gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);
- }
- } else {
- if (input_unsigned) {
- gen_ushl_i64(cpu_V0, in, tmp64);
- } else {
- gen_sshl_i64(cpu_V0, in, tmp64);
- }
- }
- tmp = tcg_temp_new_i32();
- gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
- neon_store_reg(rd, pass, tmp);
- } /* for pass */
- tcg_temp_free_i64(tmp64);
- } else {
- if (size == 1) {
- imm = (uint16_t)shift;
- imm |= imm << 16;
- } else {
- /* size == 2 */
- imm = (uint32_t)shift;
- }
- tmp2 = tcg_const_i32(imm);
- tmp4 = neon_load_reg(rm + 1, 0);
- tmp5 = neon_load_reg(rm + 1, 1);
- for (pass = 0; pass < 2; pass++) {
- if (pass == 0) {
- tmp = neon_load_reg(rm, 0);
- } else {
- tmp = tmp4;
- }
- gen_neon_shift_narrow(size, tmp, tmp2, q,
- input_unsigned);
- if (pass == 0) {
- tmp3 = neon_load_reg(rm, 1);
- } else {
- tmp3 = tmp5;
- }
- gen_neon_shift_narrow(size, tmp3, tmp2, q,
- input_unsigned);
- tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(tmp3);
- tmp = tcg_temp_new_i32();
- gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
- neon_store_reg(rd, pass, tmp);
- } /* for pass */
- tcg_temp_free_i32(tmp2);
- }
- } else if (op == 10) {
- /* VSHLL, VMOVL */
- if (q || (rd & 1)) {
- return 1;
- }
- tmp = neon_load_reg(rm, 0);
- tmp2 = neon_load_reg(rm, 1);
- for (pass = 0; pass < 2; pass++) {
- if (pass == 1)
- tmp = tmp2;
-
- gen_neon_widen(cpu_V0, tmp, size, u);
-
- if (shift != 0) {
- /* The shift is less than the width of the source
- type, so we can just shift the whole register. */
- tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
- /* Widen the result of shift: we need to clear
- * the potential overflow bits resulting from
- * left bits of the narrow input appearing as
- * right bits of left the neighbour narrow
- * input. */
- if (size < 2 || !u) {
- uint64_t imm64;
- if (size == 0) {
- imm = (0xffu >> (8 - shift));
- imm |= imm << 16;
- } else if (size == 1) {
- imm = 0xffff >> (16 - shift);
- } else {
- /* size == 2 */
- imm = 0xffffffff >> (32 - shift);
- }
- if (size < 2) {
- imm64 = imm | (((uint64_t)imm) << 32);
- } else {
- imm64 = imm;
- }
- tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
- }
- }
- neon_store_reg64(cpu_V0, rd + pass);
- }
- } else if (op >= 14) {
- /* VCVT fixed-point. */
- TCGv_ptr fpst;
- TCGv_i32 shiftv;
- VFPGenFixPointFn *fn;
-
- if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
- return 1;
- }
-
- if (!(op & 1)) {
- if (u) {
- fn = gen_helper_vfp_ultos;
- } else {
- fn = gen_helper_vfp_sltos;
- }
- } else {
- if (u) {
- fn = gen_helper_vfp_touls_round_to_zero;
- } else {
- fn = gen_helper_vfp_tosls_round_to_zero;
- }
- }
-
- /* We have already masked out the must-be-1 top bit of imm6,
- * hence this 32-shift where the ARM ARM has 64-imm6.
- */
- shift = 32 - shift;
- fpst = get_fpstatus_ptr(1);
- shiftv = tcg_const_i32(shift);
- for (pass = 0; pass < (q ? 4 : 2); pass++) {
- TCGv_i32 tmpf = neon_load_reg(rm, pass);
- fn(tmpf, tmpf, shiftv, fpst);
- neon_store_reg(rd, pass, tmpf);
- }
- tcg_temp_free_ptr(fpst);
- tcg_temp_free_i32(shiftv);
- } else {
- return 1;
- }
- } else { /* (insn & 0x00380080) == 0 */
- int invert, reg_ofs, vec_size;
-
- if (q && (rd & 1)) {
- return 1;
- }
-
- op = (insn >> 8) & 0xf;
- /* One register and immediate. */
- imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
- invert = (insn & (1 << 5)) != 0;
- /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
- * We choose to not special-case this and will behave as if a
- * valid constant encoding of 0 had been given.
- */
- switch (op) {
- case 0: case 1:
- /* no-op */
- break;
- case 2: case 3:
- imm <<= 8;
- break;
- case 4: case 5:
- imm <<= 16;
- break;
- case 6: case 7:
- imm <<= 24;
- break;
- case 8: case 9:
- imm |= imm << 16;
- break;
- case 10: case 11:
- imm = (imm << 8) | (imm << 24);
- break;
- case 12:
- imm = (imm << 8) | 0xff;
- break;
- case 13:
- imm = (imm << 16) | 0xffff;
- break;
- case 14:
- imm |= (imm << 8) | (imm << 16) | (imm << 24);
- if (invert) {
- imm = ~imm;
- }
- break;
- case 15:
- if (invert) {
- return 1;
- }
- imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
- | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
- break;
- }
- if (invert) {
- imm = ~imm;
- }
-
- reg_ofs = neon_reg_offset(rd, 0);
- vec_size = q ? 16 : 8;
-
- if (op & 1 && op < 12) {
- if (invert) {
- /* The immediate value has already been inverted,
- * so BIC becomes AND.
- */
- tcg_gen_gvec_andi(MO_32, reg_ofs, reg_ofs, imm,
- vec_size, vec_size);
- } else {
- tcg_gen_gvec_ori(MO_32, reg_ofs, reg_ofs, imm,
- vec_size, vec_size);
- }
- } else {
- /* VMOV, VMVN. */
- if (op == 14 && invert) {
- TCGv_i64 t64 = tcg_temp_new_i64();
-
- for (pass = 0; pass <= q; ++pass) {
- uint64_t val = 0;
- int n;
-
- for (n = 0; n < 8; n++) {
- if (imm & (1 << (n + pass * 8))) {
- val |= 0xffull << (n * 8);
- }
- }
- tcg_gen_movi_i64(t64, val);
- neon_store_reg64(t64, rd + pass);
- }
- tcg_temp_free_i64(t64);
- } else {
- tcg_gen_gvec_dup_imm(MO_32, reg_ofs, vec_size,
- vec_size, imm);
- }
- }
- }
+ /* Two registers and shift or reg and imm: handled by decodetree */
+ return 1;
} else { /* (insn & 0x00800010 == 0x00800000) */
if (size != 3) {
op = (insn >> 8) & 0xf;
@@ -6350,34 +5866,30 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) {
return 1;
}
- ptr1 = vfp_reg_ptr(true, rd);
- ptr2 = vfp_reg_ptr(true, rm);
-
- /* Bit 6 is the lowest opcode bit; it distinguishes between
- * encryption (AESE/AESMC) and decryption (AESD/AESIMC)
- */
- tmp3 = tcg_const_i32(extract32(insn, 6, 1));
-
+ /*
+ * Bit 6 is the lowest opcode bit; it distinguishes
+ * between encryption (AESE/AESMC) and decryption
+ * (AESD/AESIMC).
+ */
if (op == NEON_2RM_AESE) {
- gen_helper_crypto_aese(ptr1, ptr2, tmp3);
+ tcg_gen_gvec_3_ool(vfp_reg_offset(true, rd),
+ vfp_reg_offset(true, rd),
+ vfp_reg_offset(true, rm),
+ 16, 16, extract32(insn, 6, 1),
+ gen_helper_crypto_aese);
} else {
- gen_helper_crypto_aesmc(ptr1, ptr2, tmp3);
+ tcg_gen_gvec_2_ool(vfp_reg_offset(true, rd),
+ vfp_reg_offset(true, rm),
+ 16, 16, extract32(insn, 6, 1),
+ gen_helper_crypto_aesmc);
}
- tcg_temp_free_ptr(ptr1);
- tcg_temp_free_ptr(ptr2);
- tcg_temp_free_i32(tmp3);
break;
case NEON_2RM_SHA1H:
if (!dc_isar_feature(aa32_sha1, s) || ((rm | rd) & 1)) {
return 1;
}
- ptr1 = vfp_reg_ptr(true, rd);
- ptr2 = vfp_reg_ptr(true, rm);
-
- gen_helper_crypto_sha1h(ptr1, ptr2);
-
- tcg_temp_free_ptr(ptr1);
- tcg_temp_free_ptr(ptr2);
+ tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0,
+ gen_helper_crypto_sha1h);
break;
case NEON_2RM_SHA1SU1:
if ((rm | rd) & 1) {
@@ -6391,17 +5903,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
} else if (!dc_isar_feature(aa32_sha1, s)) {
return 1;
}
- ptr1 = vfp_reg_ptr(true, rd);
- ptr2 = vfp_reg_ptr(true, rm);
- if (q) {
- gen_helper_crypto_sha256su0(ptr1, ptr2);
- } else {
- gen_helper_crypto_sha1su1(ptr1, ptr2);
- }
- tcg_temp_free_ptr(ptr1);
- tcg_temp_free_ptr(ptr2);
+ tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0,
+ q ? gen_helper_crypto_sha256su0
+ : gen_helper_crypto_sha1su1);
break;
-
case NEON_2RM_VMVN:
tcg_gen_gvec_not(0, rd_ofs, rm_ofs, vec_size, vec_size);
break;
diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c
index 50a499299f..7d76412ee0 100644
--- a/target/arm/vec_helper.c
+++ b/target/arm/vec_helper.c
@@ -22,7 +22,7 @@
#include "exec/helper-proto.h"
#include "tcg/tcg-gvec-desc.h"
#include "fpu/softfloat.h"
-
+#include "vec_internal.h"
/* Note that vector data is stored in host-endian 64-bit chunks,
so addressing units smaller than that needs a host-endian fixup. */
@@ -36,16 +36,6 @@
#define H4(x) (x)
#endif
-static void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz)
-{
- uint64_t *d = vd + opr_sz;
- uintptr_t i;
-
- for (i = opr_sz; i < max_sz; i += 8) {
- *d++ = 0;
- }
-}
-
/* Signed saturating rounding doubling multiply-accumulate high half, 16-bit */
static int16_t inl_qrdmlah_s16(int16_t src1, int16_t src2,
int16_t src3, uint32_t *sat)
diff --git a/target/arm/vec_internal.h b/target/arm/vec_internal.h
new file mode 100644
index 0000000000..00a8277765
--- /dev/null
+++ b/target/arm/vec_internal.h
@@ -0,0 +1,33 @@
+/*
+ * ARM AdvSIMD / SVE Vector Helpers
+ *
+ * Copyright (c) 2020 Linaro
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARM_VEC_INTERNALS_H
+#define TARGET_ARM_VEC_INTERNALS_H
+
+static inline void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz)
+{
+ uint64_t *d = vd + opr_sz;
+ uintptr_t i;
+
+ for (i = opr_sz; i < max_sz; i += 8) {
+ *d++ = 0;
+ }
+}
+
+#endif /* TARGET_ARM_VEC_INTERNALS_H */
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index dd31c1de5f..ba05da3f2e 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5078,7 +5078,7 @@ static void x86_cpu_apply_version_props(X86CPU *cpu, X86CPUModel *model)
/* Load data from X86CPUDefinition into a X86CPU object
*/
-static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model, Error **errp)
+static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
{
X86CPUDefinition *def = model->cpudef;
CPUX86State *env = &cpu->env;
@@ -5092,13 +5092,19 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model, Error **errp)
*/
/* CPU models only set _minimum_ values for level/xlevel: */
- object_property_set_uint(OBJECT(cpu), def->level, "min-level", errp);
- object_property_set_uint(OBJECT(cpu), def->xlevel, "min-xlevel", errp);
-
- object_property_set_int(OBJECT(cpu), def->family, "family", errp);
- object_property_set_int(OBJECT(cpu), def->model, "model", errp);
- object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp);
- object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
+ object_property_set_uint(OBJECT(cpu), def->level, "min-level",
+ &error_abort);
+ object_property_set_uint(OBJECT(cpu), def->xlevel, "min-xlevel",
+ &error_abort);
+
+ object_property_set_int(OBJECT(cpu), def->family, "family",
+ &error_abort);
+ object_property_set_int(OBJECT(cpu), def->model, "model",
+ &error_abort);
+ object_property_set_int(OBJECT(cpu), def->stepping, "stepping",
+ &error_abort);
+ object_property_set_str(OBJECT(cpu), def->model_id, "model-id",
+ &error_abort);
for (w = 0; w < FEATURE_WORDS; w++) {
env->features[w] = def->features[w];
}
@@ -5135,7 +5141,8 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model, Error **errp)
vendor = host_vendor;
}
- object_property_set_str(OBJECT(cpu), vendor, "vendor", errp);
+ object_property_set_str(OBJECT(cpu), vendor, "vendor",
+ &error_abort);
x86_cpu_apply_version_props(cpu, model);
}
@@ -6979,7 +6986,7 @@ static void x86_cpu_initfn(Object *obj)
object_property_add_alias(obj, "sse4_2", obj, "sse4.2");
if (xcc->model) {
- x86_cpu_load_model(cpu, xcc->model, &error_abort);
+ x86_cpu_load_model(cpu, xcc->model);
}
}
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 36e6c704d1..9acf60dfd4 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -641,6 +641,11 @@ void HELPER(fatanh)(CPUM68KState *env, FPReg *res, FPReg *val)
res->d = floatx80_atanh(val->d, &env->fp_status);
}
+void HELPER(fetoxm1)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_etoxm1(val->d, &env->fp_status);
+}
+
void HELPER(ftanh)(CPUM68KState *env, FPReg *res, FPReg *val)
{
res->d = floatx80_tanh(val->d, &env->fp_status);
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index feee7be626..77808497a9 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -83,6 +83,7 @@ DEF_HELPER_3(fatan, void, env, fp, fp)
DEF_HELPER_3(fasin, void, env, fp, fp)
DEF_HELPER_3(facos, void, env, fp, fp)
DEF_HELPER_3(fatanh, void, env, fp, fp)
+DEF_HELPER_3(fetoxm1, void, env, fp, fp)
DEF_HELPER_3(ftanh, void, env, fp, fp)
DEF_HELPER_3(fsinh, void, env, fp, fp)
DEF_HELPER_3(fcosh, void, env, fp, fp)
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 0f80888203..3fc67aa452 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -4936,6 +4936,20 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
gen_store_fcr(s, AREG(insn, 0), mask);
}
return;
+ case 7: /* Immediate */
+ if (REG(insn, 0) == 4) {
+ if (is_write ||
+ (mask != M68K_FPIAR && mask != M68K_FPSR &&
+ mask != M68K_FPCR)) {
+ gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
+ return;
+ }
+ tmp = tcg_const_i32(read_im32(env, s));
+ gen_store_fcr(s, tmp, mask);
+ tcg_temp_free(tmp);
+ return;
+ }
+ break;
default:
break;
}
@@ -5146,6 +5160,9 @@ DISAS_INSN(fpu)
case 0x06: /* flognp1 */
gen_helper_flognp1(cpu_env, cpu_dest, cpu_src);
break;
+ case 0x08: /* fetoxm1 */
+ gen_helper_fetoxm1(cpu_env, cpu_dest, cpu_src);
+ break;
case 0x09: /* ftanh */
gen_helper_ftanh(cpu_env, cpu_dest, cpu_src);
break;
diff --git a/target/mips/cpu-param.h b/target/mips/cpu-param.h
index 308660d29d..9c4a6ea45e 100644
--- a/target/mips/cpu-param.h
+++ b/target/mips/cpu-param.h
@@ -23,7 +23,12 @@
# define TARGET_VIRT_ADDR_SPACE_BITS 32
#endif
#endif
+#ifdef CONFIG_USER_ONLY
#define TARGET_PAGE_BITS 12
+#else
+#define TARGET_PAGE_BITS_VARY
+#define TARGET_PAGE_BITS_MIN 12
+#endif
#define NB_MMU_MODES 4
#endif
diff --git a/target/mips/kvm.c b/target/mips/kvm.c
index de3e26ef1f..96cfa10cf2 100644
--- a/target/mips/kvm.c
+++ b/target/mips/kvm.c
@@ -245,10 +245,16 @@ int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level)
(KVM_REG_MIPS_CP0 | KVM_REG_SIZE_U64 | (8 * (_R) + (_S)))
#define KVM_REG_MIPS_CP0_INDEX MIPS_CP0_32(0, 0)
+#define KVM_REG_MIPS_CP0_RANDOM MIPS_CP0_32(1, 0)
#define KVM_REG_MIPS_CP0_CONTEXT MIPS_CP0_64(4, 0)
#define KVM_REG_MIPS_CP0_USERLOCAL MIPS_CP0_64(4, 2)
#define KVM_REG_MIPS_CP0_PAGEMASK MIPS_CP0_32(5, 0)
+#define KVM_REG_MIPS_CP0_PAGEGRAIN MIPS_CP0_32(5, 1)
+#define KVM_REG_MIPS_CP0_PWBASE MIPS_CP0_64(5, 5)
+#define KVM_REG_MIPS_CP0_PWFIELD MIPS_CP0_64(5, 6)
+#define KVM_REG_MIPS_CP0_PWSIZE MIPS_CP0_64(5, 7)
#define KVM_REG_MIPS_CP0_WIRED MIPS_CP0_32(6, 0)
+#define KVM_REG_MIPS_CP0_PWCTL MIPS_CP0_32(6, 6)
#define KVM_REG_MIPS_CP0_HWRENA MIPS_CP0_32(7, 0)
#define KVM_REG_MIPS_CP0_BADVADDR MIPS_CP0_64(8, 0)
#define KVM_REG_MIPS_CP0_COUNT MIPS_CP0_32(9, 0)
@@ -258,13 +264,22 @@ int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level)
#define KVM_REG_MIPS_CP0_CAUSE MIPS_CP0_32(13, 0)
#define KVM_REG_MIPS_CP0_EPC MIPS_CP0_64(14, 0)
#define KVM_REG_MIPS_CP0_PRID MIPS_CP0_32(15, 0)
+#define KVM_REG_MIPS_CP0_EBASE MIPS_CP0_64(15, 1)
#define KVM_REG_MIPS_CP0_CONFIG MIPS_CP0_32(16, 0)
#define KVM_REG_MIPS_CP0_CONFIG1 MIPS_CP0_32(16, 1)
#define KVM_REG_MIPS_CP0_CONFIG2 MIPS_CP0_32(16, 2)
#define KVM_REG_MIPS_CP0_CONFIG3 MIPS_CP0_32(16, 3)
#define KVM_REG_MIPS_CP0_CONFIG4 MIPS_CP0_32(16, 4)
#define KVM_REG_MIPS_CP0_CONFIG5 MIPS_CP0_32(16, 5)
+#define KVM_REG_MIPS_CP0_CONFIG6 MIPS_CP0_32(16, 6)
+#define KVM_REG_MIPS_CP0_XCONTEXT MIPS_CP0_64(20, 0)
#define KVM_REG_MIPS_CP0_ERROREPC MIPS_CP0_64(30, 0)
+#define KVM_REG_MIPS_CP0_KSCRATCH1 MIPS_CP0_64(31, 2)
+#define KVM_REG_MIPS_CP0_KSCRATCH2 MIPS_CP0_64(31, 3)
+#define KVM_REG_MIPS_CP0_KSCRATCH3 MIPS_CP0_64(31, 4)
+#define KVM_REG_MIPS_CP0_KSCRATCH4 MIPS_CP0_64(31, 5)
+#define KVM_REG_MIPS_CP0_KSCRATCH5 MIPS_CP0_64(31, 6)
+#define KVM_REG_MIPS_CP0_KSCRATCH6 MIPS_CP0_64(31, 7)
static inline int kvm_mips_put_one_reg(CPUState *cs, uint64_t reg_id,
int32_t *addr)
@@ -394,6 +409,29 @@ static inline int kvm_mips_get_one_ureg64(CPUState *cs, uint64_t reg_id,
(1U << CP0C5_UFE) | \
(1U << CP0C5_FRE) | \
(1U << CP0C5_UFR))
+#define KVM_REG_MIPS_CP0_CONFIG6_MASK ((1U << CP0C6_BPPASS) | \
+ (0x3fU << CP0C6_KPOS) | \
+ (1U << CP0C6_KE) | \
+ (1U << CP0C6_VTLBONLY) | \
+ (1U << CP0C6_LASX) | \
+ (1U << CP0C6_SSEN) | \
+ (1U << CP0C6_DISDRTIME) | \
+ (1U << CP0C6_PIXNUEN) | \
+ (1U << CP0C6_SCRAND) | \
+ (1U << CP0C6_LLEXCEN) | \
+ (1U << CP0C6_DISVC) | \
+ (1U << CP0C6_VCLRU) | \
+ (1U << CP0C6_DCLRU) | \
+ (1U << CP0C6_PIXUEN) | \
+ (1U << CP0C6_DISBLKLYEN) | \
+ (1U << CP0C6_UMEMUALEN) | \
+ (1U << CP0C6_SFBEN) | \
+ (1U << CP0C6_FLTINT) | \
+ (1U << CP0C6_VLTINT) | \
+ (1U << CP0C6_DISBTB) | \
+ (3U << CP0C6_STPREFCTL) | \
+ (1U << CP0C6_INSTPREF) | \
+ (1U << CP0C6_DATAPREF))
static inline int kvm_mips_change_one_reg(CPUState *cs, uint64_t reg_id,
int32_t *addr, int32_t mask)
@@ -729,6 +767,11 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level)
DPRINTF("%s: Failed to put CP0_INDEX (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_RANDOM, &env->CP0_Random);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_RANDOM (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_CONTEXT,
&env->CP0_Context);
if (err < 0) {
@@ -747,11 +790,40 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level)
DPRINTF("%s: Failed to put CP0_PAGEMASK (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_PAGEGRAIN,
+ &env->CP0_PageGrain);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_PAGEGRAIN (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_PWBASE,
+ &env->CP0_PWBase);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_PWBASE (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_PWFIELD,
+ &env->CP0_PWField);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_PWField (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_PWSIZE,
+ &env->CP0_PWSize);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_PWSIZE (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_WIRED, &env->CP0_Wired);
if (err < 0) {
DPRINTF("%s: Failed to put CP0_WIRED (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_PWCTL, &env->CP0_PWCtl);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_PWCTL (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_CP0_HWRENA, &env->CP0_HWREna);
if (err < 0) {
DPRINTF("%s: Failed to put CP0_HWRENA (%d)\n", __func__, err);
@@ -799,6 +871,11 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level)
DPRINTF("%s: Failed to put CP0_PRID (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_EBASE, &env->CP0_EBase);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_EBASE (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_change_one_reg(cs, KVM_REG_MIPS_CP0_CONFIG,
&env->CP0_Config0,
KVM_REG_MIPS_CP0_CONFIG_MASK);
@@ -841,12 +918,61 @@ static int kvm_mips_put_cp0_registers(CPUState *cs, int level)
DPRINTF("%s: Failed to change CP0_CONFIG5 (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_change_one_reg(cs, KVM_REG_MIPS_CP0_CONFIG6,
+ &env->CP0_Config6,
+ KVM_REG_MIPS_CP0_CONFIG6_MASK);
+ if (err < 0) {
+ DPRINTF("%s: Failed to change CP0_CONFIG6 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_XCONTEXT,
+ &env->CP0_XContext);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_XCONTEXT (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_ERROREPC,
&env->CP0_ErrorEPC);
if (err < 0) {
DPRINTF("%s: Failed to put CP0_ERROREPC (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH1,
+ &env->CP0_KScratch[0]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_KSCRATCH1 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH2,
+ &env->CP0_KScratch[1]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_KSCRATCH2 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH3,
+ &env->CP0_KScratch[2]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_KSCRATCH3 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH4,
+ &env->CP0_KScratch[3]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_KSCRATCH4 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH5,
+ &env->CP0_KScratch[4]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_KSCRATCH5 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_put_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH6,
+ &env->CP0_KScratch[5]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to put CP0_KSCRATCH6 (%d)\n", __func__, err);
+ ret = err;
+ }
return ret;
}
@@ -862,6 +988,11 @@ static int kvm_mips_get_cp0_registers(CPUState *cs)
DPRINTF("%s: Failed to get CP0_INDEX (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_RANDOM, &env->CP0_Random);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_RANDOM (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_CONTEXT,
&env->CP0_Context);
if (err < 0) {
@@ -880,11 +1011,40 @@ static int kvm_mips_get_cp0_registers(CPUState *cs)
DPRINTF("%s: Failed to get CP0_PAGEMASK (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_PAGEGRAIN,
+ &env->CP0_PageGrain);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_PAGEGRAIN (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_PWBASE,
+ &env->CP0_PWBase);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_PWBASE (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_PWFIELD,
+ &env->CP0_PWField);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_PWFIELD (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_PWSIZE,
+ &env->CP0_PWSize);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_PWSIZE (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_WIRED, &env->CP0_Wired);
if (err < 0) {
DPRINTF("%s: Failed to get CP0_WIRED (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_PWCTL, &env->CP0_PWCtl);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_PWCtl (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_HWRENA, &env->CP0_HWREna);
if (err < 0) {
DPRINTF("%s: Failed to get CP0_HWRENA (%d)\n", __func__, err);
@@ -932,6 +1092,11 @@ static int kvm_mips_get_cp0_registers(CPUState *cs)
DPRINTF("%s: Failed to get CP0_PRID (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_EBASE, &env->CP0_EBase);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_EBASE (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_CONFIG, &env->CP0_Config0);
if (err < 0) {
DPRINTF("%s: Failed to get CP0_CONFIG (%d)\n", __func__, err);
@@ -962,12 +1127,59 @@ static int kvm_mips_get_cp0_registers(CPUState *cs)
DPRINTF("%s: Failed to get CP0_CONFIG5 (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_CP0_CONFIG6, &env->CP0_Config6);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_CONFIG6 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_XCONTEXT,
+ &env->CP0_XContext);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_XCONTEXT (%d)\n", __func__, err);
+ ret = err;
+ }
err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_ERROREPC,
&env->CP0_ErrorEPC);
if (err < 0) {
DPRINTF("%s: Failed to get CP0_ERROREPC (%d)\n", __func__, err);
ret = err;
}
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH1,
+ &env->CP0_KScratch[0]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_KSCRATCH1 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH2,
+ &env->CP0_KScratch[1]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_KSCRATCH2 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH3,
+ &env->CP0_KScratch[2]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_KSCRATCH3 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH4,
+ &env->CP0_KScratch[3]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_KSCRATCH4 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH5,
+ &env->CP0_KScratch[4]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_KSCRATCH5 (%d)\n", __func__, err);
+ ret = err;
+ }
+ err = kvm_mips_get_one_ulreg(cs, KVM_REG_MIPS_CP0_KSCRATCH6,
+ &env->CP0_KScratch[5]);
+ if (err < 0) {
+ DPRINTF("%s: Failed to get CP0_KSCRATCH6 (%d)\n", __func__, err);
+ ret = err;
+ }
return ret;
}
diff --git a/target/mips/machine.c b/target/mips/machine.c
index 8d5b18bea2..5b23e3e912 100644
--- a/target/mips/machine.c
+++ b/target/mips/machine.c
@@ -212,8 +212,8 @@ const VMStateDescription vmstate_tlb = {
const VMStateDescription vmstate_mips_cpu = {
.name = "cpu",
- .version_id = 19,
- .minimum_version_id = 19,
+ .version_id = 20,
+ .minimum_version_id = 20,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
/* Active TC */
@@ -289,6 +289,8 @@ const VMStateDescription vmstate_mips_cpu = {
VMSTATE_INT32(env.CP0_Config1, MIPSCPU),
VMSTATE_INT32(env.CP0_Config2, MIPSCPU),
VMSTATE_INT32(env.CP0_Config3, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Config4, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Config5, MIPSCPU),
VMSTATE_INT32(env.CP0_Config6, MIPSCPU),
VMSTATE_INT32(env.CP0_Config7, MIPSCPU),
VMSTATE_UINT64(env.CP0_LLAddr, MIPSCPU),
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7db7882f52..1988b436cb 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -127,8 +127,9 @@ enum {
POWERPC_EXCP_SDOOR_HV = 100,
/* ISA 3.00 additions */
POWERPC_EXCP_HVIRT = 101,
+ POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception */
/* EOL */
- POWERPC_EXCP_NB = 102,
+ POWERPC_EXCP_NB = 103,
/* QEMU exceptions: used internally during code translation */
POWERPC_EXCP_STOP = 0x200, /* stop translation */
POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */
@@ -475,9 +476,31 @@ typedef struct ppc_v3_pate_t {
#define SRR1_PROTFAULT DSISR_PROTFAULT
#define SRR1_IAMR DSISR_AMR
+/* SRR1[42:45] wakeup fields for System Reset Interrupt */
+
+#define SRR1_WAKEMASK 0x003c0000 /* reason for wakeup */
+
+#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */
+#define SRR1_WAKEHVI 0x00240000 /* Hypervisor Virt. Interrupt (P9) */
+#define SRR1_WAKEEE 0x00200000 /* External interrupt */
+#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */
+#define SRR1_WAKEDBELL 0x00140000 /* Privileged doorbell */
+#define SRR1_WAKERESET 0x00100000 /* System reset */
+#define SRR1_WAKEHDBELL 0x000c0000 /* Hypervisor doorbell */
+#define SRR1_WAKESCOM 0x00080000 /* SCOM not in power-saving mode */
+
+/* SRR1[46:47] power-saving exit mode */
+
+#define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask */
+
+#define SRR1_WS_HVLOSS 0x00030000 /* HV resources not maintained */
+#define SRR1_WS_GPRLOSS 0x00020000 /* GPRs not maintained */
+#define SRR1_WS_NOLOSS 0x00010000 /* All resources maintained */
+
/* Facility Status and Control (FSCR) bits */
#define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */
#define FSCR_TAR (63 - 55) /* Target Address Register */
+#define FSCR_SCV (63 - 51) /* System call vectored */
/* Interrupt cause mask and position in FSCR. HFSCR has the same format */
#define FSCR_IC_MASK (0xFFULL)
#define FSCR_IC_POS (63 - 7)
@@ -487,6 +510,7 @@ typedef struct ppc_v3_pate_t {
#define FSCR_IC_TM 5
#define FSCR_IC_EBB 7
#define FSCR_IC_TAR 8
+#define FSCR_IC_SCV 12
/* Exception state register bits definition */
#define ESR_PIL PPC_BIT(36) /* Illegal Instruction */
@@ -554,6 +578,8 @@ enum {
POWERPC_FLAG_VSX = 0x00080000,
/* Has Transaction Memory (ISA 2.07) */
POWERPC_FLAG_TM = 0x00100000,
+ /* Has SCV (ISA 3.00) */
+ POWERPC_FLAG_SCV = 0x00200000,
};
/*****************************************************************************/
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f052979664..a988ba15f4 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -67,19 +67,31 @@ static inline void dump_syscall(CPUPPCState *env)
ppc_dump_gpr(env, 8), env->nip);
}
+static inline void dump_syscall_vectored(CPUPPCState *env)
+{
+ qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
+ " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
+ " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
+ " nip=" TARGET_FMT_lx "\n",
+ ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
+ ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
+ ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
+ ppc_dump_gpr(env, 8), env->nip);
+}
+
static inline void dump_hcall(CPUPPCState *env)
{
qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
- " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
- " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
- " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
+ " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
+ " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
+ " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
" nip=" TARGET_FMT_lx "\n",
ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
- ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
- ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
- ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
- ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
- env->nip);
+ ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
+ ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
+ ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
+ ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
+ env->nip);
}
static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
@@ -89,7 +101,7 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
env->resume_as_sreset = false;
/* Pretend to be returning from doze always as we don't lose state */
- *msr |= (0x1ull << (63 - 47));
+ *msr |= SRR1_WS_NOLOSS;
/* Machine checks are sent normally */
if (excp == POWERPC_EXCP_MCHECK) {
@@ -97,25 +109,25 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
}
switch (excp) {
case POWERPC_EXCP_RESET:
- *msr |= 0x4ull << (63 - 45);
+ *msr |= SRR1_WAKERESET;
break;
case POWERPC_EXCP_EXTERNAL:
- *msr |= 0x8ull << (63 - 45);
+ *msr |= SRR1_WAKEEE;
break;
case POWERPC_EXCP_DECR:
- *msr |= 0x6ull << (63 - 45);
+ *msr |= SRR1_WAKEDEC;
break;
case POWERPC_EXCP_SDOOR:
- *msr |= 0x5ull << (63 - 45);
+ *msr |= SRR1_WAKEDBELL;
break;
case POWERPC_EXCP_SDOOR_HV:
- *msr |= 0x3ull << (63 - 45);
+ *msr |= SRR1_WAKEHDBELL;
break;
case POWERPC_EXCP_HV_MAINT:
- *msr |= 0xaull << (63 - 45);
+ *msr |= SRR1_WAKEHMI;
break;
case POWERPC_EXCP_HVIRT:
- *msr |= 0x9ull << (63 - 45);
+ *msr |= SRR1_WAKEHVI;
break;
default:
cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
@@ -185,7 +197,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
- int srr0, srr1, asrr0, asrr1, lev, ail;
+ int srr0, srr1, asrr0, asrr1, lev = -1, ail;
bool lpes0;
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
@@ -421,6 +433,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
new_msr |= (target_ulong)MSR_HVB;
}
break;
+ case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */
+ lev = env->error_code;
+ dump_syscall_vectored(env);
+ env->nip += 4;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
case POWERPC_EXCP_DECR: /* Decrementer exception */
@@ -724,12 +743,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
break;
}
- /* Save PC */
- env->spr[srr0] = env->nip;
-
- /* Save MSR */
- env->spr[srr1] = msr;
-
/* Sanity check */
if (!(env->msr_mask & MSR_HVB)) {
if (new_msr & MSR_HVB) {
@@ -742,14 +755,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
}
- /* If any alternate SRR register are defined, duplicate saved values */
- if (asrr0 != -1) {
- env->spr[asrr0] = env->spr[srr0];
- }
- if (asrr1 != -1) {
- env->spr[asrr1] = env->spr[srr1];
- }
-
/*
* Sort out endianness of interrupt, this differs depending on the
* CPU, the HV mode, etc...
@@ -784,14 +789,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
#endif
- /* Jump to handler */
- vector = env->excp_vectors[excp];
- if (vector == (target_ulong)-1ULL) {
- cpu_abort(cs, "Raised an exception without defined vector %d\n",
- excp);
- }
- vector |= env->excp_prefix;
-
/*
* AIL only works if there is no HV transition and we are running
* with translations enabled
@@ -800,10 +797,21 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
ail = 0;
}
- /* Handle AIL */
- if (ail) {
- new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
- vector |= ppc_excp_vector_offset(cs, ail);
+
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(cs, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+
+ vector |= env->excp_prefix;
+
+ /* If any alternate SRR register are defined, duplicate saved values */
+ if (asrr0 != -1) {
+ env->spr[asrr0] = env->nip;
+ }
+ if (asrr1 != -1) {
+ env->spr[asrr1] = msr;
}
#if defined(TARGET_PPC64)
@@ -823,6 +831,37 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
#endif
+ if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
+ /* Save PC */
+ env->spr[srr0] = env->nip;
+
+ /* Save MSR */
+ env->spr[srr1] = msr;
+
+ /* Handle AIL */
+ if (ail) {
+ new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
+ vector |= ppc_excp_vector_offset(cs, ail);
+ }
+
+#if defined(TARGET_PPC64)
+ } else {
+ /* scv AIL is a little different */
+ if (ail) {
+ new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
+ }
+ if (ail == AIL_C000_0000_0000_4000) {
+ vector |= 0xc000000000003000ull;
+ } else {
+ vector |= 0x0000000000017000ull;
+ }
+ vector += lev * 0x20;
+
+ env->lr = env->nip;
+ env->ctr = msr;
+#endif
+ }
+
powerpc_set_excp_state(cpu, vector, new_msr);
}
@@ -1160,6 +1199,11 @@ void helper_rfid(CPUPPCState *env)
do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
}
+void helper_rfscv(CPUPPCState *env)
+{
+ do_rfi(env, env->lr, env->ctr);
+}
+
void helper_hrfid(CPUPPCState *env)
{
do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index a95c010391..90166cbabd 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -15,6 +15,7 @@ DEF_HELPER_1(rfmci, void, env)
#if defined(TARGET_PPC64)
DEF_HELPER_2(pminsn, void, env, i32)
DEF_HELPER_1(rfid, void, env)
+DEF_HELPER_1(rfscv, void, env)
DEF_HELPER_1(hrfid, void, env)
DEF_HELPER_2(store_lpcr, void, env, tl)
DEF_HELPER_2(store_pcr, void, env, tl)
@@ -213,10 +214,6 @@ DEF_HELPER_3(vsubuqm, void, avr, avr, avr)
DEF_HELPER_4(vsubecuq, void, avr, avr, avr, avr)
DEF_HELPER_4(vsubeuqm, void, avr, avr, avr, avr)
DEF_HELPER_3(vsubcuq, void, avr, avr, avr)
-DEF_HELPER_3(vrlb, void, avr, avr, avr)
-DEF_HELPER_3(vrlh, void, avr, avr, avr)
-DEF_HELPER_3(vrlw, void, avr, avr, avr)
-DEF_HELPER_3(vrld, void, avr, avr, avr)
DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32)
DEF_HELPER_3(vextractub, void, avr, avr, i32)
DEF_HELPER_3(vextractuh, void, avr, avr, i32)
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index be53cd6f68..d8bd3c234a 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -1348,23 +1348,6 @@ VRFI(p, float_round_up)
VRFI(z, float_round_to_zero)
#undef VRFI
-#define VROTATE(suffix, element, mask) \
- void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int shift = b->element[i] & mask; \
- r->element[i] = (a->element[i] << shift) | \
- (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
- } \
- }
-VROTATE(b, u8, 0x7)
-VROTATE(h, u16, 0xF)
-VROTATE(w, u32, 0x1F)
-VROTATE(d, u64, 0x3F)
-#undef VROTATE
-
void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 1404e53dec..c60bf31357 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -28,7 +28,8 @@
#include "mmu-radix64.h"
#include "mmu-book3s-v3.h"
-static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr,
+static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
+ vaddr eaddr,
uint64_t *lpid, uint64_t *pid)
{
if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */
@@ -49,6 +50,8 @@ static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr,
*lpid = 0;
*pid = 0;
break;
+ default:
+ g_assert_not_reached();
}
} else { /* !MSR[HV] -> Guest */
switch (eaddr & R_EADDR_QUADRANT) {
@@ -63,6 +66,8 @@ static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr,
*lpid = env->spr[SPR_LPIDR];
*pid = 0; /* pid set to 0 -> addresses guest operating system */
break;
+ default:
+ g_assert_not_reached();
}
}
@@ -269,7 +274,7 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
ppc_v3_pate_t pate,
hwaddr *h_raddr, int *h_prot,
int *h_page_size, bool pde_addr,
- bool cause_excp)
+ bool guest_visible)
{
int fault_cause = 0;
hwaddr pte_addr;
@@ -281,16 +286,18 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
&pte, &fault_cause, &pte_addr) ||
ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) {
- if (pde_addr) /* address being translated was that of a guest pde */
+ if (pde_addr) { /* address being translated was that of a guest pde */
fault_cause |= DSISR_PRTABLE_FAULT;
- if (cause_excp) {
+ }
+ if (guest_visible) {
ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause);
}
return 1;
}
- /* Update Reference and Change Bits */
- ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
+ if (guest_visible) {
+ ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
+ }
return 0;
}
@@ -299,7 +306,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
vaddr eaddr, uint64_t pid,
ppc_v3_pate_t pate, hwaddr *g_raddr,
int *g_prot, int *g_page_size,
- bool cause_excp)
+ bool guest_visible)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
@@ -313,7 +320,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
if (offset >= size) {
/* offset exceeds size of the process table */
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
}
return 1;
@@ -333,7 +340,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
*/
ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
pate, &h_raddr, &h_prot,
- &h_page_size, 1, 1);
+ &h_page_size, true,
+ guest_visible);
if (ret) {
return ret;
}
@@ -353,7 +361,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
&fault_cause, &pte_addr);
if (ret) {
/* No valid PTE */
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
}
return ret;
@@ -372,7 +380,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
do {
ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
pate, &h_raddr, &h_prot,
- &h_page_size, 1, 1);
+ &h_page_size, true,
+ guest_visible);
if (ret) {
return ret;
}
@@ -381,7 +390,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
&nls, g_page_size, &pte, &fault_cause);
if (ret) {
/* No valid pte */
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
}
return ret;
@@ -398,13 +407,15 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
/* Access denied due to protection */
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
}
return 1;
}
- ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
+ if (guest_visible) {
+ ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
+ }
return 0;
}
@@ -429,17 +440,17 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
bool relocation,
hwaddr *raddr, int *psizep, int *protp,
- bool cause_excp)
+ bool guest_visible)
{
CPUPPCState *env = &cpu->env;
- uint64_t lpid = 0, pid = 0;
+ uint64_t lpid, pid;
ppc_v3_pate_t pate;
int psize, prot;
hwaddr g_raddr;
/* Virtual Mode Access - get the fully qualified address */
if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_segi(cpu, rwx, eaddr);
}
return 1;
@@ -452,13 +463,13 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
vhc->get_pate(cpu->vhyp, &pate);
} else {
if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
}
return 1;
}
if (!validate_pate(cpu, lpid, &pate)) {
- if (cause_excp) {
+ if (guest_visible) {
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
}
return 1;
@@ -479,7 +490,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
if (relocation) {
int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
pate, &g_raddr, &prot,
- &psize, cause_excp);
+ &psize, guest_visible);
if (ret) {
return ret;
}
@@ -502,7 +513,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
pate, raddr, &prot, &psize,
- 0, cause_excp);
+ false, guest_visible);
if (ret) {
return ret;
}
diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h
index 96228546aa..f28c5794d0 100644
--- a/target/ppc/mmu-radix64.h
+++ b/target/ppc/mmu-radix64.h
@@ -55,9 +55,9 @@ static inline int ppc_radix64_get_prot_eaa(uint64_t pte)
(pte & R_PTE_EAA_X ? PAGE_EXEC : 0);
}
-static inline int ppc_radix64_get_prot_amr(PowerPCCPU *cpu)
+static inline int ppc_radix64_get_prot_amr(const PowerPCCPU *cpu)
{
- CPUPPCState *env = &cpu->env;
+ const CPUPPCState *env = &cpu->env;
int amr = env->spr[SPR_AMR] >> 62; /* We only care about key0 AMR63:62 */
int iamr = env->spr[SPR_IAMR] >> 62; /* We only care about key0 IAMR63:62 */
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 338529879f..4ce3d664b5 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -173,6 +173,7 @@ struct DisasContext {
bool vsx_enabled;
bool spe_enabled;
bool tm_enabled;
+ bool scv_enabled;
bool gtse;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
@@ -4030,6 +4031,24 @@ static void gen_rfid(DisasContext *ctx)
#endif
}
+#if !defined(CONFIG_USER_ONLY)
+static void gen_rfscv(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ /* Restore CPU state */
+ CHK_SV;
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_update_cfar(ctx, ctx->base.pc_next - 4);
+ gen_helper_rfscv(cpu_env);
+ gen_sync_exception(ctx);
+#endif
+}
+#endif
+
static void gen_hrfid(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
@@ -4048,6 +4067,7 @@ static void gen_hrfid(DisasContext *ctx)
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
#else
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
+#define POWERPC_SYSCALL_VECTORED POWERPC_EXCP_SYSCALL_VECTORED
#endif
static void gen_sc(DisasContext *ctx)
{
@@ -4057,6 +4077,23 @@ static void gen_sc(DisasContext *ctx)
gen_exception_err(ctx, POWERPC_SYSCALL, lev);
}
+#if defined(TARGET_PPC64)
+#if !defined(CONFIG_USER_ONLY)
+static void gen_scv(DisasContext *ctx)
+{
+ uint32_t lev;
+
+ if (unlikely(!ctx->scv_enabled)) {
+ gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_SCV);
+ return;
+ }
+
+ lev = (ctx->opcode >> 5) & 0x7F;
+ gen_exception_err(ctx, POWERPC_SYSCALL_VECTORED, lev);
+}
+#endif
+#endif
+
/*** Trap ***/
/* Check for unconditional traps (always or never) */
@@ -7049,6 +7086,12 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER),
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
#if defined(TARGET_PPC64)
GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B),
+#if !defined(CONFIG_USER_ONLY)
+/* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */
+GEN_HANDLER_E(scv, 0x11, 0x10, 0xFF, 0x03FFF01E, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(scv, 0x11, 0x00, 0xFF, 0x03FFF01E, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(rfscv, 0x13, 0x12, 0x02, 0x03FF8001, PPC_NONE, PPC2_ISA300),
+#endif
GEN_HANDLER_E(stop, 0x13, 0x12, 0x0b, 0x03FFF801, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E(doze, 0x13, 0x12, 0x0c, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER_E(nap, 0x13, 0x12, 0x0d, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
@@ -7056,7 +7099,9 @@ GEN_HANDLER_E(sleep, 0x13, 0x12, 0x0e, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER_E(rvwinkle, 0x13, 0x12, 0x0f, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H),
#endif
-GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW),
+/* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */
+GEN_HANDLER(sc, 0x11, 0x11, 0xFF, 0x03FFF01D, PPC_FLOW),
+GEN_HANDLER(sc, 0x11, 0x01, 0xFF, 0x03FFF01D, PPC_FLOW),
GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW),
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
#if defined(TARGET_PPC64)
@@ -7835,6 +7880,12 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
} else {
ctx->vsx_enabled = false;
}
+ if ((env->flags & POWERPC_FLAG_SCV)
+ && (env->spr[SPR_FSCR] & (1ull << FSCR_SCV))) {
+ ctx->scv_enabled = true;
+ } else {
+ ctx->scv_enabled = false;
+ }
#if defined(TARGET_PPC64)
if ((env->flags & POWERPC_FLAG_TM) && msr_tm) {
ctx->tm_enabled = !!msr_tm;
diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c
index 403ed3a01c..de2fd136ff 100644
--- a/target/ppc/translate/vmx-impl.inc.c
+++ b/target/ppc/translate/vmx-impl.inc.c
@@ -900,13 +900,13 @@ GEN_VXFORM3(vsubeuqm, 31, 0);
GEN_VXFORM3(vsubecuq, 31, 0);
GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
vsubecuq, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM(vrlb, 2, 0);
-GEN_VXFORM(vrlh, 2, 1);
-GEN_VXFORM(vrlw, 2, 2);
+GEN_VXFORM_V(vrlb, MO_8, tcg_gen_gvec_rotlv, 2, 0);
+GEN_VXFORM_V(vrlh, MO_16, tcg_gen_gvec_rotlv, 2, 1);
+GEN_VXFORM_V(vrlw, MO_32, tcg_gen_gvec_rotlv, 2, 2);
GEN_VXFORM(vrlwmi, 2, 2);
GEN_VXFORM_DUAL(vrlw, PPC_ALTIVEC, PPC_NONE, \
vrlwmi, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM(vrld, 2, 3);
+GEN_VXFORM_V(vrld, MO_64, tcg_gen_gvec_rotlv, 2, 3);
GEN_VXFORM(vrldmi, 2, 3);
GEN_VXFORM_DUAL(vrld, PPC_NONE, PPC2_ALTIVEC_207, \
vrldmi, PPC_NONE, PPC2_ISA300)
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index d8adc1bd49..38cb773ab4 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -3382,6 +3382,7 @@ static void init_excp_POWER9(CPUPPCState *env)
#if !defined(CONFIG_USER_ONLY)
env->excp_vectors[POWERPC_EXCP_HVIRT] = 0x00000EA0;
+ env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00000000;
#endif
}
@@ -9030,7 +9031,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |
- POWERPC_FLAG_VSX | POWERPC_FLAG_TM;
+ POWERPC_FLAG_VSX | POWERPC_FLAG_TM | POWERPC_FLAG_SCV;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 6c78337858..3a6d202d03 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -133,26 +133,24 @@ static void riscv_base32_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, 0);
+ set_resetvec(env, DEFAULT_RSTVEC);
}
-static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
+static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
- set_priv_version(env, PRIV_VERSION_1_09_1);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
- set_feature(env, RISCV_FEATURE_MMU);
- set_feature(env, RISCV_FEATURE_PMP);
}
-static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
+static void rv32imcu_nommu_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
- set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
+ set_misa(env, RV32 | RVI | RVM | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
- set_resetvec(env, DEFAULT_RSTVEC);
- set_feature(env, RISCV_FEATURE_MMU);
- set_feature(env, RISCV_FEATURE_PMP);
+ set_resetvec(env, 0x8090);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
}
static void rv32imacu_nommu_cpu_init(Object *obj)
@@ -161,7 +159,7 @@ static void rv32imacu_nommu_cpu_init(Object *obj)
set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
- set_feature(env, RISCV_FEATURE_PMP);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
}
static void rv32imafcu_nommu_cpu_init(Object *obj)
@@ -170,7 +168,7 @@ static void rv32imafcu_nommu_cpu_init(Object *obj)
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
- set_feature(env, RISCV_FEATURE_PMP);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
}
#elif defined(TARGET_RISCV64)
@@ -180,16 +178,7 @@ static void riscv_base64_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, 0);
-}
-
-static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
-{
- CPURISCVState *env = &RISCV_CPU(obj)->env;
- set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
- set_priv_version(env, PRIV_VERSION_1_09_1);
set_resetvec(env, DEFAULT_RSTVEC);
- set_feature(env, RISCV_FEATURE_MMU);
- set_feature(env, RISCV_FEATURE_PMP);
}
static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
@@ -198,8 +187,6 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
- set_feature(env, RISCV_FEATURE_MMU);
- set_feature(env, RISCV_FEATURE_PMP);
}
static void rv64imacu_nommu_cpu_init(Object *obj)
@@ -208,7 +195,7 @@ static void rv64imacu_nommu_cpu_init(Object *obj)
set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
- set_feature(env, RISCV_FEATURE_PMP);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
}
#endif
@@ -388,8 +375,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
priv_version = PRIV_VERSION_1_11_0;
} else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) {
priv_version = PRIV_VERSION_1_10_0;
- } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.9.1")) {
- priv_version = PRIV_VERSION_1_09_1;
} else {
error_setg(errp,
"Unsupported privilege spec version '%s'",
@@ -399,7 +384,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
set_priv_version(env, priv_version);
- set_resetvec(env, DEFAULT_RSTVEC);
if (cpu->cfg.mmu) {
set_feature(env, RISCV_FEATURE_MMU);
@@ -620,21 +604,14 @@ static const TypeInfo riscv_cpu_type_infos[] = {
DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init),
#if defined(TARGET_RISCV32)
DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32imcu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init),
- /* Depreacted */
- DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init)
#elif defined(TARGET_RISCV64)
DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init),
- /* Deprecated */
- DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init)
#endif
};
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index d0e7f5b9c5..80569f0d44 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -35,18 +35,12 @@
#define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any")
#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32")
#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64")
+#define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex")
#define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31")
#define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34")
#define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51")
#define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34")
#define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54")
-/* Deprecated */
-#define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu")
-#define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1")
-#define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0")
-#define TYPE_RISCV_CPU_RV64IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv64imacu-nommu")
-#define TYPE_RISCV_CPU_RV64GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.9.1")
-#define TYPE_RISCV_CPU_RV64GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.10.0")
#define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2))
#define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2))
@@ -80,7 +74,6 @@ enum {
RISCV_FEATURE_MISA
};
-#define PRIV_VERSION_1_09_1 0x00010901
#define PRIV_VERSION_1_10_0 0x00011000
#define PRIV_VERSION_1_11_0 0x00011100
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index bc80aa87cf..62fe1ecc8f 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -364,57 +364,36 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
mxr = get_field(env->vsstatus, MSTATUS_MXR);
}
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- if (first_stage == true) {
- if (use_background) {
- base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT;
- vm = get_field(env->vsatp, SATP_MODE);
- } else {
- base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
- vm = get_field(env->satp, SATP_MODE);
- }
- widened = 0;
+ if (first_stage == true) {
+ if (use_background) {
+ base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT;
+ vm = get_field(env->vsatp, SATP_MODE);
} else {
- base = (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT;
- vm = get_field(env->hgatp, HGATP_MODE);
- widened = 2;
- }
- sum = get_field(env->mstatus, MSTATUS_SUM);
- switch (vm) {
- case VM_1_10_SV32:
- levels = 2; ptidxbits = 10; ptesize = 4; break;
- case VM_1_10_SV39:
- levels = 3; ptidxbits = 9; ptesize = 8; break;
- case VM_1_10_SV48:
- levels = 4; ptidxbits = 9; ptesize = 8; break;
- case VM_1_10_SV57:
- levels = 5; ptidxbits = 9; ptesize = 8; break;
- case VM_1_10_MBARE:
- *physical = addr;
- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return TRANSLATE_SUCCESS;
- default:
- g_assert_not_reached();
+ base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP_MODE);
}
- } else {
widened = 0;
- base = (hwaddr)(env->sptbr) << PGSHIFT;
- sum = !get_field(env->mstatus, MSTATUS_PUM);
- vm = get_field(env->mstatus, MSTATUS_VM);
- switch (vm) {
- case VM_1_09_SV32:
- levels = 2; ptidxbits = 10; ptesize = 4; break;
- case VM_1_09_SV39:
- levels = 3; ptidxbits = 9; ptesize = 8; break;
- case VM_1_09_SV48:
- levels = 4; ptidxbits = 9; ptesize = 8; break;
- case VM_1_09_MBARE:
- *physical = addr;
- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return TRANSLATE_SUCCESS;
- default:
- g_assert_not_reached();
- }
+ } else {
+ base = (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT;
+ vm = get_field(env->hgatp, HGATP_MODE);
+ widened = 2;
+ }
+ sum = get_field(env->mstatus, MSTATUS_SUM);
+ switch (vm) {
+ case VM_1_10_SV32:
+ levels = 2; ptidxbits = 10; ptesize = 4; break;
+ case VM_1_10_SV39:
+ levels = 3; ptidxbits = 9; ptesize = 8; break;
+ case VM_1_10_SV48:
+ levels = 4; ptidxbits = 9; ptesize = 8; break;
+ case VM_1_10_SV57:
+ levels = 5; ptidxbits = 9; ptesize = 8; break;
+ case VM_1_10_MBARE:
+ *physical = addr;
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TRANSLATE_SUCCESS;
+ default:
+ g_assert_not_reached();
}
CPUState *cs = env_cpu(env);
@@ -588,7 +567,6 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
int page_fault_exceptions;
if (first_stage) {
page_fault_exceptions =
- (env->priv_ver >= PRIV_VERSION_1_10_0) &&
get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
!pmp_violation;
} else {
@@ -941,8 +919,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
}
s = env->mstatus;
- s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
- get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
+ s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
s = set_field(s, MSTATUS_SPP, env->priv);
s = set_field(s, MSTATUS_SIE, 0);
env->mstatus = s;
@@ -979,8 +956,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
}
s = env->mstatus;
- s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
- get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
+ s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
s = set_field(s, MSTATUS_MPP, env->priv);
s = set_field(s, MSTATUS_MIE, 0);
env->mstatus = s;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 11d184cd16..383be0a955 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -58,31 +58,11 @@ static int ctr(CPURISCVState *env, int csrno)
#if !defined(CONFIG_USER_ONLY)
CPUState *cs = env_cpu(env);
RISCVCPU *cpu = RISCV_CPU(cs);
- uint32_t ctr_en = ~0u;
if (!cpu->cfg.ext_counters) {
/* The Counters extensions is not enabled */
return -1;
}
-
- /*
- * The counters are always enabled at run time on newer priv specs, as the
- * CSR has changed from controlling that the counters can be read to
- * controlling that the counters increment.
- */
- if (env->priv_ver > PRIV_VERSION_1_09_1) {
- return 0;
- }
-
- if (env->priv < PRV_M) {
- ctr_en &= env->mcounteren;
- }
- if (env->priv < PRV_S) {
- ctr_en &= env->scounteren;
- }
- if (!(ctr_en & (1u << (csrno & 31)))) {
- return -1;
- }
#endif
return 0;
}
@@ -293,9 +273,6 @@ static const target_ulong delegable_excps =
(1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) |
(1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) |
(1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT));
-static const target_ulong sstatus_v1_9_mask = SSTATUS_SIE | SSTATUS_SPIE |
- SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
- SSTATUS_SUM | SSTATUS_SD;
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
@@ -304,20 +281,11 @@ static const target_ulong hip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
static const target_ulong vsip_writable_mask = MIP_VSSIP;
#if defined(TARGET_RISCV32)
-static const char valid_vm_1_09[16] = {
- [VM_1_09_MBARE] = 1,
- [VM_1_09_SV32] = 1,
-};
static const char valid_vm_1_10[16] = {
[VM_1_10_MBARE] = 1,
[VM_1_10_SV32] = 1
};
#elif defined(TARGET_RISCV64)
-static const char valid_vm_1_09[16] = {
- [VM_1_09_MBARE] = 1,
- [VM_1_09_SV39] = 1,
- [VM_1_09_SV48] = 1,
-};
static const char valid_vm_1_10[16] = {
[VM_1_10_MBARE] = 1,
[VM_1_10_SV39] = 1,
@@ -347,8 +315,7 @@ static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val)
static int validate_vm(CPURISCVState *env, target_ulong vm)
{
- return (env->priv_ver >= PRIV_VERSION_1_10_0) ?
- valid_vm_1_10[vm & 0xf] : valid_vm_1_09[vm & 0xf];
+ return valid_vm_1_10[vm & 0xf];
}
static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
@@ -358,34 +325,21 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
int dirty;
/* flush tlb on mstatus fields that affect VM */
- if (env->priv_ver <= PRIV_VERSION_1_09_1) {
- if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP |
- MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_VM)) {
- tlb_flush(env_cpu(env));
- }
- mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
- MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
- MSTATUS_MPP | MSTATUS_MXR |
- (validate_vm(env, get_field(val, MSTATUS_VM)) ?
- MSTATUS_VM : 0);
+ if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV |
+ MSTATUS_MPRV | MSTATUS_SUM)) {
+ tlb_flush(env_cpu(env));
}
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV |
- MSTATUS_MPRV | MSTATUS_SUM)) {
- tlb_flush(env_cpu(env));
- }
- mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
- MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
- MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR |
- MSTATUS_TW;
+ mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
+ MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
+ MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR |
+ MSTATUS_TW;
#if defined(TARGET_RISCV64)
- /*
- * RV32: MPV and MTL are not in mstatus. The current plan is to
- * add them to mstatush. For now, we just don't support it.
- */
- mask |= MSTATUS_MTL | MSTATUS_MPV;
+ /*
+ * RV32: MPV and MTL are not in mstatus. The current plan is to
+ * add them to mstatush. For now, we just don't support it.
+ */
+ mask |= MSTATUS_MTL | MSTATUS_MPV;
#endif
- }
mstatus = (mstatus & ~mask) | (val & mask);
@@ -534,18 +488,12 @@ static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val)
static int read_mcounteren(CPURISCVState *env, int csrno, target_ulong *val)
{
- if (env->priv_ver < PRIV_VERSION_1_10_0) {
- return -1;
- }
*val = env->mcounteren;
return 0;
}
static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val)
{
- if (env->priv_ver < PRIV_VERSION_1_10_0) {
- return -1;
- }
env->mcounteren = val;
return 0;
}
@@ -553,8 +501,7 @@ static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val)
/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */
static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val)
{
- if (env->priv_ver > PRIV_VERSION_1_09_1
- && env->priv_ver < PRIV_VERSION_1_11_0) {
+ if (env->priv_ver < PRIV_VERSION_1_11_0) {
return -1;
}
*val = env->mcounteren;
@@ -564,32 +511,13 @@ static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val)
/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */
static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val)
{
- if (env->priv_ver > PRIV_VERSION_1_09_1
- && env->priv_ver < PRIV_VERSION_1_11_0) {
+ if (env->priv_ver < PRIV_VERSION_1_11_0) {
return -1;
}
env->mcounteren = val;
return 0;
}
-static int read_mucounteren(CPURISCVState *env, int csrno, target_ulong *val)
-{
- if (env->priv_ver > PRIV_VERSION_1_09_1) {
- return -1;
- }
- *val = env->scounteren;
- return 0;
-}
-
-static int write_mucounteren(CPURISCVState *env, int csrno, target_ulong val)
-{
- if (env->priv_ver > PRIV_VERSION_1_09_1) {
- return -1;
- }
- env->scounteren = val;
- return 0;
-}
-
/* Machine Trap Handling */
static int read_mscratch(CPURISCVState *env, int csrno, target_ulong *val)
{
@@ -663,16 +591,14 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
/* Supervisor Trap Setup */
static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
{
- target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
- sstatus_v1_10_mask : sstatus_v1_9_mask);
+ target_ulong mask = (sstatus_v1_10_mask);
*val = env->mstatus & mask;
return 0;
}
static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
{
- target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
- sstatus_v1_10_mask : sstatus_v1_9_mask);
+ target_ulong mask = (sstatus_v1_10_mask);
target_ulong newval = (env->mstatus & ~mask) | (val & mask);
return write_mstatus(env, CSR_MSTATUS, newval);
}
@@ -722,18 +648,12 @@ static int write_stvec(CPURISCVState *env, int csrno, target_ulong val)
static int read_scounteren(CPURISCVState *env, int csrno, target_ulong *val)
{
- if (env->priv_ver < PRIV_VERSION_1_10_0) {
- return -1;
- }
*val = env->scounteren;
return 0;
}
static int write_scounteren(CPURISCVState *env, int csrno, target_ulong val)
{
- if (env->priv_ver < PRIV_VERSION_1_10_0) {
- return -1;
- }
env->scounteren = val;
return 0;
}
@@ -812,15 +732,15 @@ static int read_satp(CPURISCVState *env, int csrno, target_ulong *val)
{
if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
*val = 0;
- } else if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
- return -1;
- } else {
- *val = env->satp;
- }
+ return 0;
+ }
+
+ if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
+ return -1;
} else {
- *val = env->sptbr;
+ *val = env->satp;
}
+
return 0;
}
@@ -829,13 +749,7 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
return 0;
}
- if (env->priv_ver <= PRIV_VERSION_1_09_1 && (val ^ env->sptbr)) {
- tlb_flush(env_cpu(env));
- env->sptbr = val & (((target_ulong)
- 1 << (TARGET_PHYS_ADDR_SPACE_BITS - PGSHIFT)) - 1);
- }
- if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
- validate_vm(env, get_field(val, SATP_MODE)) &&
+ if (validate_vm(env, get_field(val, SATP_MODE)) &&
((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
{
if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
@@ -1313,8 +1227,6 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MSTATUSH] = { any, read_mstatush, write_mstatush },
#endif
- /* Legacy Counter Setup (priv v1.9.1) */
- [CSR_MUCOUNTEREN] = { any, read_mucounteren, write_mucounteren },
[CSR_MSCOUNTEREN] = { any, read_mscounteren, write_mscounteren },
/* Machine Trap Handling */
diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c
index 76c2fad71c..5f26e0f5ea 100644
--- a/target/riscv/insn_trans/trans_privileged.inc.c
+++ b/target/riscv/insn_trans/trans_privileged.inc.c
@@ -85,30 +85,21 @@ static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
{
#ifndef CONFIG_USER_ONLY
- if (ctx->priv_ver >= PRIV_VERSION_1_10_0) {
- gen_helper_tlb_flush(cpu_env);
- return true;
- }
+ gen_helper_tlb_flush(cpu_env);
+ return true;
#endif
return false;
}
static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
{
-#ifndef CONFIG_USER_ONLY
- if (ctx->priv_ver <= PRIV_VERSION_1_09_1) {
- gen_helper_tlb_flush(cpu_env);
- return true;
- }
-#endif
return false;
}
static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
{
#ifndef CONFIG_USER_ONLY
- if (ctx->priv_ver >= PRIV_VERSION_1_10_0 &&
- has_ext(ctx, RVH)) {
+ if (has_ext(ctx, RVH)) {
/* Hpervisor extensions exist */
/*
* if (env->priv == PRV_M ||
@@ -127,8 +118,7 @@ static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
static bool trans_hfence_bvma(DisasContext *ctx, arg_sfence_vma *a)
{
#ifndef CONFIG_USER_ONLY
- if (ctx->priv_ver >= PRIV_VERSION_1_10_0 &&
- has_ext(ctx, RVH)) {
+ if (has_ext(ctx, RVH)) {
/* Hpervisor extensions exist */
/*
* if (env->priv == PRV_M ||
diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c
index d725a7a36e..b569f08387 100644
--- a/target/riscv/monitor.c
+++ b/target/riscv/monitor.c
@@ -215,11 +215,6 @@ void hmp_info_mem(Monitor *mon, const QDict *qdict)
return;
}
- if (env->priv_ver < PRIV_VERSION_1_10_0) {
- monitor_printf(mon, "Privileged mode < 1.10 unsupported\n");
- return;
- }
-
if (!(env->satp & SATP_MODE)) {
monitor_printf(mon, "No translation or protection\n");
return;
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index c6412f680c..b0c49efc4a 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -84,8 +84,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
}
- if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
- get_field(env->mstatus, MSTATUS_TSR) && !(env->priv >= PRV_M)) {
+ if (get_field(env->mstatus, MSTATUS_TSR) && !(env->priv >= PRV_M)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
@@ -119,10 +118,8 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
} else {
prev_priv = get_field(mstatus, MSTATUS_SPP);
- mstatus = set_field(mstatus,
- env->priv_ver >= PRIV_VERSION_1_10_0 ?
- MSTATUS_SIE : MSTATUS_UIE << prev_priv,
- get_field(mstatus, MSTATUS_SPIE));
+ mstatus = set_field(mstatus, MSTATUS_SIE,
+ get_field(mstatus, MSTATUS_SPIE));
mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
env->mstatus = mstatus;
@@ -147,10 +144,8 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
target_ulong mstatus = env->mstatus;
target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
target_ulong prev_virt = MSTATUS_MPV_ISSET(env);
- mstatus = set_field(mstatus,
- env->priv_ver >= PRIV_VERSION_1_10_0 ?
- MSTATUS_MIE : MSTATUS_UIE << prev_priv,
- get_field(mstatus, MSTATUS_MPIE));
+ mstatus = set_field(mstatus, MSTATUS_MIE,
+ get_field(mstatus, MSTATUS_MPIE));
mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
#ifdef TARGET_RISCV32
@@ -177,7 +172,6 @@ void helper_wfi(CPURISCVState *env)
CPUState *cs = env_cpu(env);
if ((env->priv == PRV_S &&
- env->priv_ver >= PRIV_VERSION_1_10_0 &&
get_field(env->mstatus, MSTATUS_TW)) ||
riscv_cpu_virt_enabled(env)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
@@ -193,7 +187,6 @@ void helper_tlb_flush(CPURISCVState *env)
CPUState *cs = env_cpu(env);
if (!(env->priv >= PRV_S) ||
(env->priv == PRV_S &&
- env->priv_ver >= PRIV_VERSION_1_10_0 &&
get_field(env->mstatus, MSTATUS_TVM))) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
} else {
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 8efe6ed514..2fa609bffe 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -524,7 +524,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
}
}
if (!err) {
- visit_check_struct(visitor, errp);
+ visit_check_struct(visitor, &err);
}
visit_end_struct(visitor, NULL);
visit_free(visitor);
diff --git a/target/s390x/helper.c b/target/s390x/helper.c
index 09f60406aa..9257d388ba 100644
--- a/target/s390x/helper.c
+++ b/target/s390x/helper.c
@@ -42,9 +42,6 @@ void s390x_cpu_timer(void *opaque)
{
cpu_inject_cpu_timer((S390CPU *) opaque);
}
-#endif
-
-#ifndef CONFIG_USER_ONLY
hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
{
@@ -98,14 +95,12 @@ void s390_handle_wait(S390CPU *cpu)
CPUState *cs = CPU(cpu);
if (s390_cpu_halt(cpu) == 0) {
-#ifndef CONFIG_USER_ONLY
if (is_special_wait_psw(cpu->env.psw.addr)) {
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
} else {
cpu->env.crash_reason = S390_CRASH_REASON_DISABLED_WAIT;
qemu_system_guest_panicked(cpu_get_crash_info(cs));
}
-#endif
}
}
diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index b5813c2ac2..b7887b552b 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -198,10 +198,6 @@ DEF_HELPER_FLAGS_4(gvec_vmlo16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmlo32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vpopct8, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vpopct16, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
-DEF_HELPER_FLAGS_4(gvec_verllv8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
-DEF_HELPER_FLAGS_4(gvec_verllv16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
-DEF_HELPER_FLAGS_4(gvec_verll8, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32)
-DEF_HELPER_FLAGS_4(gvec_verll16, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32)
DEF_HELPER_FLAGS_4(gvec_verim8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_verim16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vsl, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32)
diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
index 2bc77f0871..91ddaedd84 100644
--- a/target/s390x/insn-data.def
+++ b/target/s390x/insn-data.def
@@ -1147,8 +1147,8 @@
/* VECTOR POPULATION COUNT */
F(0xe750, VPOPCT, VRR_a, V, 0, 0, 0, 0, vpopct, 0, IF_VEC)
/* VECTOR ELEMENT ROTATE LEFT LOGICAL */
- F(0xe773, VERLLV, VRR_c, V, 0, 0, 0, 0, verllv, 0, IF_VEC)
- F(0xe733, VERLL, VRS_a, V, la2, 0, 0, 0, verll, 0, IF_VEC)
+ F(0xe773, VERLLV, VRR_c, V, 0, 0, 0, 0, vesv, 0, IF_VEC)
+ F(0xe733, VERLL, VRS_a, V, la2, 0, 0, 0, ves, 0, IF_VEC)
/* VECTOR ELEMENT ROTATE AND INSERT UNDER MASK */
F(0xe772, VERIM, VRI_d, V, 0, 0, 0, 0, verim, 0, IF_VEC)
/* VECTOR ELEMENT SHIFT LEFT */
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
index 8c95c734db..b1e0ebf67f 100644
--- a/target/s390x/internal.h
+++ b/target/s390x/internal.h
@@ -204,6 +204,8 @@ enum cc_op {
CC_OP_MAX
};
+#ifndef CONFIG_USER_ONLY
+
static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
uint8_t *ar)
{
@@ -225,6 +227,8 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
/* Base/displacement are at the same locations. */
#define decode_basedisp_rs decode_basedisp_s
+#endif /* CONFIG_USER_ONLY */
+
/* arch_dump.c */
int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
@@ -232,9 +236,11 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
/* cc_helper.c */
const char *cc_name(enum cc_op cc_op);
-void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
uint64_t vr);
+#ifndef CONFIG_USER_ONLY
+void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
+#endif /* CONFIG_USER_ONLY */
/* cpu.c */
@@ -299,18 +305,18 @@ void s390_cpu_gdb_init(CPUState *cs);
/* helper.c */
void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
-hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
+void do_restart_interrupt(CPUS390XState *env);
+#ifndef CONFIG_USER_ONLY
uint64_t get_psw_mask(CPUS390XState *env);
void s390_cpu_recompute_watchpoints(CPUState *cs);
void s390x_tod_timer(void *opaque);
void s390x_cpu_timer(void *opaque);
-void do_restart_interrupt(CPUS390XState *env);
void s390_handle_wait(S390CPU *cpu);
+hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
#define S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area)
int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch);
int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len);
-#ifndef CONFIG_USER_ONLY
LowCore *cpu_map_lowcore(CPUS390XState *env);
void cpu_unmap_lowcore(LowCore *lowcore);
#endif /* CONFIG_USER_ONLY */
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 69881a0da0..f2f75d2a57 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -2165,7 +2165,7 @@ int kvm_arch_msi_data_to_gsi(uint32_t data)
static int query_cpu_subfunc(S390FeatBitmap features)
{
- struct kvm_s390_vm_cpu_subfunc prop;
+ struct kvm_s390_vm_cpu_subfunc prop = {};
struct kvm_device_attr attr = {
.group = KVM_S390_VM_CPU_MODEL,
.attr = KVM_S390_VM_CPU_MACHINE_SUBFUNC,
@@ -2292,7 +2292,7 @@ static int kvm_to_feat[][2] = {
static int query_cpu_feat(S390FeatBitmap features)
{
- struct kvm_s390_vm_cpu_feat prop;
+ struct kvm_s390_vm_cpu_feat prop = {};
struct kvm_device_attr attr = {
.group = KVM_S390_VM_CPU_MODEL,
.attr = KVM_S390_VM_CPU_MACHINE_FEAT,
diff --git a/target/s390x/translate_vx.inc.c b/target/s390x/translate_vx.inc.c
index 12347f8a03..eb767f5288 100644
--- a/target/s390x/translate_vx.inc.c
+++ b/target/s390x/translate_vx.inc.c
@@ -1825,63 +1825,6 @@ static DisasJumpType op_vpopct(DisasContext *s, DisasOps *o)
return DISAS_NEXT;
}
-static void gen_rll_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
-{
- TCGv_i32 t0 = tcg_temp_new_i32();
-
- tcg_gen_andi_i32(t0, b, 31);
- tcg_gen_rotl_i32(d, a, t0);
- tcg_temp_free_i32(t0);
-}
-
-static void gen_rll_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
-{
- TCGv_i64 t0 = tcg_temp_new_i64();
-
- tcg_gen_andi_i64(t0, b, 63);
- tcg_gen_rotl_i64(d, a, t0);
- tcg_temp_free_i64(t0);
-}
-
-static DisasJumpType op_verllv(DisasContext *s, DisasOps *o)
-{
- const uint8_t es = get_field(s, m4);
- static const GVecGen3 g[4] = {
- { .fno = gen_helper_gvec_verllv8, },
- { .fno = gen_helper_gvec_verllv16, },
- { .fni4 = gen_rll_i32, },
- { .fni8 = gen_rll_i64, },
- };
-
- if (es > ES_64) {
- gen_program_exception(s, PGM_SPECIFICATION);
- return DISAS_NORETURN;
- }
-
- gen_gvec_3(get_field(s, v1), get_field(s, v2),
- get_field(s, v3), &g[es]);
- return DISAS_NEXT;
-}
-
-static DisasJumpType op_verll(DisasContext *s, DisasOps *o)
-{
- const uint8_t es = get_field(s, m4);
- static const GVecGen2s g[4] = {
- { .fno = gen_helper_gvec_verll8, },
- { .fno = gen_helper_gvec_verll16, },
- { .fni4 = gen_rll_i32, },
- { .fni8 = gen_rll_i64, },
- };
-
- if (es > ES_64) {
- gen_program_exception(s, PGM_SPECIFICATION);
- return DISAS_NORETURN;
- }
- gen_gvec_2s(get_field(s, v1), get_field(s, v3), o->addr1,
- &g[es]);
- return DISAS_NEXT;
-}
-
static void gen_rim_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, int32_t c)
{
TCGv_i32 t = tcg_temp_new_i32();
@@ -1946,6 +1889,9 @@ static DisasJumpType op_vesv(DisasContext *s, DisasOps *o)
case 0x70:
gen_gvec_fn_3(shlv, es, v1, v2, v3);
break;
+ case 0x73:
+ gen_gvec_fn_3(rotlv, es, v1, v2, v3);
+ break;
case 0x7a:
gen_gvec_fn_3(sarv, es, v1, v2, v3);
break;
@@ -1977,6 +1923,9 @@ static DisasJumpType op_ves(DisasContext *s, DisasOps *o)
case 0x30:
gen_gvec_fn_2i(shli, es, v1, v3, d2);
break;
+ case 0x33:
+ gen_gvec_fn_2i(rotli, es, v1, v3, d2);
+ break;
case 0x3a:
gen_gvec_fn_2i(sari, es, v1, v3, d2);
break;
@@ -1994,6 +1943,9 @@ static DisasJumpType op_ves(DisasContext *s, DisasOps *o)
case 0x30:
gen_gvec_fn_2s(shls, es, v1, v3, shift);
break;
+ case 0x33:
+ gen_gvec_fn_2s(rotls, es, v1, v3, shift);
+ break;
case 0x3a:
gen_gvec_fn_2s(sars, es, v1, v3, shift);
break;
diff --git a/target/s390x/vec_int_helper.c b/target/s390x/vec_int_helper.c
index 0d6bc13dd6..5561b3ed90 100644
--- a/target/s390x/vec_int_helper.c
+++ b/target/s390x/vec_int_helper.c
@@ -515,37 +515,6 @@ void HELPER(gvec_vpopct##BITS)(void *v1, const void *v2, uint32_t desc) \
DEF_VPOPCT(8)
DEF_VPOPCT(16)
-#define DEF_VERLLV(BITS) \
-void HELPER(gvec_verllv##BITS)(void *v1, const void *v2, const void *v3, \
- uint32_t desc) \
-{ \
- int i; \
- \
- for (i = 0; i < (128 / BITS); i++) { \
- const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
- const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i); \
- \
- s390_vec_write_element##BITS(v1, i, rol##BITS(a, b)); \
- } \
-}
-DEF_VERLLV(8)
-DEF_VERLLV(16)
-
-#define DEF_VERLL(BITS) \
-void HELPER(gvec_verll##BITS)(void *v1, const void *v2, uint64_t count, \
- uint32_t desc) \
-{ \
- int i; \
- \
- for (i = 0; i < (128 / BITS); i++) { \
- const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
- \
- s390_vec_write_element##BITS(v1, i, rol##BITS(a, count)); \
- } \
-}
-DEF_VERLL(8)
-DEF_VERLL(16)
-
#define DEF_VERIM(BITS) \
void HELPER(gvec_verim##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
diff --git a/target/tricore/Makefile.objs b/target/tricore/Makefile.objs
index 7a05670718..281b55f08d 100644
--- a/target/tricore/Makefile.objs
+++ b/target/tricore/Makefile.objs
@@ -1 +1 @@
-obj-y += translate.o helper.o cpu.o op_helper.o fpu_helper.o
+obj-y += translate.o helper.o cpu.o op_helper.o fpu_helper.o gdbstub.o
diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c
index 743b404a95..2f2e5b029f 100644
--- a/target/tricore/cpu.c
+++ b/target/tricore/cpu.c
@@ -23,17 +23,14 @@
#include "exec/exec-all.h"
#include "qemu/error-report.h"
-static hwaddr tricore_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
- MemTxAttrs *attrs)
+static inline void set_feature(CPUTriCoreState *env, int feature)
{
- error_report("function cpu_get_phys_page_attrs_debug not "
- "implemented, aborting");
- return -1;
+ env->features |= 1ULL << feature;
}
-static inline void set_feature(CPUTriCoreState *env, int feature)
+static gchar *tricore_gdb_arch_name(CPUState *cs)
{
- env->features |= 1ULL << feature;
+ return g_strdup("tricore");
}
static void tricore_cpu_set_pc(CPUState *cs, vaddr value)
@@ -158,10 +155,15 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data)
cc->class_by_name = tricore_cpu_class_by_name;
cc->has_work = tricore_cpu_has_work;
+ cc->gdb_read_register = tricore_cpu_gdb_read_register;
+ cc->gdb_write_register = tricore_cpu_gdb_write_register;
+ cc->gdb_num_core_regs = 44;
+ cc->gdb_arch_name = tricore_gdb_arch_name;
+
cc->dump_state = tricore_cpu_dump_state;
cc->set_pc = tricore_cpu_set_pc;
cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb;
- cc->get_phys_page_attrs_debug = tricore_cpu_get_phys_page_attrs_debug;
+ cc->get_phys_page_debug = tricore_cpu_get_phys_page_debug;
cc->tcg_initialize = tricore_tcg_init;
cc->tlb_fill = tricore_cpu_tlb_fill;
}
diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h
index 8c014fad07..b82349d1b1 100644
--- a/target/tricore/cpu.h
+++ b/target/tricore/cpu.h
@@ -353,6 +353,8 @@ enum {
uint32_t psw_read(CPUTriCoreState *env);
void psw_write(CPUTriCoreState *env, uint32_t val);
+int tricore_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
+int tricore_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
void fpu_set_state(CPUTriCoreState *env);
diff --git a/target/tricore/gdbstub.c b/target/tricore/gdbstub.c
new file mode 100644
index 0000000000..0f4e612a04
--- /dev/null
+++ b/target/tricore/gdbstub.c
@@ -0,0 +1,139 @@
+/*
+ * TriCore gdb server stub
+ *
+ * Copyright (c) 2019 Bastian Koppelmann, Paderborn University
+ *
+ * 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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+
+#define LCX_REGNUM 32
+#define FCX_REGNUM 33
+#define PCXI_REGNUM 34
+#define TRICORE_PSW_REGNUM 35
+#define TRICORE_PC_REGNUM 36
+#define ICR_REGNUM 37
+#define ISP_REGNUM 38
+#define BTV_REGNUM 39
+#define BIV_REGNUM 40
+#define SYSCON_REGNUM 41
+#define PMUCON0_REGNUM 42
+#define DMUCON_REGNUM 43
+
+static uint32_t tricore_cpu_gdb_read_csfr(CPUTriCoreState *env, int n)
+{
+ switch (n) {
+ case LCX_REGNUM:
+ return env->LCX;
+ case FCX_REGNUM:
+ return env->FCX;
+ case PCXI_REGNUM:
+ return env->PCXI;
+ case TRICORE_PSW_REGNUM:
+ return psw_read(env);
+ case TRICORE_PC_REGNUM:
+ return env->PC;
+ case ICR_REGNUM:
+ return env->ICR;
+ case ISP_REGNUM:
+ return env->ISP;
+ case BTV_REGNUM:
+ return env->BTV;
+ case BIV_REGNUM:
+ return env->BIV;
+ case SYSCON_REGNUM:
+ return env->SYSCON;
+ case PMUCON0_REGNUM:
+ return 0; /* PMUCON0 */
+ case DMUCON_REGNUM:
+ return 0; /* DMUCON0 */
+ default:
+ return 0;
+ }
+}
+
+static void tricore_cpu_gdb_write_csfr(CPUTriCoreState *env, int n,
+ uint32_t val)
+{
+ switch (n) {
+ case LCX_REGNUM:
+ env->LCX = val;
+ break;
+ case FCX_REGNUM:
+ env->FCX = val;
+ break;
+ case PCXI_REGNUM:
+ env->PCXI = val;
+ break;
+ case TRICORE_PSW_REGNUM:
+ psw_write(env, val);
+ break;
+ case TRICORE_PC_REGNUM:
+ env->PC = val;
+ break;
+ case ICR_REGNUM:
+ env->ICR = val;
+ break;
+ case ISP_REGNUM:
+ env->ISP = val;
+ break;
+ case BTV_REGNUM:
+ env->BTV = val;
+ break;
+ case BIV_REGNUM:
+ env->BIV = val;
+ break;
+ case SYSCON_REGNUM:
+ env->SYSCON = val;
+ break;
+ }
+}
+
+
+int tricore_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
+{
+ TriCoreCPU *cpu = TRICORE_CPU(cs);
+ CPUTriCoreState *env = &cpu->env;
+
+ if (n < 16) { /* data registers */
+ return gdb_get_reg32(mem_buf, env->gpr_d[n]);
+ } else if (n < 32) { /* address registers */
+ return gdb_get_reg32(mem_buf, env->gpr_a[n - 16]);
+ } else { /* csfr */
+ return gdb_get_reg32(mem_buf, tricore_cpu_gdb_read_csfr(env, n));
+ }
+ return 0;
+}
+
+int tricore_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ TriCoreCPU *cpu = TRICORE_CPU(cs);
+ CPUTriCoreState *env = &cpu->env;
+ uint32_t tmp;
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 16) { /* data registers */
+ env->gpr_d[n] = tmp;
+ } else if (n < 32) { /* address registers */
+ env->gpr_d[n - 16] = tmp;
+ } else {
+ tricore_cpu_gdb_write_csfr(env, n, tmp);
+ }
+ return 4;
+}
diff --git a/target/tricore/helper.c b/target/tricore/helper.c
index d5db7b2c03..7715293263 100644
--- a/target/tricore/helper.c
+++ b/target/tricore/helper.c
@@ -42,6 +42,19 @@ static int get_physical_address(CPUTriCoreState *env, hwaddr *physical,
return ret;
}
+
+hwaddr tricore_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+ TriCoreCPU *cpu = TRICORE_CPU(cs);
+ hwaddr phys_addr;
+ int prot;
+ int mmu_idx = cpu_mmu_index(&cpu->env, false);
+
+ if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) {
+ return -1;
+ }
+ return phys_addr;
+}
#endif
/* TODO: Add exeption support*/
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
index 609d75ae8a..7752630ac1 100644
--- a/target/tricore/translate.c
+++ b/target/tricore/translate.c
@@ -66,14 +66,19 @@ static const char *regnames_d[] = {
typedef struct DisasContext {
DisasContextBase base;
- CPUTriCoreState *env;
target_ulong pc_succ_insn;
uint32_t opcode;
/* Routine used to access memory */
int mem_idx;
uint32_t hflags, saved_hflags;
+ uint64_t features;
} DisasContext;
+static int has_feature(DisasContext *ctx, int feature)
+{
+ return (ctx->features & (1ULL << feature)) != 0;
+}
+
enum {
MODE_LL = 0,
MODE_LU = 1,
@@ -370,7 +375,7 @@ static void gen_swapmsk(DisasContext *ctx, int reg, TCGv ea)
These makros also specify in which ISA version the csfr was introduced. */
#define R(ADDRESS, REG, FEATURE) \
case ADDRESS: \
- if (tricore_feature(ctx->env, FEATURE)) { \
+ if (has_feature(ctx, FEATURE)) { \
tcg_gen_ld_tl(ret, cpu_env, offsetof(CPUTriCoreState, REG)); \
} \
break;
@@ -395,7 +400,7 @@ static inline void gen_mfcr(DisasContext *ctx, TCGv ret, int32_t offset)
since no execption occurs */
#define A(ADDRESS, REG, FEATURE) R(ADDRESS, REG, FEATURE) \
case ADDRESS: \
- if (tricore_feature(ctx->env, FEATURE)) { \
+ if (has_feature(ctx, FEATURE)) { \
tcg_gen_st_tl(r1, cpu_env, offsetof(CPUTriCoreState, REG)); \
} \
break;
@@ -3158,7 +3163,7 @@ gen_dvinit_b(DisasContext *ctx, TCGv rl, TCGv rh, TCGv r1, TCGv r2)
{
TCGv_i64 ret = tcg_temp_new_i64();
- if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) {
+ if (!has_feature(ctx, TRICORE_FEATURE_131)) {
gen_helper_dvinit_b_13(ret, cpu_env, r1, r2);
} else {
gen_helper_dvinit_b_131(ret, cpu_env, r1, r2);
@@ -3173,7 +3178,7 @@ gen_dvinit_h(DisasContext *ctx, TCGv rl, TCGv rh, TCGv r1, TCGv r2)
{
TCGv_i64 ret = tcg_temp_new_i64();
- if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) {
+ if (!has_feature(ctx, TRICORE_FEATURE_131)) {
gen_helper_dvinit_h_13(ret, cpu_env, r1, r2);
} else {
gen_helper_dvinit_h_131(ret, cpu_env, r1, r2);
@@ -3233,6 +3238,14 @@ static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
#endif
}
+static void generate_qemu_excp(DisasContext *ctx, int excp)
+{
+ TCGv_i32 tmp = tcg_const_i32(excp);
+ gen_helper_qemu_excp(cpu_env, tmp);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ tcg_temp_free(tmp);
+}
+
static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
{
if (use_goto_tb(ctx, dest)) {
@@ -3242,7 +3255,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
} else {
gen_save_pc(dest);
if (ctx->base.singlestep_enabled) {
- /* raise exception debug */
+ generate_qemu_excp(ctx, EXCP_DEBUG);
}
tcg_gen_exit_tb(NULL, 0);
}
@@ -3261,15 +3274,6 @@ static void generate_trap(DisasContext *ctx, int class, int tin)
tcg_temp_free(tintemp);
}
-static void generate_qemu_excp(DisasContext *ctx, int excp)
-{
- TCGv_i32 tmp = tcg_const_i32(excp);
- gen_save_pc(ctx->base.pc_next);
- gen_helper_qemu_excp(cpu_env, tmp);
- ctx->base.is_jmp = DISAS_NORETURN;
- tcg_temp_free(tmp);
-}
-
static inline void gen_branch_cond(DisasContext *ctx, TCGCond cond, TCGv r1,
TCGv r2, int16_t address)
{
@@ -3656,7 +3660,7 @@ static void decode_src_opc(DisasContext *ctx, int op1)
tcg_gen_movi_tl(cpu_gpr_a[r1], const4);
break;
case OPC1_16_SRC_MOV_E:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
tcg_gen_movi_tl(cpu_gpr_d[r1], const4);
tcg_gen_sari_tl(cpu_gpr_d[r1+1], cpu_gpr_d[r1], 31);
} else {
@@ -4107,7 +4111,7 @@ static void decode_16Bit_opc(DisasContext *ctx)
break;
case OPC1_16_SBC_JEQ2:
case OPC1_16_SBC_JNE2:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
address = MASK_OP_SBC_DISP4(ctx->opcode);
const16 = MASK_OP_SBC_CONST4_SEXT(ctx->opcode);
gen_compute_branch(ctx, op1, 0, 0, const16, address);
@@ -4125,7 +4129,7 @@ static void decode_16Bit_opc(DisasContext *ctx)
/* SBR-format */
case OPC1_16_SBR_JEQ2:
case OPC1_16_SBR_JNE2:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
r1 = MASK_OP_SBR_S2(ctx->opcode);
address = MASK_OP_SBR_DISP4(ctx->opcode);
gen_compute_branch(ctx, op1, r1, 0, 0, address);
@@ -4705,13 +4709,13 @@ static void decode_bo_addrmode_post_pre_base(DisasContext *ctx)
break;
case OPC2_32_BO_CACHEI_WI_SHORTOFF:
case OPC2_32_BO_CACHEI_W_SHORTOFF:
- if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) {
+ if (!has_feature(ctx, TRICORE_FEATURE_131)) {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC2_32_BO_CACHEI_W_POSTINC:
case OPC2_32_BO_CACHEI_WI_POSTINC:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_131)) {
+ if (has_feature(ctx, TRICORE_FEATURE_131)) {
tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
@@ -4719,7 +4723,7 @@ static void decode_bo_addrmode_post_pre_base(DisasContext *ctx)
break;
case OPC2_32_BO_CACHEI_W_PREINC:
case OPC2_32_BO_CACHEI_WI_PREINC:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_131)) {
+ if (has_feature(ctx, TRICORE_FEATURE_131)) {
tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
@@ -5373,7 +5377,7 @@ static void decode_bol_opc(DisasContext *ctx, int32_t op1)
tcg_gen_addi_tl(cpu_gpr_a[r1], cpu_gpr_a[r2], address);
break;
case OPC1_32_BOL_ST_A_LONGOFF:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
gen_offset_st(ctx, cpu_gpr_a[r1], cpu_gpr_a[r2], address, MO_LEUL);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
@@ -5383,42 +5387,42 @@ static void decode_bol_opc(DisasContext *ctx, int32_t op1)
gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LEUL);
break;
case OPC1_32_BOL_LD_B_LONGOFF:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_SB);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC1_32_BOL_LD_BU_LONGOFF:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_UB);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC1_32_BOL_LD_H_LONGOFF:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LESW);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC1_32_BOL_LD_HU_LONGOFF:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LEUW);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC1_32_BOL_ST_B_LONGOFF:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_SB);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC1_32_BOL_ST_H_LONGOFF:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
gen_offset_st(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], address, MO_LESW);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
@@ -6023,7 +6027,7 @@ static void decode_rlc_opc(DisasContext *ctx,
tcg_gen_movi_tl(cpu_gpr_d[r2], const16);
break;
case OPC1_32_RLC_MOV_64:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
CHECK_REG_PAIR(r2);
tcg_gen_movi_tl(cpu_gpr_d[r2], const16);
tcg_gen_movi_tl(cpu_gpr_d[r2+1], const16 >> 15);
@@ -6249,7 +6253,7 @@ static void decode_rr_accumulator(DisasContext *ctx)
tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r2]);
break;
case OPC2_32_RR_MOV_64:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
temp = tcg_temp_new();
CHECK_REG_PAIR(r3);
@@ -6263,7 +6267,7 @@ static void decode_rr_accumulator(DisasContext *ctx)
}
break;
case OPC2_32_RR_MOVS_64:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
CHECK_REG_PAIR(r3);
tcg_gen_mov_tl(cpu_gpr_d[r3], cpu_gpr_d[r2]);
tcg_gen_sari_tl(cpu_gpr_d[r3 + 1], cpu_gpr_d[r2], 31);
@@ -6603,7 +6607,7 @@ static void decode_rr_divide(DisasContext *ctx)
tcg_gen_shri_tl(temp3, cpu_gpr_d[r1], 8);
/* reset av */
tcg_gen_movi_tl(cpu_PSW_AV, 0);
- if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) {
+ if (!has_feature(ctx, TRICORE_FEATURE_131)) {
/* overflow = (abs(D[r3+1]) >= abs(D[r2])) */
tcg_gen_abs_tl(temp, temp3);
tcg_gen_abs_tl(temp2, cpu_gpr_d[r2]);
@@ -6636,7 +6640,7 @@ static void decode_rr_divide(DisasContext *ctx)
tcg_gen_shri_tl(temp3, cpu_gpr_d[r1], 16);
/* reset av */
tcg_gen_movi_tl(cpu_PSW_AV, 0);
- if (!tricore_feature(ctx->env, TRICORE_FEATURE_131)) {
+ if (!has_feature(ctx, TRICORE_FEATURE_131)) {
/* overflow = (abs(D[r3+1]) >= abs(D[r2])) */
tcg_gen_abs_tl(temp, temp3);
tcg_gen_abs_tl(temp2, cpu_gpr_d[r2]);
@@ -6699,14 +6703,14 @@ static void decode_rr_divide(DisasContext *ctx)
gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]);
break;
case OPC2_32_RR_CRC32:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_161)) {
+ if (has_feature(ctx, TRICORE_FEATURE_161)) {
gen_helper_crc32(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
} else {
generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
}
break;
case OPC2_32_RR_DIV:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
GEN_HELPER_RR(divide, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1],
cpu_gpr_d[r2]);
} else {
@@ -6714,7 +6718,7 @@ static void decode_rr_divide(DisasContext *ctx)
}
break;
case OPC2_32_RR_DIV_U:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
GEN_HELPER_RR(divide_u, cpu_gpr_d[r3], cpu_gpr_d[r3+1],
cpu_gpr_d[r1], cpu_gpr_d[r2]);
} else {
@@ -8412,7 +8416,7 @@ static void decode_sys_interrupts(DisasContext *ctx)
gen_helper_svlcx(cpu_env);
break;
case OPC2_32_SYS_RESTORE:
- if (tricore_feature(ctx->env, TRICORE_FEATURE_16)) {
+ if (has_feature(ctx, TRICORE_FEATURE_16)) {
if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM ||
(ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_UM1) {
tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], 8, 1);
@@ -8793,6 +8797,7 @@ static void tricore_tr_init_disas_context(DisasContextBase *dcbase,
CPUTriCoreState *env = cs->env_ptr;
ctx->mem_idx = cpu_mmu_index(env, false);
ctx->hflags = (uint32_t)ctx->base.tb->flags;
+ ctx->features = env->features;
}
static void tricore_tr_tb_start(DisasContextBase *db, CPUState *cpu)
diff --git a/tcg/README b/tcg/README
index bfa2e4ed24..a64f67809b 100644
--- a/tcg/README
+++ b/tcg/README
@@ -605,10 +605,11 @@ E.g. VECL=1 -> 64 << 1 -> v128, and VECE=2 -> 1 << 2 -> i32.
* shri_vec v0, v1, i2
* sari_vec v0, v1, i2
+* rotli_vec v0, v1, i2
* shrs_vec v0, v1, s2
* sars_vec v0, v1, s2
- Similarly for logical and arithmetic right shift.
+ Similarly for logical and arithmetic right shift, and left rotate.
* shlv_vec v0, v1, v2
@@ -620,8 +621,10 @@ E.g. VECL=1 -> 64 << 1 -> v128, and VECE=2 -> 1 << 2 -> i32.
* shrv_vec v0, v1, v2
* sarv_vec v0, v1, v2
+* rotlv_vec v0, v1, v2
+* rotrv_vec v0, v1, v2
- Similarly for logical and arithmetic right shift.
+ Similarly for logical and arithmetic right shift, and rotates.
* cmp_vec v0, v1, v2, cond
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index ca214f6909..9bc2a5ecbe 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -133,6 +133,9 @@ typedef enum {
#define TCG_TARGET_HAS_not_vec 1
#define TCG_TARGET_HAS_neg_vec 1
#define TCG_TARGET_HAS_abs_vec 1
+#define TCG_TARGET_HAS_roti_vec 0
+#define TCG_TARGET_HAS_rots_vec 0
+#define TCG_TARGET_HAS_rotv_vec 0
#define TCG_TARGET_HAS_shi_vec 1
#define TCG_TARGET_HAS_shs_vec 0
#define TCG_TARGET_HAS_shv_vec 1
diff --git a/tcg/aarch64/tcg-target.inc.c b/tcg/aarch64/tcg-target.inc.c
index 843fd0ca69..760b0e742d 100644
--- a/tcg/aarch64/tcg-target.inc.c
+++ b/tcg/aarch64/tcg-target.inc.c
@@ -557,6 +557,7 @@ typedef enum {
I3614_SSHR = 0x0f000400,
I3614_SSRA = 0x0f001400,
I3614_SHL = 0x0f005400,
+ I3614_SLI = 0x2f005400,
I3614_USHR = 0x2f000400,
I3614_USRA = 0x2f001400,
@@ -2411,6 +2412,9 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
case INDEX_op_sari_vec:
tcg_out_insn(s, 3614, SSHR, is_q, a0, a1, (16 << vece) - a2);
break;
+ case INDEX_op_aa64_sli_vec:
+ tcg_out_insn(s, 3614, SLI, is_q, a0, a2, args[3] + (8 << vece));
+ break;
case INDEX_op_shlv_vec:
tcg_out_insn(s, 3616, USHL, is_q, vece, a0, a1, a2);
break;
@@ -2498,8 +2502,11 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
case INDEX_op_shlv_vec:
case INDEX_op_bitsel_vec:
return 1;
+ case INDEX_op_rotli_vec:
case INDEX_op_shrv_vec:
case INDEX_op_sarv_vec:
+ case INDEX_op_rotlv_vec:
+ case INDEX_op_rotrv_vec:
return -1;
case INDEX_op_mul_vec:
case INDEX_op_smax_vec:
@@ -2517,14 +2524,24 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
TCGArg a0, ...)
{
va_list va;
- TCGv_vec v0, v1, v2, t1;
+ TCGv_vec v0, v1, v2, t1, t2;
+ TCGArg a2;
va_start(va, a0);
v0 = temp_tcgv_vec(arg_temp(a0));
v1 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
- v2 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
+ a2 = va_arg(va, TCGArg);
+ v2 = temp_tcgv_vec(arg_temp(a2));
switch (opc) {
+ case INDEX_op_rotli_vec:
+ t1 = tcg_temp_new_vec(type);
+ tcg_gen_shri_vec(vece, t1, v1, -a2 & ((8 << vece) - 1));
+ vec_gen_4(INDEX_op_aa64_sli_vec, type, vece,
+ tcgv_vec_arg(v0), tcgv_vec_arg(t1), tcgv_vec_arg(v1), a2);
+ tcg_temp_free_vec(t1);
+ break;
+
case INDEX_op_shrv_vec:
case INDEX_op_sarv_vec:
/* Right shifts are negative left shifts for AArch64. */
@@ -2537,6 +2554,35 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
tcg_temp_free_vec(t1);
break;
+ case INDEX_op_rotlv_vec:
+ t1 = tcg_temp_new_vec(type);
+ tcg_gen_dupi_vec(vece, t1, 8 << vece);
+ tcg_gen_sub_vec(vece, t1, v2, t1);
+ /* Right shifts are negative left shifts for AArch64. */
+ vec_gen_3(INDEX_op_shlv_vec, type, vece, tcgv_vec_arg(t1),
+ tcgv_vec_arg(v1), tcgv_vec_arg(t1));
+ vec_gen_3(INDEX_op_shlv_vec, type, vece, tcgv_vec_arg(v0),
+ tcgv_vec_arg(v1), tcgv_vec_arg(v2));
+ tcg_gen_or_vec(vece, v0, v0, t1);
+ tcg_temp_free_vec(t1);
+ break;
+
+ case INDEX_op_rotrv_vec:
+ t1 = tcg_temp_new_vec(type);
+ t2 = tcg_temp_new_vec(type);
+ tcg_gen_neg_vec(vece, t1, v2);
+ tcg_gen_dupi_vec(vece, t2, 8 << vece);
+ tcg_gen_add_vec(vece, t2, t1, t2);
+ /* Right shifts are negative left shifts for AArch64. */
+ vec_gen_3(INDEX_op_shlv_vec, type, vece, tcgv_vec_arg(t1),
+ tcgv_vec_arg(v1), tcgv_vec_arg(t1));
+ vec_gen_3(INDEX_op_shlv_vec, type, vece, tcgv_vec_arg(t2),
+ tcgv_vec_arg(v1), tcgv_vec_arg(t2));
+ tcg_gen_or_vec(vece, v0, t1, t2);
+ tcg_temp_free_vec(t1);
+ tcg_temp_free_vec(t2);
+ break;
+
default:
g_assert_not_reached();
}
@@ -2557,6 +2603,7 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
static const TCGTargetOpDef lZ_l = { .args_ct_str = { "lZ", "l" } };
static const TCGTargetOpDef r_r_r = { .args_ct_str = { "r", "r", "r" } };
static const TCGTargetOpDef w_w_w = { .args_ct_str = { "w", "w", "w" } };
+ static const TCGTargetOpDef w_0_w = { .args_ct_str = { "w", "0", "w" } };
static const TCGTargetOpDef w_w_wO = { .args_ct_str = { "w", "w", "wO" } };
static const TCGTargetOpDef w_w_wN = { .args_ct_str = { "w", "w", "wN" } };
static const TCGTargetOpDef w_w_wZ = { .args_ct_str = { "w", "w", "wZ" } };
@@ -2751,6 +2798,8 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
return &w_w_wZ;
case INDEX_op_bitsel_vec:
return &w_w_w_w;
+ case INDEX_op_aa64_sli_vec:
+ return &w_0_w;
default:
return NULL;
diff --git a/tcg/aarch64/tcg-target.opc.h b/tcg/aarch64/tcg-target.opc.h
index 26bfd9c460..bce30accd9 100644
--- a/tcg/aarch64/tcg-target.opc.h
+++ b/tcg/aarch64/tcg-target.opc.h
@@ -12,3 +12,4 @@
*/
DEF(aa64_sshl_vec, 1, 2, 0, IMPLVEC)
+DEF(aa64_sli_vec, 1, 2, 1, IMPLVEC)
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index bfb3f5f6e9..99ac1e3958 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -183,6 +183,9 @@ extern bool have_avx2;
#define TCG_TARGET_HAS_not_vec 0
#define TCG_TARGET_HAS_neg_vec 0
#define TCG_TARGET_HAS_abs_vec 1
+#define TCG_TARGET_HAS_roti_vec 0
+#define TCG_TARGET_HAS_rots_vec 0
+#define TCG_TARGET_HAS_rotv_vec 0
#define TCG_TARGET_HAS_shi_vec 1
#define TCG_TARGET_HAS_shs_vec 1
#define TCG_TARGET_HAS_shv_vec have_avx2
diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c
index ec083bddcf..ae0228238b 100644
--- a/tcg/i386/tcg-target.inc.c
+++ b/tcg/i386/tcg-target.inc.c
@@ -3233,6 +3233,7 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
case INDEX_op_shls_vec:
case INDEX_op_shrs_vec:
case INDEX_op_sars_vec:
+ case INDEX_op_rotls_vec:
case INDEX_op_cmp_vec:
case INDEX_op_x86_shufps_vec:
case INDEX_op_x86_blend_vec:
@@ -3271,6 +3272,7 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
case INDEX_op_xor_vec:
case INDEX_op_andc_vec:
return 1;
+ case INDEX_op_rotli_vec:
case INDEX_op_cmp_vec:
case INDEX_op_cmpsel_vec:
return -1;
@@ -3297,12 +3299,17 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
return vece >= MO_16;
case INDEX_op_sars_vec:
return vece >= MO_16 && vece <= MO_32;
+ case INDEX_op_rotls_vec:
+ return vece >= MO_16 ? -1 : 0;
case INDEX_op_shlv_vec:
case INDEX_op_shrv_vec:
return have_avx2 && vece >= MO_32;
case INDEX_op_sarv_vec:
return have_avx2 && vece == MO_32;
+ case INDEX_op_rotlv_vec:
+ case INDEX_op_rotrv_vec:
+ return have_avx2 && vece >= MO_32 ? -1 : 0;
case INDEX_op_mul_vec:
if (vece == MO_8) {
@@ -3331,7 +3338,7 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
}
}
-static void expand_vec_shi(TCGType type, unsigned vece, bool shr,
+static void expand_vec_shi(TCGType type, unsigned vece, TCGOpcode opc,
TCGv_vec v0, TCGv_vec v1, TCGArg imm)
{
TCGv_vec t1, t2;
@@ -3341,26 +3348,31 @@ static void expand_vec_shi(TCGType type, unsigned vece, bool shr,
t1 = tcg_temp_new_vec(type);
t2 = tcg_temp_new_vec(type);
- /* Unpack to W, shift, and repack. Tricky bits:
- (1) Use punpck*bw x,x to produce DDCCBBAA,
- i.e. duplicate in other half of the 16-bit lane.
- (2) For right-shift, add 8 so that the high half of
- the lane becomes zero. For left-shift, we must
- shift up and down again.
- (3) Step 2 leaves high half zero such that PACKUSWB
- (pack with unsigned saturation) does not modify
- the quantity. */
+ /*
+ * Unpack to W, shift, and repack. Tricky bits:
+ * (1) Use punpck*bw x,x to produce DDCCBBAA,
+ * i.e. duplicate in other half of the 16-bit lane.
+ * (2) For right-shift, add 8 so that the high half of the lane
+ * becomes zero. For left-shift, and left-rotate, we must
+ * shift up and down again.
+ * (3) Step 2 leaves high half zero such that PACKUSWB
+ * (pack with unsigned saturation) does not modify
+ * the quantity.
+ */
vec_gen_3(INDEX_op_x86_punpckl_vec, type, MO_8,
tcgv_vec_arg(t1), tcgv_vec_arg(v1), tcgv_vec_arg(v1));
vec_gen_3(INDEX_op_x86_punpckh_vec, type, MO_8,
tcgv_vec_arg(t2), tcgv_vec_arg(v1), tcgv_vec_arg(v1));
- if (shr) {
- tcg_gen_shri_vec(MO_16, t1, t1, imm + 8);
- tcg_gen_shri_vec(MO_16, t2, t2, imm + 8);
+ if (opc != INDEX_op_rotli_vec) {
+ imm += 8;
+ }
+ if (opc == INDEX_op_shri_vec) {
+ tcg_gen_shri_vec(MO_16, t1, t1, imm);
+ tcg_gen_shri_vec(MO_16, t2, t2, imm);
} else {
- tcg_gen_shli_vec(MO_16, t1, t1, imm + 8);
- tcg_gen_shli_vec(MO_16, t2, t2, imm + 8);
+ tcg_gen_shli_vec(MO_16, t1, t1, imm);
+ tcg_gen_shli_vec(MO_16, t2, t2, imm);
tcg_gen_shri_vec(MO_16, t1, t1, 8);
tcg_gen_shri_vec(MO_16, t2, t2, 8);
}
@@ -3427,6 +3439,61 @@ static void expand_vec_sari(TCGType type, unsigned vece,
}
}
+static void expand_vec_rotli(TCGType type, unsigned vece,
+ TCGv_vec v0, TCGv_vec v1, TCGArg imm)
+{
+ TCGv_vec t;
+
+ if (vece == MO_8) {
+ expand_vec_shi(type, vece, INDEX_op_rotli_vec, v0, v1, imm);
+ return;
+ }
+
+ t = tcg_temp_new_vec(type);
+ tcg_gen_shli_vec(vece, t, v1, imm);
+ tcg_gen_shri_vec(vece, v0, v1, (8 << vece) - imm);
+ tcg_gen_or_vec(vece, v0, v0, t);
+ tcg_temp_free_vec(t);
+}
+
+static void expand_vec_rotls(TCGType type, unsigned vece,
+ TCGv_vec v0, TCGv_vec v1, TCGv_i32 lsh)
+{
+ TCGv_i32 rsh;
+ TCGv_vec t;
+
+ tcg_debug_assert(vece != MO_8);
+
+ t = tcg_temp_new_vec(type);
+ rsh = tcg_temp_new_i32();
+
+ tcg_gen_neg_i32(rsh, lsh);
+ tcg_gen_andi_i32(rsh, rsh, (8 << vece) - 1);
+ tcg_gen_shls_vec(vece, t, v1, lsh);
+ tcg_gen_shrs_vec(vece, v0, v1, rsh);
+ tcg_gen_or_vec(vece, v0, v0, t);
+ tcg_temp_free_vec(t);
+ tcg_temp_free_i32(rsh);
+}
+
+static void expand_vec_rotv(TCGType type, unsigned vece, TCGv_vec v0,
+ TCGv_vec v1, TCGv_vec sh, bool right)
+{
+ TCGv_vec t = tcg_temp_new_vec(type);
+
+ tcg_gen_dupi_vec(vece, t, 8 << vece);
+ tcg_gen_sub_vec(vece, t, t, sh);
+ if (right) {
+ tcg_gen_shlv_vec(vece, t, v1, t);
+ tcg_gen_shrv_vec(vece, v0, v1, sh);
+ } else {
+ tcg_gen_shrv_vec(vece, t, v1, t);
+ tcg_gen_shlv_vec(vece, v0, v1, sh);
+ }
+ tcg_gen_or_vec(vece, v0, v0, t);
+ tcg_temp_free_vec(t);
+}
+
static void expand_vec_mul(TCGType type, unsigned vece,
TCGv_vec v0, TCGv_vec v1, TCGv_vec v2)
{
@@ -3636,13 +3703,30 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
switch (opc) {
case INDEX_op_shli_vec:
case INDEX_op_shri_vec:
- expand_vec_shi(type, vece, opc == INDEX_op_shri_vec, v0, v1, a2);
+ expand_vec_shi(type, vece, opc, v0, v1, a2);
break;
case INDEX_op_sari_vec:
expand_vec_sari(type, vece, v0, v1, a2);
break;
+ case INDEX_op_rotli_vec:
+ expand_vec_rotli(type, vece, v0, v1, a2);
+ break;
+
+ case INDEX_op_rotls_vec:
+ expand_vec_rotls(type, vece, v0, v1, temp_tcgv_i32(arg_temp(a2)));
+ break;
+
+ case INDEX_op_rotlv_vec:
+ v2 = temp_tcgv_vec(arg_temp(a2));
+ expand_vec_rotv(type, vece, v0, v1, v2, false);
+ break;
+ case INDEX_op_rotrv_vec:
+ v2 = temp_tcgv_vec(arg_temp(a2));
+ expand_vec_rotv(type, vece, v0, v1, v2, true);
+ break;
+
case INDEX_op_mul_vec:
v2 = temp_tcgv_vec(arg_temp(a2));
expand_vec_mul(type, vece, v0, v1, v2);
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 4fa21f0e71..be5b2901c3 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -161,6 +161,9 @@ extern bool have_vsx;
#define TCG_TARGET_HAS_not_vec 1
#define TCG_TARGET_HAS_neg_vec have_isa_3_00
#define TCG_TARGET_HAS_abs_vec 0
+#define TCG_TARGET_HAS_roti_vec 0
+#define TCG_TARGET_HAS_rots_vec 0
+#define TCG_TARGET_HAS_rotv_vec 1
#define TCG_TARGET_HAS_shi_vec 0
#define TCG_TARGET_HAS_shs_vec 0
#define TCG_TARGET_HAS_shv_vec 1
diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c
index ee1f9227c1..7da67086c6 100644
--- a/tcg/ppc/tcg-target.inc.c
+++ b/tcg/ppc/tcg-target.inc.c
@@ -2995,6 +2995,7 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
case INDEX_op_shlv_vec:
case INDEX_op_shrv_vec:
case INDEX_op_sarv_vec:
+ case INDEX_op_rotlv_vec:
return vece <= MO_32 || have_isa_2_07;
case INDEX_op_ssadd_vec:
case INDEX_op_sssub_vec:
@@ -3005,6 +3006,7 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
case INDEX_op_shli_vec:
case INDEX_op_shri_vec:
case INDEX_op_sari_vec:
+ case INDEX_op_rotli_vec:
return vece <= MO_32 || have_isa_2_07 ? -1 : 0;
case INDEX_op_neg_vec:
return vece >= MO_32 && have_isa_3_00;
@@ -3019,6 +3021,8 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
return 0;
case INDEX_op_bitsel_vec:
return have_vsx;
+ case INDEX_op_rotrv_vec:
+ return -1;
default:
return 0;
}
@@ -3301,7 +3305,7 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
case INDEX_op_ppc_pkum_vec:
insn = pkum_op[vece];
break;
- case INDEX_op_ppc_rotl_vec:
+ case INDEX_op_rotlv_vec:
insn = rotl_op[vece];
break;
case INDEX_op_ppc_msum_vec:
@@ -3409,7 +3413,7 @@ static void expand_vec_mul(TCGType type, unsigned vece, TCGv_vec v0,
t3 = tcg_temp_new_vec(type);
t4 = tcg_temp_new_vec(type);
tcg_gen_dupi_vec(MO_8, t4, -16);
- vec_gen_3(INDEX_op_ppc_rotl_vec, type, MO_32, tcgv_vec_arg(t1),
+ vec_gen_3(INDEX_op_rotlv_vec, type, MO_32, tcgv_vec_arg(t1),
tcgv_vec_arg(v2), tcgv_vec_arg(t4));
vec_gen_3(INDEX_op_ppc_mulou_vec, type, MO_16, tcgv_vec_arg(t2),
tcgv_vec_arg(v1), tcgv_vec_arg(v2));
@@ -3434,7 +3438,7 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
TCGArg a0, ...)
{
va_list va;
- TCGv_vec v0, v1, v2;
+ TCGv_vec v0, v1, v2, t0;
TCGArg a2;
va_start(va, a0);
@@ -3452,6 +3456,9 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
case INDEX_op_sari_vec:
expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_sarv_vec);
break;
+ case INDEX_op_rotli_vec:
+ expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_rotlv_vec);
+ break;
case INDEX_op_cmp_vec:
v2 = temp_tcgv_vec(arg_temp(a2));
expand_vec_cmp(type, vece, v0, v1, v2, va_arg(va, TCGArg));
@@ -3460,6 +3467,13 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
v2 = temp_tcgv_vec(arg_temp(a2));
expand_vec_mul(type, vece, v0, v1, v2);
break;
+ case INDEX_op_rotlv_vec:
+ v2 = temp_tcgv_vec(arg_temp(a2));
+ t0 = tcg_temp_new_vec(type);
+ tcg_gen_neg_vec(vece, t0, v2);
+ tcg_gen_rotlv_vec(vece, v0, v1, t0);
+ tcg_temp_free_vec(t0);
+ break;
default:
g_assert_not_reached();
}
@@ -3664,12 +3678,13 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
case INDEX_op_shlv_vec:
case INDEX_op_shrv_vec:
case INDEX_op_sarv_vec:
+ case INDEX_op_rotlv_vec:
+ case INDEX_op_rotrv_vec:
case INDEX_op_ppc_mrgh_vec:
case INDEX_op_ppc_mrgl_vec:
case INDEX_op_ppc_muleu_vec:
case INDEX_op_ppc_mulou_vec:
case INDEX_op_ppc_pkum_vec:
- case INDEX_op_ppc_rotl_vec:
case INDEX_op_dup2_vec:
return &v_v_v;
case INDEX_op_not_vec:
diff --git a/tcg/ppc/tcg-target.opc.h b/tcg/ppc/tcg-target.opc.h
index 1373f77e82..db514403c3 100644
--- a/tcg/ppc/tcg-target.opc.h
+++ b/tcg/ppc/tcg-target.opc.h
@@ -30,4 +30,3 @@ DEF(ppc_msum_vec, 1, 3, 0, IMPLVEC)
DEF(ppc_muleu_vec, 1, 2, 0, IMPLVEC)
DEF(ppc_mulou_vec, 1, 2, 0, IMPLVEC)
DEF(ppc_pkum_vec, 1, 2, 0, IMPLVEC)
-DEF(ppc_rotl_vec, 1, 2, 0, IMPLVEC)
diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c
index 049a55e700..3707c0effb 100644
--- a/tcg/tcg-op-gvec.c
+++ b/tcg/tcg-op-gvec.c
@@ -2694,6 +2694,74 @@ void tcg_gen_gvec_sari(unsigned vece, uint32_t dofs, uint32_t aofs,
}
}
+void tcg_gen_vec_rotl8i_i64(TCGv_i64 d, TCGv_i64 a, int64_t c)
+{
+ uint64_t mask = dup_const(MO_8, 0xff << c);
+
+ tcg_gen_shli_i64(d, a, c);
+ tcg_gen_shri_i64(a, a, 8 - c);
+ tcg_gen_andi_i64(d, d, mask);
+ tcg_gen_andi_i64(a, a, ~mask);
+ tcg_gen_or_i64(d, d, a);
+}
+
+void tcg_gen_vec_rotl16i_i64(TCGv_i64 d, TCGv_i64 a, int64_t c)
+{
+ uint64_t mask = dup_const(MO_16, 0xffff << c);
+
+ tcg_gen_shli_i64(d, a, c);
+ tcg_gen_shri_i64(a, a, 16 - c);
+ tcg_gen_andi_i64(d, d, mask);
+ tcg_gen_andi_i64(a, a, ~mask);
+ tcg_gen_or_i64(d, d, a);
+}
+
+void tcg_gen_gvec_rotli(unsigned vece, uint32_t dofs, uint32_t aofs,
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
+{
+ static const TCGOpcode vecop_list[] = { INDEX_op_rotli_vec, 0 };
+ static const GVecGen2i g[4] = {
+ { .fni8 = tcg_gen_vec_rotl8i_i64,
+ .fniv = tcg_gen_rotli_vec,
+ .fno = gen_helper_gvec_rotl8i,
+ .opt_opc = vecop_list,
+ .vece = MO_8 },
+ { .fni8 = tcg_gen_vec_rotl16i_i64,
+ .fniv = tcg_gen_rotli_vec,
+ .fno = gen_helper_gvec_rotl16i,
+ .opt_opc = vecop_list,
+ .vece = MO_16 },
+ { .fni4 = tcg_gen_rotli_i32,
+ .fniv = tcg_gen_rotli_vec,
+ .fno = gen_helper_gvec_rotl32i,
+ .opt_opc = vecop_list,
+ .vece = MO_32 },
+ { .fni8 = tcg_gen_rotli_i64,
+ .fniv = tcg_gen_rotli_vec,
+ .fno = gen_helper_gvec_rotl64i,
+ .opt_opc = vecop_list,
+ .prefer_i64 = TCG_TARGET_REG_BITS == 64,
+ .vece = MO_64 },
+ };
+
+ tcg_debug_assert(vece <= MO_64);
+ tcg_debug_assert(shift >= 0 && shift < (8 << vece));
+ if (shift == 0) {
+ tcg_gen_gvec_mov(vece, dofs, aofs, oprsz, maxsz);
+ } else {
+ tcg_gen_gvec_2i(dofs, aofs, oprsz, maxsz, shift, &g[vece]);
+ }
+}
+
+void tcg_gen_gvec_rotri(unsigned vece, uint32_t dofs, uint32_t aofs,
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
+{
+ tcg_debug_assert(vece <= MO_64);
+ tcg_debug_assert(shift >= 0 && shift < (8 << vece));
+ tcg_gen_gvec_rotli(vece, dofs, aofs, -shift & ((8 << vece) - 1),
+ oprsz, maxsz);
+}
+
/*
* Specialized generation vector shifts by a non-constant scalar.
*/
@@ -2908,6 +2976,28 @@ void tcg_gen_gvec_sars(unsigned vece, uint32_t dofs, uint32_t aofs,
do_gvec_shifts(vece, dofs, aofs, shift, oprsz, maxsz, &g);
}
+void tcg_gen_gvec_rotls(unsigned vece, uint32_t dofs, uint32_t aofs,
+ TCGv_i32 shift, uint32_t oprsz, uint32_t maxsz)
+{
+ static const GVecGen2sh g = {
+ .fni4 = tcg_gen_rotl_i32,
+ .fni8 = tcg_gen_rotl_i64,
+ .fniv_s = tcg_gen_rotls_vec,
+ .fniv_v = tcg_gen_rotlv_vec,
+ .fno = {
+ gen_helper_gvec_rotl8i,
+ gen_helper_gvec_rotl16i,
+ gen_helper_gvec_rotl32i,
+ gen_helper_gvec_rotl64i,
+ },
+ .s_list = { INDEX_op_rotls_vec, 0 },
+ .v_list = { INDEX_op_rotlv_vec, 0 },
+ };
+
+ tcg_debug_assert(vece <= MO_64);
+ do_gvec_shifts(vece, dofs, aofs, shift, oprsz, maxsz, &g);
+}
+
/*
* Expand D = A << (B % element bits)
*
@@ -3103,6 +3193,128 @@ void tcg_gen_gvec_sarv(unsigned vece, uint32_t dofs, uint32_t aofs,
tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]);
}
+/*
+ * Similarly for rotates.
+ */
+
+static void tcg_gen_rotlv_mod_vec(unsigned vece, TCGv_vec d,
+ TCGv_vec a, TCGv_vec b)
+{
+ TCGv_vec t = tcg_temp_new_vec_matching(d);
+
+ tcg_gen_dupi_vec(vece, t, (8 << vece) - 1);
+ tcg_gen_and_vec(vece, t, t, b);
+ tcg_gen_rotlv_vec(vece, d, a, t);
+ tcg_temp_free_vec(t);
+}
+
+static void tcg_gen_rotl_mod_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
+{
+ TCGv_i32 t = tcg_temp_new_i32();
+
+ tcg_gen_andi_i32(t, b, 31);
+ tcg_gen_rotl_i32(d, a, t);
+ tcg_temp_free_i32(t);
+}
+
+static void tcg_gen_rotl_mod_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ tcg_gen_andi_i64(t, b, 63);
+ tcg_gen_rotl_i64(d, a, t);
+ tcg_temp_free_i64(t);
+}
+
+void tcg_gen_gvec_rotlv(unsigned vece, uint32_t dofs, uint32_t aofs,
+ uint32_t bofs, uint32_t oprsz, uint32_t maxsz)
+{
+ static const TCGOpcode vecop_list[] = { INDEX_op_rotlv_vec, 0 };
+ static const GVecGen3 g[4] = {
+ { .fniv = tcg_gen_rotlv_mod_vec,
+ .fno = gen_helper_gvec_rotl8v,
+ .opt_opc = vecop_list,
+ .vece = MO_8 },
+ { .fniv = tcg_gen_rotlv_mod_vec,
+ .fno = gen_helper_gvec_rotl16v,
+ .opt_opc = vecop_list,
+ .vece = MO_16 },
+ { .fni4 = tcg_gen_rotl_mod_i32,
+ .fniv = tcg_gen_rotlv_mod_vec,
+ .fno = gen_helper_gvec_rotl32v,
+ .opt_opc = vecop_list,
+ .vece = MO_32 },
+ { .fni8 = tcg_gen_rotl_mod_i64,
+ .fniv = tcg_gen_rotlv_mod_vec,
+ .fno = gen_helper_gvec_rotl64v,
+ .opt_opc = vecop_list,
+ .prefer_i64 = TCG_TARGET_REG_BITS == 64,
+ .vece = MO_64 },
+ };
+
+ tcg_debug_assert(vece <= MO_64);
+ tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]);
+}
+
+static void tcg_gen_rotrv_mod_vec(unsigned vece, TCGv_vec d,
+ TCGv_vec a, TCGv_vec b)
+{
+ TCGv_vec t = tcg_temp_new_vec_matching(d);
+
+ tcg_gen_dupi_vec(vece, t, (8 << vece) - 1);
+ tcg_gen_and_vec(vece, t, t, b);
+ tcg_gen_rotrv_vec(vece, d, a, t);
+ tcg_temp_free_vec(t);
+}
+
+static void tcg_gen_rotr_mod_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
+{
+ TCGv_i32 t = tcg_temp_new_i32();
+
+ tcg_gen_andi_i32(t, b, 31);
+ tcg_gen_rotr_i32(d, a, t);
+ tcg_temp_free_i32(t);
+}
+
+static void tcg_gen_rotr_mod_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+ TCGv_i64 t = tcg_temp_new_i64();
+
+ tcg_gen_andi_i64(t, b, 63);
+ tcg_gen_rotr_i64(d, a, t);
+ tcg_temp_free_i64(t);
+}
+
+void tcg_gen_gvec_rotrv(unsigned vece, uint32_t dofs, uint32_t aofs,
+ uint32_t bofs, uint32_t oprsz, uint32_t maxsz)
+{
+ static const TCGOpcode vecop_list[] = { INDEX_op_rotrv_vec, 0 };
+ static const GVecGen3 g[4] = {
+ { .fniv = tcg_gen_rotrv_mod_vec,
+ .fno = gen_helper_gvec_rotr8v,
+ .opt_opc = vecop_list,
+ .vece = MO_8 },
+ { .fniv = tcg_gen_rotrv_mod_vec,
+ .fno = gen_helper_gvec_rotr16v,
+ .opt_opc = vecop_list,
+ .vece = MO_16 },
+ { .fni4 = tcg_gen_rotr_mod_i32,
+ .fniv = tcg_gen_rotrv_mod_vec,
+ .fno = gen_helper_gvec_rotr32v,
+ .opt_opc = vecop_list,
+ .vece = MO_32 },
+ { .fni8 = tcg_gen_rotr_mod_i64,
+ .fniv = tcg_gen_rotrv_mod_vec,
+ .fno = gen_helper_gvec_rotr64v,
+ .opt_opc = vecop_list,
+ .prefer_i64 = TCG_TARGET_REG_BITS == 64,
+ .vece = MO_64 },
+ };
+
+ tcg_debug_assert(vece <= MO_64);
+ tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]);
+}
+
/* Expand OPSZ bytes worth of three-operand operations using i32 elements. */
static void expand_cmp_i32(uint32_t dofs, uint32_t aofs, uint32_t bofs,
uint32_t oprsz, TCGCond cond)
diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c
index b6937e8d64..f784517d84 100644
--- a/tcg/tcg-op-vec.c
+++ b/tcg/tcg-op-vec.c
@@ -545,6 +545,18 @@ void tcg_gen_sari_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i)
do_shifti(INDEX_op_sari_vec, vece, r, a, i);
}
+void tcg_gen_rotli_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i)
+{
+ do_shifti(INDEX_op_rotli_vec, vece, r, a, i);
+}
+
+void tcg_gen_rotri_vec(unsigned vece, TCGv_vec r, TCGv_vec a, int64_t i)
+{
+ int bits = 8 << vece;
+ tcg_debug_assert(i >= 0 && i < bits);
+ do_shifti(INDEX_op_rotli_vec, vece, r, a, -i & (bits - 1));
+}
+
void tcg_gen_cmp_vec(TCGCond cond, unsigned vece,
TCGv_vec r, TCGv_vec a, TCGv_vec b)
{
@@ -684,8 +696,18 @@ void tcg_gen_sarv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
do_op3_nofail(vece, r, a, b, INDEX_op_sarv_vec);
}
+void tcg_gen_rotlv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
+{
+ do_op3_nofail(vece, r, a, b, INDEX_op_rotlv_vec);
+}
+
+void tcg_gen_rotrv_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
+{
+ do_op3_nofail(vece, r, a, b, INDEX_op_rotrv_vec);
+}
+
static void do_shifts(unsigned vece, TCGv_vec r, TCGv_vec a,
- TCGv_i32 s, TCGOpcode opc_s, TCGOpcode opc_v)
+ TCGv_i32 s, TCGOpcode opc)
{
TCGTemp *rt = tcgv_vec_temp(r);
TCGTemp *at = tcgv_vec_temp(a);
@@ -694,48 +716,40 @@ static void do_shifts(unsigned vece, TCGv_vec r, TCGv_vec a,
TCGArg ai = temp_arg(at);
TCGArg si = temp_arg(st);
TCGType type = rt->base_type;
- const TCGOpcode *hold_list;
int can;
tcg_debug_assert(at->base_type >= type);
- tcg_assert_listed_vecop(opc_s);
- hold_list = tcg_swap_vecop_list(NULL);
-
- can = tcg_can_emit_vec_op(opc_s, type, vece);
+ tcg_assert_listed_vecop(opc);
+ can = tcg_can_emit_vec_op(opc, type, vece);
if (can > 0) {
- vec_gen_3(opc_s, type, vece, ri, ai, si);
+ vec_gen_3(opc, type, vece, ri, ai, si);
} else if (can < 0) {
- tcg_expand_vec_op(opc_s, type, vece, ri, ai, si);
+ const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL);
+ tcg_expand_vec_op(opc, type, vece, ri, ai, si);
+ tcg_swap_vecop_list(hold_list);
} else {
- TCGv_vec vec_s = tcg_temp_new_vec(type);
-
- if (vece == MO_64) {
- TCGv_i64 s64 = tcg_temp_new_i64();
- tcg_gen_extu_i32_i64(s64, s);
- tcg_gen_dup_i64_vec(MO_64, vec_s, s64);
- tcg_temp_free_i64(s64);
- } else {
- tcg_gen_dup_i32_vec(vece, vec_s, s);
- }
- do_op3_nofail(vece, r, a, vec_s, opc_v);
- tcg_temp_free_vec(vec_s);
+ g_assert_not_reached();
}
- tcg_swap_vecop_list(hold_list);
}
void tcg_gen_shls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b)
{
- do_shifts(vece, r, a, b, INDEX_op_shls_vec, INDEX_op_shlv_vec);
+ do_shifts(vece, r, a, b, INDEX_op_shls_vec);
}
void tcg_gen_shrs_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b)
{
- do_shifts(vece, r, a, b, INDEX_op_shrs_vec, INDEX_op_shrv_vec);
+ do_shifts(vece, r, a, b, INDEX_op_shrs_vec);
}
void tcg_gen_sars_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 b)
{
- do_shifts(vece, r, a, b, INDEX_op_sars_vec, INDEX_op_sarv_vec);
+ do_shifts(vece, r, a, b, INDEX_op_sars_vec);
+}
+
+void tcg_gen_rotls_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_i32 s)
+{
+ do_shifts(vece, r, a, s, INDEX_op_rotls_vec);
}
void tcg_gen_bitsel_vec(unsigned vece, TCGv_vec r, TCGv_vec a,
diff --git a/tcg/tcg.c b/tcg/tcg.c
index a2268d9db0..1aa6cb47f2 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1661,6 +1661,13 @@ bool tcg_op_supported(TCGOpcode op)
case INDEX_op_shrv_vec:
case INDEX_op_sarv_vec:
return have_vec && TCG_TARGET_HAS_shv_vec;
+ case INDEX_op_rotli_vec:
+ return have_vec && TCG_TARGET_HAS_roti_vec;
+ case INDEX_op_rotls_vec:
+ return have_vec && TCG_TARGET_HAS_rots_vec;
+ case INDEX_op_rotlv_vec:
+ case INDEX_op_rotrv_vec:
+ return have_vec && TCG_TARGET_HAS_rotv_vec;
case INDEX_op_ssadd_vec:
case INDEX_op_usadd_vec:
case INDEX_op_sssub_vec:
@@ -2975,34 +2982,68 @@ static bool liveness_pass_2(TCGContext *s)
}
/* Outputs become available. */
- for (i = 0; i < nb_oargs; i++) {
- arg_ts = arg_temp(op->args[i]);
+ if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) {
+ arg_ts = arg_temp(op->args[0]);
dir_ts = arg_ts->state_ptr;
- if (!dir_ts) {
- continue;
+ if (dir_ts) {
+ op->args[0] = temp_arg(dir_ts);
+ changes = true;
+
+ /* The output is now live and modified. */
+ arg_ts->state = 0;
+
+ if (NEED_SYNC_ARG(0)) {
+ TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
+ ? INDEX_op_st_i32
+ : INDEX_op_st_i64);
+ TCGOp *sop = tcg_op_insert_after(s, op, sopc);
+ TCGTemp *out_ts = dir_ts;
+
+ if (IS_DEAD_ARG(0)) {
+ out_ts = arg_temp(op->args[1]);
+ arg_ts->state = TS_DEAD;
+ tcg_op_remove(s, op);
+ } else {
+ arg_ts->state = TS_MEM;
+ }
+
+ sop->args[0] = temp_arg(out_ts);
+ sop->args[1] = temp_arg(arg_ts->mem_base);
+ sop->args[2] = arg_ts->mem_offset;
+ } else {
+ tcg_debug_assert(!IS_DEAD_ARG(0));
+ }
}
- op->args[i] = temp_arg(dir_ts);
- changes = true;
+ } else {
+ for (i = 0; i < nb_oargs; i++) {
+ arg_ts = arg_temp(op->args[i]);
+ dir_ts = arg_ts->state_ptr;
+ if (!dir_ts) {
+ continue;
+ }
+ op->args[i] = temp_arg(dir_ts);
+ changes = true;
- /* The output is now live and modified. */
- arg_ts->state = 0;
+ /* The output is now live and modified. */
+ arg_ts->state = 0;
- /* Sync outputs upon their last write. */
- if (NEED_SYNC_ARG(i)) {
- TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
- ? INDEX_op_st_i32
- : INDEX_op_st_i64);
- TCGOp *sop = tcg_op_insert_after(s, op, sopc);
+ /* Sync outputs upon their last write. */
+ if (NEED_SYNC_ARG(i)) {
+ TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
+ ? INDEX_op_st_i32
+ : INDEX_op_st_i64);
+ TCGOp *sop = tcg_op_insert_after(s, op, sopc);
- sop->args[0] = temp_arg(dir_ts);
- sop->args[1] = temp_arg(arg_ts->mem_base);
- sop->args[2] = arg_ts->mem_offset;
+ sop->args[0] = temp_arg(dir_ts);
+ sop->args[1] = temp_arg(arg_ts->mem_base);
+ sop->args[2] = arg_ts->mem_offset;
- arg_ts->state = TS_MEM;
- }
- /* Drop outputs that are dead. */
- if (IS_DEAD_ARG(i)) {
- arg_ts->state = TS_DEAD;
+ arg_ts->state = TS_MEM;
+ }
+ /* Drop outputs that are dead. */
+ if (IS_DEAD_ARG(i)) {
+ arg_ts->state = TS_DEAD;
+ }
}
}
}
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 0cb58aad26..c2397de8ed 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -4,7 +4,7 @@
check-help:
@echo "Regression testing targets:"
@echo
- @echo " $(MAKE) check Run unit, qapi-schema, qtest and decodetree"
+ @echo " $(MAKE) check Run block, qapi-schema, unit, softfloat, qtest and decodetree tests"
@echo
@echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target"
@echo " $(MAKE) check-qtest Run qtest tests"
@@ -689,11 +689,26 @@ test-softfloat = $(call quiet-command, \
(cat $2.out && exit 1;), \
"FLOAT TEST", $2)
-# Conversion Routines:
+# Conversion Routines: Float to Float
+# FIXME: f32_to_f128 (broken), f64_to_f128 (broken)
+# FIXME: f128_to_f32(broken), f128_to_f64 (broken)
+# FIXME: f128_to_extF80 (broken)
+check-softfloat-conv-f2f: $(FP_TEST_BIN)
+ $(call test-softfloat, \
+ f16_to_f32 f16_to_f64 \
+ f16_to_extF80 f16_to_f128 \
+ f32_to_f16 f32_to_f64 \
+ f32_to_extF80 \
+ f64_to_f16 f64_to_f32 \
+ extF80_to_f16 extF80_to_f32 \
+ extF80_to_f64 extF80_to_f128 \
+ f128_to_f16, \
+ float-to-float)
+
+# Conversion Routines: Int and Uint to Float
# FIXME: i32_to_extF80 (broken), i64_to_extF80 (broken)
-# ui32_to_f128 (not implemented), extF80_roundToInt (broken)
-#
-check-softfloat-conv: $(FP_TEST_BIN)
+# ui32_to_f128 (not implemented)
+check-softfloat-conv-to-float: $(FP_TEST_BIN)
$(call test-softfloat, \
i32_to_f16 i64_to_f16 \
i32_to_f32 i64_to_f32 \
@@ -703,7 +718,12 @@ check-softfloat-conv: $(FP_TEST_BIN)
ui32_to_f16 ui64_to_f16 \
ui32_to_f32 ui64_to_f32 \
ui32_to_f64 ui64_to_f64 \
+ ui32_to_extF80 ui64_to_extF80 \
ui64_to_f128, uint-to-float)
+
+# Conversion Routines: Float to integers
+# FIXME: extF80_roundToInt (broken)
+check-softfloat-conv-to-int: $(FP_TEST_BIN)
$(call test-softfloat, \
f16_to_i32 f16_to_i32_r_minMag \
f32_to_i32 f32_to_i32_r_minMag \
@@ -720,10 +740,12 @@ check-softfloat-conv: $(FP_TEST_BIN)
f16_to_ui32 f16_to_ui32_r_minMag \
f32_to_ui32 f32_to_ui32_r_minMag \
f64_to_ui32 f64_to_ui32_r_minMag \
+ extF80_to_ui32 extF80_to_ui32_r_minMag \
f128_to_ui32 f128_to_ui32_r_minMag \
f16_to_ui64 f16_to_ui64_r_minMag \
f32_to_ui64 f32_to_ui64_r_minMag \
f64_to_ui64 f64_to_ui64_r_minMag \
+ extF80_to_ui64 extF80_to_ui64_r_minMag \
f128_to_ui64 f128_to_ui64_r_minMag, \
float-to-uint)
$(call test-softfloat, \
@@ -731,9 +753,14 @@ check-softfloat-conv: $(FP_TEST_BIN)
f64_roundToInt f128_roundToInt, \
round-to-integer)
+.PHONY: check-softfloat-conv
+check-softfloat-conv: check-softfloat-conv-f2f
+check-softfloat-conv: check-softfloat-conv-to-float
+check-softfloat-conv: check-softfloat-conv-to-int
+
# Generic rule for all float operations
#
-# Some patterns are overidden due to broken or missing tests.
+# Some patterns are overridden due to broken or missing tests.
# Hopefully these can be removed over time.
check-softfloat-%: $(FP_TEST_BIN)
@@ -743,13 +770,6 @@ check-softfloat-%: $(FP_TEST_BIN)
SF_COMPARE_OPS=eq eq_signaling le le_quiet lt_quiet
SF_COMPARE_RULES=$(patsubst %,check-softfloat-%, $(SF_COMPARE_OPS))
-# FIXME: extF80_le_quiet (broken)
-check-softfloat-le_quiet: $(FP_TEST_BIN)
- $(call test-softfloat, \
- f16_le_quiet f32_le_quiet f64_le_quiet \
- f128_le_quiet, \
- le_quiet)
-
# FIXME: extF80_lt_quiet (broken)
check-softfloat-lt_quiet: $(FP_TEST_BIN)
$(call test-softfloat, \
diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py
index 59e7b4f763..77d1c1d9ff 100644
--- a/tests/acceptance/avocado_qemu/__init__.py
+++ b/tests/acceptance/avocado_qemu/__init__.py
@@ -69,13 +69,15 @@ def pick_default_qemu_bin(arch=None):
def _console_interaction(test, success_message, failure_message,
- send_string, keep_sending=False):
+ send_string, keep_sending=False, vm=None):
assert not keep_sending or send_string
- console = test.vm.console_socket.makefile()
+ if vm is None:
+ vm = test.vm
+ console = vm.console_socket.makefile()
console_logger = logging.getLogger('console')
while True:
if send_string:
- test.vm.console_socket.sendall(send_string.encode())
+ vm.console_socket.sendall(send_string.encode())
if not keep_sending:
send_string = None # send only once
msg = console.readline().strip()
@@ -115,7 +117,8 @@ def interrupt_interactive_console_until_pattern(test, success_message,
_console_interaction(test, success_message, failure_message,
interrupt_string, True)
-def wait_for_console_pattern(test, success_message, failure_message=None):
+def wait_for_console_pattern(test, success_message, failure_message=None,
+ vm=None):
"""
Waits for messages to appear on the console, while logging the content
@@ -125,7 +128,7 @@ def wait_for_console_pattern(test, success_message, failure_message=None):
:param success_message: if this message appears, test succeeds
:param failure_message: if this message appears, test fails
"""
- _console_interaction(test, success_message, failure_message, None)
+ _console_interaction(test, success_message, failure_message, None, vm=vm)
def exec_command_and_wait_for_pattern(test, command,
success_message, failure_message=None):
diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py
index 075a386300..3aa57e88b0 100644
--- a/tests/acceptance/boot_linux.py
+++ b/tests/acceptance/boot_linux.py
@@ -26,22 +26,8 @@ KVM_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "KVM"
TCG_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "TCG"
-class BootLinux(Test):
- """
- Boots a Linux system, checking for a successful initialization
- """
-
- timeout = 900
- chksum = None
-
- def setUp(self):
- super(BootLinux, self).setUp()
- self.vm.add_args('-smp', '2')
- self.vm.add_args('-m', '1024')
- self.prepare_boot()
- self.prepare_cloudinit()
-
- def prepare_boot(self):
+class BootLinuxBase(Test):
+ def download_boot(self):
self.log.debug('Looking for and selecting a qemu-img binary to be '
'used to create the bootable snapshot image')
# If qemu-img has been built, use it, otherwise the system wide one
@@ -60,17 +46,17 @@ class BootLinux(Test):
if image_arch == 'ppc64':
image_arch = 'ppc64le'
try:
- self.boot = vmimage.get(
+ boot = vmimage.get(
'fedora', arch=image_arch, version='31',
checksum=self.chksum,
algorithm='sha256',
cache_dir=self.cache_dirs[0],
snapshot_dir=self.workdir)
- self.vm.add_args('-drive', 'file=%s' % self.boot.path)
except:
self.cancel('Failed to download/prepare boot image')
+ return boot.path
- def prepare_cloudinit(self):
+ def download_cloudinit(self):
self.log.info('Preparing cloudinit image')
try:
cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
@@ -81,9 +67,32 @@ class BootLinux(Test):
# QEMU's hard coded usermode router address
phone_home_host='10.0.2.2',
phone_home_port=self.phone_home_port)
- self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
except Exception:
self.cancel('Failed to prepared cloudinit image')
+ return cloudinit_iso
+
+class BootLinux(BootLinuxBase):
+ """
+ Boots a Linux system, checking for a successful initialization
+ """
+
+ timeout = 900
+ chksum = None
+
+ def setUp(self):
+ super(BootLinux, self).setUp()
+ self.vm.add_args('-smp', '2')
+ self.vm.add_args('-m', '1024')
+ self.prepare_boot()
+ self.prepare_cloudinit()
+
+ def prepare_boot(self):
+ path = self.download_boot()
+ self.vm.add_args('-drive', 'file=%s' % path)
+
+ def prepare_cloudinit(self):
+ cloudinit_iso = self.download_cloudinit()
+ self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
def launch_and_wait(self):
self.vm.set_console()
diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py
index c6b06a1a13..3f3aa0c854 100644
--- a/tests/acceptance/boot_linux_console.py
+++ b/tests/acceptance/boot_linux_console.py
@@ -28,19 +28,13 @@ try:
except CmdNotFoundError:
P7ZIP_AVAILABLE = False
-class BootLinuxConsole(Test):
- """
- Boots a Linux kernel and checks that the console is operational and the
- kernel command line is properly passed from QEMU to the kernel
- """
-
- timeout = 90
-
+class LinuxKernelTest(Test):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
- def wait_for_console_pattern(self, success_message):
+ def wait_for_console_pattern(self, success_message, vm=None):
wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing')
+ failure_message='Kernel panic - not syncing',
+ vm=vm)
def extract_from_deb(self, deb, path):
"""
@@ -79,6 +73,13 @@ class BootLinuxConsole(Test):
os.chdir(cwd)
return os.path.normpath(os.path.join(self.workdir, path))
+class BootLinuxConsole(LinuxKernelTest):
+ """
+ Boots a Linux kernel and checks that the console is operational and the
+ kernel command line is properly passed from QEMU to the kernel
+ """
+ timeout = 90
+
def test_x86_64_pc(self):
"""
:avocado: tags=arch:x86_64
@@ -307,6 +308,32 @@ class BootLinuxConsole(Test):
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.wait_for_console_pattern(console_pattern)
+ def test_aarch64_xlnx_versal_virt(self):
+ """
+ :avocado: tags=arch:aarch64
+ :avocado: tags=machine:xlnx-versal-virt
+ :avocado: tags=device:pl011
+ :avocado: tags=device:arm_gicv3
+ """
+ kernel_url = ('http://ports.ubuntu.com/ubuntu-ports/dists/'
+ 'bionic-updates/main/installer-arm64/current/images/'
+ 'netboot/ubuntu-installer/arm64/linux')
+ kernel_hash = '5bfc54cf7ed8157d93f6e5b0241e727b6dc22c50'
+ kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+
+ initrd_url = ('http://ports.ubuntu.com/ubuntu-ports/dists/'
+ 'bionic-updates/main/installer-arm64/current/images/'
+ 'netboot/ubuntu-installer/arm64/initrd.gz')
+ initrd_hash = 'd385d3e88d53e2004c5d43cbe668b458a094f772'
+ initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
+
+ self.vm.set_console()
+ self.vm.add_args('-m', '2G',
+ '-kernel', kernel_path,
+ '-initrd', initrd_path)
+ self.vm.launch()
+ self.wait_for_console_pattern('Checked W+X mappings: passed')
+
def test_arm_virt(self):
"""
:avocado: tags=arch:arm
@@ -378,13 +405,18 @@ class BootLinuxConsole(Test):
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- serial_kernel_cmdline[uart_id])
+ serial_kernel_cmdline[uart_id] +
+ ' root=/dev/mmcblk0p2 rootwait ' +
+ 'dwc_otg.fiq_fsm_enable=0')
self.vm.add_args('-kernel', kernel_path,
'-dtb', dtb_path,
- '-append', kernel_command_line)
+ '-append', kernel_command_line,
+ '-device', 'usb-kbd')
self.vm.launch()
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.wait_for_console_pattern(console_pattern)
+ console_pattern = 'Product: QEMU USB Keyboard'
+ self.wait_for_console_pattern(console_pattern)
def test_arm_raspi2_uart0(self):
"""
diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py
index 0365289cda..792639cb69 100644
--- a/tests/acceptance/migration.py
+++ b/tests/acceptance/migration.py
@@ -35,6 +35,10 @@ class Migration(Test):
timeout=self.timeout,
step=0.1,
args=(src_vm,))
+ wait.wait_for(self.migration_finished,
+ timeout=self.timeout,
+ step=0.1,
+ args=(dst_vm,))
self.assertEqual(src_vm.command('query-migrate')['status'], 'completed')
self.assertEqual(dst_vm.command('query-migrate')['status'], 'completed')
self.assertEqual(dst_vm.command('query-status')['status'], 'running')
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index 43a8678688..ed46bd98eb 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -7,7 +7,7 @@ HOST_ARCH = $(if $(ARCH),$(ARCH),$(shell uname -m))
DOCKER_SUFFIX := .docker
DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles
# we don't run tests on intermediate images (used as base by another image)
-DOCKER_PARTIAL_IMAGES := debian9 debian10
+DOCKER_PARTIAL_IMAGES := debian9 debian10 debian11
DOCKER_PARTIAL_IMAGES += debian9-mxe debian-bootstrap
DOCKER_IMAGES := $(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker))))
DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES))
@@ -131,9 +131,11 @@ docker-image-travis: NOUSER=1
# Specialist build images, sometimes very limited tools
docker-image-tricore-cross: docker-image-debian9
+docker-image-debian-arm64-test-cross: docker-image-debian11
# These images may be good enough for building tests but not for test builds
DOCKER_PARTIAL_IMAGES += debian-alpha-cross
+DOCKER_PARTIAL_IMAGES += debian-arm64-test-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
diff --git a/tests/docker/docker.py b/tests/docker/docker.py
index d8268c1111..5a9735db78 100755
--- a/tests/docker/docker.py
+++ b/tests/docker/docker.py
@@ -258,12 +258,13 @@ class Docker(object):
return self._do_kill_instances(True)
def _output(self, cmd, **kwargs):
- if sys.version_info[1] >= 6:
+ try:
return subprocess.check_output(self._command + cmd,
stderr=subprocess.STDOUT,
encoding='utf-8',
**kwargs)
- else:
+ except TypeError:
+ # 'encoding' argument was added in 3.6+
return subprocess.check_output(self._command + cmd,
stderr=subprocess.STDOUT,
**kwargs).decode('utf-8')
diff --git a/tests/docker/dockerfiles/debian-arm64-test-cross.docker b/tests/docker/dockerfiles/debian-arm64-test-cross.docker
new file mode 100644
index 0000000000..a44e76d942
--- /dev/null
+++ b/tests/docker/dockerfiles/debian-arm64-test-cross.docker
@@ -0,0 +1,13 @@
+#
+# Docker arm64 cross-compiler target (tests only)
+#
+# This docker target builds on the debian Bullseye base image.
+#
+FROM qemu:debian11
+
+# Add the foreign architecture we want and install dependencies
+RUN dpkg --add-architecture arm64
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt install -y --no-install-recommends \
+ crossbuild-essential-arm64 gcc-10-aarch64-linux-gnu
diff --git a/tests/docker/dockerfiles/debian11.docker b/tests/docker/dockerfiles/debian11.docker
new file mode 100644
index 0000000000..5adfd62d55
--- /dev/null
+++ b/tests/docker/dockerfiles/debian11.docker
@@ -0,0 +1,18 @@
+#
+# Docker multiarch cross-compiler target
+#
+# This docker target uses the current development version of Debian as
+# a base for cross compilers for building test binaries. We won't
+# attempt to build QEMU on it yet given it is still in development.
+#
+# On its own you can't build much but the docker-foo-cross targets
+# build on top of the base debian image.
+#
+FROM debian:bullseye-slim
+
+# Duplicate deb line as deb-src
+RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list
+
+# Install common build utilities
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata
diff --git a/tests/migration/guestperf-batch.py b/tests/migration/guestperf-batch.py
index cb150ce804..f1e900908d 100755
--- a/tests/migration/guestperf-batch.py
+++ b/tests/migration/guestperf-batch.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# Migration test batch comparison invokation
#
diff --git a/tests/migration/guestperf-plot.py b/tests/migration/guestperf-plot.py
index d70bb7a557..907151011a 100755
--- a/tests/migration/guestperf-plot.py
+++ b/tests/migration/guestperf-plot.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# Migration test graph plotting command
#
diff --git a/tests/migration/guestperf.py b/tests/migration/guestperf.py
index 99b027e8ba..ba1c4bc4ca 100755
--- a/tests/migration/guestperf.py
+++ b/tests/migration/guestperf.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# Migration test direct invokation command
#
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
index f59bf4b2fb..c7997760fd 100644
--- a/tests/qemu-iotests/178.out.qcow2
+++ b/tests/qemu-iotests/178.out.qcow2
@@ -13,7 +13,7 @@ qemu-img: Invalid option list: ,
qemu-img: Invalid parameter 'snapshot.foo'
qemu-img: Failed in parsing snapshot param 'snapshot.foo'
qemu-img: --output must be used with human or json as argument.
-qemu-img: Image size must be less than 8 EiB!
+qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807.
qemu-img: Unknown file format 'foo'
== Size calculation for a new file (human) ==
@@ -37,6 +37,7 @@ qemu-img: The image size is too large (try using a larger cluster size)
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
required size: 196608
fully allocated size: 196608
+bitmaps size: 0
converted image file size in bytes: 196608
@@ -45,6 +46,7 @@ converted image file size in bytes: 196608
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
required size: 393216
fully allocated size: 1074135040
+bitmaps size: 0
wrote 512/512 bytes at offset 512
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset 65536
@@ -53,6 +55,7 @@ wrote 64512/64512 bytes at offset 134217728
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
required size: 589824
fully allocated size: 1074135040
+bitmaps size: 0
converted image file size in bytes: 524288
@@ -60,6 +63,7 @@ converted image file size in bytes: 524288
required size: 524288
fully allocated size: 1074135040
+bitmaps size: 0
converted image file size in bytes: 458752
@@ -67,16 +71,19 @@ converted image file size in bytes: 458752
required size: 1074135040
fully allocated size: 1074135040
+bitmaps size: 0
== qcow2 input image and LUKS encryption ==
required size: 2686976
fully allocated size: 1076232192
+bitmaps size: 0
== qcow2 input image and preallocation (human) ==
required size: 1074135040
fully allocated size: 1074135040
+bitmaps size: 0
converted image file size in bytes: 1074135040
@@ -87,6 +94,7 @@ wrote 8388608/8388608 bytes at offset 0
8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
required size: 8716288
fully allocated size: 8716288
+bitmaps size: 0
converted image file size in bytes: 8716288
@@ -173,6 +181,7 @@ qemu-img: The image size is too large (try using a larger cluster size)
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
{
+ "bitmaps": 0,
"required": 196608,
"fully-allocated": 196608
}
@@ -183,6 +192,7 @@ converted image file size in bytes: 196608
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
{
+ "bitmaps": 0,
"required": 393216,
"fully-allocated": 1074135040
}
@@ -193,6 +203,7 @@ wrote 65536/65536 bytes at offset 65536
wrote 64512/64512 bytes at offset 134217728
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{
+ "bitmaps": 0,
"required": 589824,
"fully-allocated": 1074135040
}
@@ -202,6 +213,7 @@ converted image file size in bytes: 524288
== qcow2 input image with internal snapshot (json) ==
{
+ "bitmaps": 0,
"required": 524288,
"fully-allocated": 1074135040
}
@@ -211,6 +223,7 @@ converted image file size in bytes: 458752
== qcow2 input image and a backing file (json) ==
{
+ "bitmaps": 0,
"required": 1074135040,
"fully-allocated": 1074135040
}
@@ -218,6 +231,7 @@ converted image file size in bytes: 458752
== qcow2 input image and LUKS encryption ==
{
+ "bitmaps": 0,
"required": 2686976,
"fully-allocated": 1076232192
}
@@ -225,6 +239,7 @@ converted image file size in bytes: 458752
== qcow2 input image and preallocation (json) ==
{
+ "bitmaps": 0,
"required": 1074135040,
"fully-allocated": 1074135040
}
@@ -237,6 +252,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608
wrote 8388608/8388608 bytes at offset 0
8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{
+ "bitmaps": 0,
"required": 8716288,
"fully-allocated": 8716288
}
diff --git a/tests/qemu-iotests/178.out.raw b/tests/qemu-iotests/178.out.raw
index 404ca908d8..20e17da115 100644
--- a/tests/qemu-iotests/178.out.raw
+++ b/tests/qemu-iotests/178.out.raw
@@ -13,7 +13,7 @@ qemu-img: Invalid option list: ,
qemu-img: Invalid parameter 'snapshot.foo'
qemu-img: Failed in parsing snapshot param 'snapshot.foo'
qemu-img: --output must be used with human or json as argument.
-qemu-img: Image size must be less than 8 EiB!
+qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807.
qemu-img: Unknown file format 'foo'
== Size calculation for a new file (human) ==
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
index 6d41650438..fe630918e9 100755
--- a/tests/qemu-iotests/190
+++ b/tests/qemu-iotests/190
@@ -2,7 +2,7 @@
#
# qemu-img measure sub-command tests on huge qcow2 files
#
-# Copyright (C) 2017 Red Hat, Inc.
+# Copyright (C) 2017-2020 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
-echo "== Huge file =="
+echo "== Huge file without bitmaps =="
echo
_make_test_img -o 'cluster_size=2M' 2T
@@ -51,6 +51,49 @@ $QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG"
$QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG"
$QEMU_IMG measure -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG"
+echo
+echo "== Huge file with bitmaps =="
+echo
+
+$QEMU_IMG bitmap --add --granularity 512 -f qcow2 "$TEST_IMG" b1
+$QEMU_IMG bitmap --add -g 2M -f qcow2 "$TEST_IMG" b2
+
+# No bitmap without a source
+$QEMU_IMG measure -O qcow2 --size 10M
+# No bitmap output, since raw does not support it
+$QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG"
+# No bitmap output, since no bitmaps on raw source. Munge required size, as
+# some filesystems store the qcow2 file with less sparseness than others
+$QEMU_IMG measure -O qcow2 -f raw "$TEST_IMG" |
+ sed '/^required size:/ s/[0-9][0-9]*/SIZE/'
+# No bitmap output, since v2 does not support it
+$QEMU_IMG measure -O qcow2 -o compat=0.10 -f qcow2 "$TEST_IMG"
+
+# Compute expected output: bitmap clusters + bitmap tables + bitmaps directory
+echo
+val2T=$((2*1024*1024*1024*1024))
+cluster=$((64*1024))
+b1clusters=$(( (val2T/512/8 + cluster - 1) / cluster ))
+b2clusters=$(( (val2T/2/1024/1024/8 + cluster - 1) / cluster ))
+echo expected bitmap $((b1clusters * cluster +
+ (b1clusters * 8 + cluster - 1) / cluster * cluster +
+ b2clusters * cluster +
+ (b2clusters * 8 + cluster - 1) / cluster * cluster +
+ cluster))
+$QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG"
+
+# Compute expected output: bitmap clusters + bitmap tables + bitmaps directory
+echo
+cluster=$((2*1024*1024))
+b1clusters=$(( (val2T/512/8 + cluster - 1) / cluster ))
+b2clusters=$(( (val2T/2/1024/1024/8 + cluster - 1) / cluster ))
+echo expected bitmap $((b1clusters * cluster +
+ (b1clusters * 8 + cluster - 1) / cluster * cluster +
+ b2clusters * cluster +
+ (b2clusters * 8 + cluster - 1) / cluster * cluster +
+ cluster))
+$QEMU_IMG measure --output=json -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG"
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/190.out b/tests/qemu-iotests/190.out
index d001942002..ed9d8214eb 100644
--- a/tests/qemu-iotests/190.out
+++ b/tests/qemu-iotests/190.out
@@ -1,11 +1,36 @@
QA output created by 190
-== Huge file ==
+== Huge file without bitmaps ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2199023255552
required size: 2199023255552
fully allocated size: 2199023255552
required size: 335806464
fully allocated size: 2199359062016
+bitmaps size: 0
required size: 18874368
fully allocated size: 2199042129920
+bitmaps size: 0
+
+== Huge file with bitmaps ==
+
+required size: 327680
+fully allocated size: 10813440
+required size: 2199023255552
+fully allocated size: 2199023255552
+required size: SIZE
+fully allocated size: 17170432
+required size: 335806464
+fully allocated size: 2199359062016
+
+expected bitmap 537198592
+required size: 335806464
+fully allocated size: 2199359062016
+bitmaps size: 537198592
+
+expected bitmap 545259520
+{
+ "bitmaps": 545259520,
+ "required": 18874368,
+ "fully-allocated": 2199042129920
+}
*** done
diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194
index 8b1f720af4..3fad7c6c1a 100755
--- a/tests/qemu-iotests/194
+++ b/tests/qemu-iotests/194
@@ -42,6 +42,8 @@ with iotests.FilePath('source.img') as source_img_path, \
.add_incoming('unix:{0}'.format(migration_sock_path))
.launch())
+ source_vm.qmp_log('block-dirty-bitmap-add', node='drive0', name='bitmap0')
+
iotests.log('Launching NBD server on destination...')
iotests.log(dest_vm.qmp('nbd-server-start', addr={'type': 'unix', 'data': {'path': nbd_sock_path}}))
iotests.log(dest_vm.qmp('nbd-server-add', device='drive0', writable=True))
@@ -61,12 +63,14 @@ with iotests.FilePath('source.img') as source_img_path, \
filters=[iotests.filter_qmp_event])
iotests.log('Starting migration...')
- source_vm.qmp('migrate-set-capabilities',
- capabilities=[{'capability': 'events', 'state': True}])
- dest_vm.qmp('migrate-set-capabilities',
- capabilities=[{'capability': 'events', 'state': True}])
+ capabilities = [{'capability': 'events', 'state': True},
+ {'capability': 'dirty-bitmaps', 'state': True}]
+ source_vm.qmp('migrate-set-capabilities', capabilities=capabilities)
+ dest_vm.qmp('migrate-set-capabilities', capabilities=capabilities)
iotests.log(source_vm.qmp('migrate', uri='unix:{0}'.format(migration_sock_path)))
+ source_vm.qmp_log('migrate-start-postcopy')
+
while True:
event1 = source_vm.event_wait('MIGRATION')
iotests.log(event1, filters=[iotests.filter_qmp_event])
@@ -82,3 +86,5 @@ with iotests.FilePath('source.img') as source_img_path, \
iotests.log('Stopping the NBD server on destination...')
iotests.log(dest_vm.qmp('nbd-server-stop'))
break
+
+ iotests.log(source_vm.qmp('query-block')['return'][0]['dirty-bitmaps'])
diff --git a/tests/qemu-iotests/194.out b/tests/qemu-iotests/194.out
index 71857853fb..dd60dcc14f 100644
--- a/tests/qemu-iotests/194.out
+++ b/tests/qemu-iotests/194.out
@@ -1,4 +1,6 @@
Launching VMs...
+{"execute": "block-dirty-bitmap-add", "arguments": {"name": "bitmap0", "node": "drive0"}}
+{"return": {}}
Launching NBD server on destination...
{"return": {}}
{"return": {}}
@@ -8,11 +10,15 @@ Waiting for `drive-mirror` to complete...
{"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
Starting migration...
{"return": {}}
+{"execute": "migrate-start-postcopy", "arguments": {}}
+{"return": {}}
{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"status": "postcopy-active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
Gracefully ending the `drive-mirror` job on source...
{"return": {}}
{"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
Stopping the NBD server on destination...
{"return": {}}
+[{"busy": false, "count": 0, "granularity": 65536, "name": "bitmap0", "persistent": false, "recording": true, "status": "active"}]
diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291
new file mode 100755
index 0000000000..3ca83b9cd1
--- /dev/null
+++ b/tests/qemu-iotests/291
@@ -0,0 +1,112 @@
+#!/usr/bin/env bash
+#
+# Test qemu-img bitmap handling
+#
+# Copyright (C) 2018-2020 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+ nbd_server_stop
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.nbd
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+_require_command QEMU_NBD
+
+echo
+echo "=== Initial image setup ==="
+echo
+
+# Create backing image with one bitmap
+TEST_IMG="$TEST_IMG.base" _make_test_img 10M
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG.base" b0
+$QEMU_IO -c 'w 3M 1M' -f $IMGFMT "$TEST_IMG.base" | _filter_qemu_io
+
+# Create initial image and populate two bitmaps: one active, one inactive.
+ORIG_IMG=$TEST_IMG
+TEST_IMG=$TEST_IMG.orig
+_make_test_img -b "$ORIG_IMG.base" -F $IMGFMT 10M
+$QEMU_IO -c 'w 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
+$QEMU_IMG bitmap --add -g 512k -f $IMGFMT "$TEST_IMG" b1
+$QEMU_IMG bitmap --add --disable -f $IMGFMT "$TEST_IMG" b2
+$QEMU_IO -c 'w 3M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
+$QEMU_IMG bitmap --clear -f $IMGFMT "$TEST_IMG" b1
+$QEMU_IO -c 'w 1M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
+$QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1
+$QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2
+$QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "=== Bitmap preservation not possible to non-qcow2 ==="
+echo
+
+TEST_IMG=$ORIG_IMG
+$QEMU_IMG convert --bitmaps -O raw "$TEST_IMG.orig" "$TEST_IMG" &&
+ echo "unexpected success"
+
+echo
+echo "=== Convert with bitmap preservation ==="
+echo
+
+# Only bitmaps from the active layer are copied
+$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG.orig" "$TEST_IMG"
+$QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific
+# But we can also merge in bitmaps from other layers. This test is a bit
+# contrived to cover more code paths, in reality, you could merge directly
+# into b0 without going through tmp
+$QEMU_IMG bitmap --add --disable -f $IMGFMT "$TEST_IMG" b0
+$QEMU_IMG bitmap --add --merge b0 -b "$TEST_IMG.base" -F $IMGFMT \
+ -f $IMGFMT "$TEST_IMG" tmp
+$QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0
+$QEMU_IMG bitmap --remove --image-opts \
+ driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp
+$QEMU_IMG info "$TEST_IMG" | _filter_img_info --format-specific
+
+echo
+echo "=== Check bitmap contents ==="
+echo
+
+# x-dirty-bitmap is a hack for reading bitmaps; it abuses block status to
+# report "data":false for portions of the bitmap which are set
+IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket"
+nbd_server_start_unix_socket -r -f qcow2 -B b0 "$TEST_IMG"
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b0" | _filter_qemu_img_map
+nbd_server_start_unix_socket -r -f qcow2 -B b1 "$TEST_IMG"
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b1" | _filter_qemu_img_map
+nbd_server_start_unix_socket -r -f qcow2 -B b2 "$TEST_IMG"
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out
new file mode 100644
index 0000000000..8c62017567
--- /dev/null
+++ b/tests/qemu-iotests/291.out
@@ -0,0 +1,80 @@
+QA output created by 291
+
+=== Initial image setup ===
+
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=10485760
+wrote 1048576/1048576 bytes at offset 3145728
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=10485760 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1048576/1048576 bytes at offset 3145728
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1048576/1048576 bytes at offset 1048576
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1048576/1048576 bytes at offset 2097152
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Bitmap preservation not possible to non-qcow2 ===
+
+qemu-img: Format driver 'raw' does not support bitmaps
+
+=== Convert with bitmap preservation ===
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 10 MiB (10485760 bytes)
+disk size: 4.39 MiB
+Format specific information:
+ compat: 1.1
+ compression type: zlib
+ lazy refcounts: false
+ bitmaps:
+ [0]:
+ flags:
+ name: b1
+ granularity: 524288
+ [1]:
+ flags:
+ [0]: auto
+ name: b2
+ granularity: 65536
+ refcount bits: 16
+ corrupt: false
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 10 MiB (10485760 bytes)
+disk size: 4.48 MiB
+Format specific information:
+ compat: 1.1
+ compression type: zlib
+ lazy refcounts: false
+ bitmaps:
+ [0]:
+ flags:
+ name: b1
+ granularity: 524288
+ [1]:
+ flags:
+ [0]: auto
+ name: b2
+ granularity: 65536
+ [2]:
+ flags:
+ name: b0
+ granularity: 65536
+ refcount bits: 16
+ corrupt: false
+
+=== Check bitmap contents ===
+
+[{ "start": 0, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 3145728, "length": 1048576, "depth": 0, "zero": false, "data": false},
+{ "start": 4194304, "length": 6291456, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": false},
+{ "start": 2097152, "length": 8388608, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 2097152, "length": 1048576, "depth": 0, "zero": false, "data": false},
+{ "start": 3145728, "length": 7340032, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 445c26f8d2..d886fa0cb3 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -299,5 +299,6 @@
288 quick
289 rw quick
290 rw auto quick
+291 rw quick
292 rw auto quick
297 meta
diff --git a/tests/qemu-iotests/nbd-fault-injector.py b/tests/qemu-iotests/nbd-fault-injector.py
index 588d62aebf..78f42c4214 100755
--- a/tests/qemu-iotests/nbd-fault-injector.py
+++ b/tests/qemu-iotests/nbd-fault-injector.py
@@ -47,10 +47,7 @@ import sys
import socket
import struct
import collections
-if sys.version_info.major >= 3:
- import configparser
-else:
- import ConfigParser as configparser
+import configparser
FAKE_DISK_SIZE = 8 * 1024 * 1024 * 1024 # 8 GB
diff --git a/tests/qtest/endianness-test.c b/tests/qtest/endianness-test.c
index 2798802c63..cc088ac01a 100644
--- a/tests/qtest/endianness-test.c
+++ b/tests/qtest/endianness-test.c
@@ -33,7 +33,7 @@ static const TestCase test_cases[] = {
{ "mips64", "pica61", 0x90000000, .bswap = true },
{ "mips64", "mips", 0x14000000, .bswap = true },
{ "mips64", "malta", 0x10000000, .bswap = true },
- { "mips64el", "fulong2e", 0x1fd00000 },
+ { "mips64el", "fuloong2e", 0x1fd00000 },
{ "ppc", "g3beige", 0xfe000000, .bswap = true, .superio = "i82378" },
{ "ppc", "40p", 0x80000000, .bswap = true },
{ "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" },
diff --git a/tests/qtest/fuzz/fork_fuzz.ld b/tests/qtest/fuzz/fork_fuzz.ld
index e086bba873..bfb667ed06 100644
--- a/tests/qtest/fuzz/fork_fuzz.ld
+++ b/tests/qtest/fuzz/fork_fuzz.ld
@@ -28,6 +28,11 @@ SECTIONS
/* Internal Libfuzzer TracePC object which contains the ValueProfileMap */
FuzzerTracePC*(.bss*);
+ /*
+ * In case the above line fails, explicitly specify the (mangled) name of
+ * the object we care about
+ */
+ *(.bss._ZN6fuzzer3TPCE);
}
.data.fuzz_end : ALIGN(4K)
{
diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c
index f5c923852e..33365c3782 100644
--- a/tests/qtest/fuzz/fuzz.c
+++ b/tests/qtest/fuzz/fuzz.c
@@ -137,6 +137,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
{
char *target_name;
+ char *dir;
/* Initialize qgraph and modules */
qos_graph_init();
@@ -147,6 +148,20 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
target_name = strstr(**argv, "-target-");
if (target_name) { /* The binary name specifies the target */
target_name += strlen("-target-");
+ /*
+ * With oss-fuzz, the executable is kept in the root of a directory (we
+ * cannot assume the path). All data (including bios binaries) must be
+ * in the same dir, or a subdir. Thus, we cannot place the pc-bios so
+ * that it would be in exec_dir/../pc-bios.
+ * As a workaround, oss-fuzz allows us to use argv[0] to get the
+ * location of the executable. Using this we add exec_dir/pc-bios to
+ * the datadirs.
+ */
+ dir = g_build_filename(g_path_get_dirname(**argv), "pc-bios", NULL);
+ if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
+ qemu_add_data_dir(dir);
+ }
+ g_free(dir);
} else if (*argc > 1) { /* The target is specified as an argument */
target_name = (*argv)[1];
if (!strstr(target_name, "--fuzz-target=")) {
diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c
index bcd6769b4c..e2f31e56f9 100644
--- a/tests/qtest/fuzz/i440fx_fuzz.c
+++ b/tests/qtest/fuzz/i440fx_fuzz.c
@@ -151,12 +151,13 @@ static void i440fx_fuzz_qos_fork(QTestState *s,
i440fx_fuzz_qos(s, Data, Size);
_Exit(0);
} else {
+ flush_events(s);
wait(NULL);
}
}
static const char *i440fx_qtest_argv = TARGET_NAME " -machine accel=qtest"
- "-m 0 -display none";
+ " -m 0 -display none";
static const char *i440fx_argv(FuzzTarget *t)
{
return i440fx_qtest_argv;
diff --git a/tests/qtest/fuzz/virtio_net_fuzz.c b/tests/qtest/fuzz/virtio_net_fuzz.c
index d08a47e278..a33bd73067 100644
--- a/tests/qtest/fuzz/virtio_net_fuzz.c
+++ b/tests/qtest/fuzz/virtio_net_fuzz.c
@@ -122,6 +122,7 @@ static void virtio_net_fork_fuzz(QTestState *s,
flush_events(s);
_Exit(0);
} else {
+ flush_events(s);
wait(NULL);
}
}
@@ -134,6 +135,7 @@ static void virtio_net_fork_fuzz_check_used(QTestState *s,
flush_events(s);
_Exit(0);
} else {
+ flush_events(s);
wait(NULL);
}
}
diff --git a/tests/qtest/fuzz/virtio_scsi_fuzz.c b/tests/qtest/fuzz/virtio_scsi_fuzz.c
index 3b95247f12..51dce491ab 100644
--- a/tests/qtest/fuzz/virtio_scsi_fuzz.c
+++ b/tests/qtest/fuzz/virtio_scsi_fuzz.c
@@ -145,6 +145,7 @@ static void virtio_scsi_fork_fuzz(QTestState *s,
flush_events(s);
_Exit(0);
} else {
+ flush_events(s);
wait(NULL);
}
}
@@ -164,6 +165,7 @@ static void virtio_scsi_with_flag_fuzz(QTestState *s,
}
_Exit(0);
} else {
+ flush_events(s);
wait(NULL);
}
}
diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c
index 8bb54a6360..10d8ec26a9 100644
--- a/tests/qtest/machine-none-test.c
+++ b/tests/qtest/machine-none-test.c
@@ -54,8 +54,8 @@ static struct arch2cpu cpus_map[] = {
{ "xtensa", "dc233c" },
{ "xtensaeb", "fsf" },
{ "hppa", "hppa" },
- { "riscv64", "rv64gcsu-v1.10.0" },
- { "riscv32", "rv32gcsu-v1.9.1" },
+ { "riscv64", "rv64" },
+ { "riscv32", "rv32" },
{ "rx", "rx62n" },
};
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 2568c9529c..dc3490c9fa 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "libqtest.h"
+#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qemu/module.h"
#include "qemu/option.h"
@@ -301,7 +302,6 @@ static char *migrate_get_socket_address(QTestState *who, const char *parameter)
{
QDict *rsp;
char *result;
- Error *local_err = NULL;
SocketAddressList *addrs;
Visitor *iv = NULL;
QObject *object;
@@ -310,7 +310,7 @@ static char *migrate_get_socket_address(QTestState *who, const char *parameter)
object = qdict_get(rsp, parameter);
iv = qobject_input_visitor_new(object);
- visit_type_SocketAddressList(iv, NULL, &addrs, &local_err);
+ visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort);
visit_free(iv);
/* we are only using a single address */
diff --git a/tests/qtest/test-hmp.c b/tests/qtest/test-hmp.c
index f8aa5f92c5..b8b1271b9e 100644
--- a/tests/qtest/test-hmp.c
+++ b/tests/qtest/test-hmp.c
@@ -61,6 +61,7 @@ static const char *hmp_cmds[] = {
"p $pc + 8",
"qom-list /",
"qom-set /machine initrd test",
+ "qom-get /machine initrd",
"screendump /dev/null",
"sendkey x",
"singlestep on",
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index 71f72cfbe3..1057a8ac49 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -61,7 +61,7 @@ run-memory-replay: memory-replay run-memory-record
$(QEMU_OPTS) memory, \
"$< on $(TARGET_NAME)")
-EXTRA_TESTS+=memory-record memory-replay
+EXTRA_RUNS+=run-memory-replay
ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_3),)
pauth-3: CFLAGS += -march=armv8.3-a
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
index eaaaff6233..2326f97856 100755
--- a/tests/tcg/configure.sh
+++ b/tests/tcg/configure.sh
@@ -97,8 +97,8 @@ for target in $target_list; do
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
+ container_image=debian-arm64-test-cross
+ container_cross_cc=aarch64-linux-gnu-gcc-10
;;
alpha-*)
container_image=debian-alpha-cross
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index 51fb75ecfd..cb49cc9ccb 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -28,6 +28,8 @@ run-float_%: float_%
testthread: LDFLAGS+=-lpthread
+threadcount: LDFLAGS+=-lpthread
+
# We define the runner for test-mmap after the individual
# architectures have defined their supported pages sizes. If no
# additional page sizes are defined we only run the default test.
diff --git a/tests/tcg/multiarch/gdbstub/sha1.py b/tests/tcg/multiarch/gdbstub/sha1.py
index 734553b98b..2bfde49633 100644
--- a/tests/tcg/multiarch/gdbstub/sha1.py
+++ b/tests/tcg/multiarch/gdbstub/sha1.py
@@ -65,6 +65,10 @@ except (gdb.error, AttributeError):
print("SKIPPING (not connected)", file=sys.stderr)
exit(0)
+if gdb.parse_and_eval('$pc') == 0:
+ print("SKIP: PC not set")
+ exit(0)
+
try:
# These are not very useful in scripts
gdb.execute("set pagination off")
diff --git a/tests/tcg/multiarch/threadcount.c b/tests/tcg/multiarch/threadcount.c
new file mode 100644
index 0000000000..545a1c8146
--- /dev/null
+++ b/tests/tcg/multiarch/threadcount.c
@@ -0,0 +1,64 @@
+/*
+ * Thread Exerciser
+ *
+ * Unlike testthread which is mainly concerned about testing thread
+ * semantics this test is used to exercise the thread creation and
+ * accounting. A version of this test found a problem with clashing
+ * cpu_indexes which caused a break in plugin handling.
+ *
+ * Based on the original test case by Nikolay Igotti.
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+
+int max_threads = 10;
+
+typedef struct {
+ int delay;
+} ThreadArg;
+
+static void *thread_fn(void* varg)
+{
+ ThreadArg *arg = varg;
+ usleep(arg->delay);
+ free(arg);
+ return NULL;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ pthread_t *threads;
+
+ if (argc > 1) {
+ max_threads = atoi(argv[1]);
+ }
+ threads = calloc(sizeof(pthread_t), max_threads);
+
+ for (i = 0; i < max_threads; i++) {
+ ThreadArg *arg = calloc(sizeof(ThreadArg), 1);
+ arg->delay = i * 100;
+ pthread_create(threads + i, NULL, thread_fn, arg);
+ }
+
+ printf("Created %d threads\n", max_threads);
+
+ /* sleep until roughly half the threads have "finished" */
+ usleep(max_threads * 50);
+
+ for (i = 0; i < max_threads; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ printf("Done\n");
+
+ return 0;
+}
diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include
index 1bf9693d19..a253aba457 100644
--- a/tests/vm/Makefile.include
+++ b/tests/vm/Makefile.include
@@ -41,6 +41,7 @@ endif
@echo " J=[0..9]* - Override the -jN parameter for make commands"
@echo " DEBUG=1 - Enable verbose output on host and interactive debugging"
@echo " V=1 - Enable verbose ouput on host and guest commands"
+ @echo " QEMU_LOCAL=1 - Use QEMU binary local to this build."
@echo " QEMU=/path/to/qemu - Change path to QEMU binary"
@echo " QEMU_IMG=/path/to/qemu-img - Change path to qemu-img tool"
@@ -56,6 +57,8 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \
$(call quiet-command, \
$(PYTHON) $< \
$(if $(V)$(DEBUG), --debug) \
+ $(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \
+ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
--image "$@" \
--force \
--build-image $@, \
@@ -70,6 +73,7 @@ vm-build-%: $(IMAGES_DIR)/%.img
$(if $(DEBUG), --interactive) \
$(if $(J),--jobs $(J)) \
$(if $(V),--verbose) \
+ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
--image "$<" \
$(if $(BUILD_TARGET),--build-target $(BUILD_TARGET)) \
--snapshot \
@@ -90,6 +94,8 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img
$(call quiet-command, \
$(PYTHON) $(SRC_PATH)/tests/vm/$* \
$(if $(J),--jobs $(J)) \
+ $(if $(V)$(DEBUG), --debug) \
+ $(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
--image "$<" \
--interactive \
false, \
diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
index 756ccf7aca..a80b616a08 100644
--- a/tests/vm/basevm.py
+++ b/tests/vm/basevm.py
@@ -61,8 +61,11 @@ class BaseVM(object):
# 4 is arbitrary, but greater than 2,
# since we found we need to wait more than twice as long.
tcg_ssh_timeout_multiplier = 4
- def __init__(self, debug=False, vcpus=None):
+ def __init__(self, debug=False, vcpus=None, genisoimage=None,
+ build_path=None):
self._guest = None
+ self._genisoimage = genisoimage
+ self._build_path = build_path
self._tmpdir = os.path.realpath(tempfile.mkdtemp(prefix="vm-test-",
suffix=".tmp",
dir="."))
@@ -183,15 +186,15 @@ class BaseVM(object):
"-device", "virtio-blk,drive=drive0,bootindex=0"]
args += self._data_args + extra_args
logging.debug("QEMU args: %s", " ".join(args))
- qemu_bin = os.environ.get("QEMU", "qemu-system-" + self.arch)
- guest = QEMUMachine(binary=qemu_bin, args=args)
+ qemu_path = get_qemu_path(self.arch, self._build_path)
+ guest = QEMUMachine(binary=qemu_path, args=args)
guest.set_machine('pc')
guest.set_console()
try:
guest.launch()
except:
logging.error("Failed to launch QEMU, command line:")
- logging.error(" ".join([qemu_bin] + args))
+ logging.error(" ".join([qemu_path] + args))
logging.error("Log:")
logging.error(guest.get_log())
logging.error("QEMU version >= 2.10 is required")
@@ -317,24 +320,24 @@ class BaseVM(object):
def print_step(self, text):
sys.stderr.write("### %s ...\n" % text)
- def wait_ssh(self, wait_root=False, seconds=300):
+ def wait_ssh(self, wait_root=False, seconds=300, cmd="exit 0"):
# Allow more time for VM to boot under TCG.
if not kvm_available(self.arch):
seconds *= self.tcg_ssh_timeout_multiplier
starttime = datetime.datetime.now()
endtime = starttime + datetime.timedelta(seconds=seconds)
- guest_up = False
+ cmd_success = False
while datetime.datetime.now() < endtime:
- if wait_root and self.ssh_root("exit 0") == 0:
- guest_up = True
+ if wait_root and self.ssh_root(cmd) == 0:
+ cmd_success = True
break
- elif self.ssh("exit 0") == 0:
- guest_up = True
+ elif self.ssh(cmd) == 0:
+ cmd_success = True
break
seconds = (endtime - datetime.datetime.now()).total_seconds()
logging.debug("%ds before timeout", seconds)
time.sleep(1)
- if not guest_up:
+ if not cmd_success:
raise Exception("Timeout while waiting for guest ssh")
def shutdown(self):
@@ -381,15 +384,28 @@ class BaseVM(object):
udata.writelines(["apt:\n",
" proxy: %s" % proxy])
udata.close()
- subprocess.check_call(["genisoimage", "-output", "cloud-init.iso",
+ subprocess.check_call([self._genisoimage, "-output", "cloud-init.iso",
"-volid", "cidata", "-joliet", "-rock",
"user-data", "meta-data"],
- cwd=cidir,
- stdin=self._devnull, stdout=self._stdout,
- stderr=self._stdout)
+ cwd=cidir,
+ stdin=self._devnull, stdout=self._stdout,
+ stderr=self._stdout)
return os.path.join(cidir, "cloud-init.iso")
+def get_qemu_path(arch, build_path=None):
+ """Fetch the path to the qemu binary."""
+ # If QEMU environment variable set, it takes precedence
+ if "QEMU" in os.environ:
+ qemu_path = os.environ["QEMU"]
+ elif build_path:
+ qemu_path = os.path.join(build_path, arch + "-softmmu")
+ qemu_path = os.path.join(qemu_path, "qemu-system-" + arch)
+ else:
+ # Default is to use system path for qemu.
+ qemu_path = "qemu-system-" + arch
+ return qemu_path
+
def parse_args(vmcls):
def get_default_jobs():
@@ -420,10 +436,15 @@ def parse_args(vmcls):
help="build QEMU from source in guest")
parser.add_option("--build-target",
help="QEMU build target", default="check")
+ parser.add_option("--build-path", default=None,
+ help="Path of build directory, "\
+ "for using build tree QEMU binary. ")
parser.add_option("--interactive", "-I", action="store_true",
help="Interactively run command")
parser.add_option("--snapshot", "-s", action="store_true",
help="run tests with a snapshot")
+ parser.add_option("--genisoimage", default="genisoimage",
+ help="iso imaging tool")
parser.disable_interspersed_args()
return parser.parse_args()
@@ -435,7 +456,8 @@ def main(vmcls):
return 1
logging.basicConfig(level=(logging.DEBUG if args.debug
else logging.WARN))
- vm = vmcls(debug=args.debug, vcpus=args.jobs)
+ vm = vmcls(debug=args.debug, vcpus=args.jobs,
+ genisoimage=args.genisoimage, build_path=args.build_path)
if args.build_image:
if os.path.exists(args.image) and not args.force:
sys.stderr.writelines(["Image file exists: %s\n" % args.image,
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index 3ba1d90984..2ce7c96085 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -140,7 +140,6 @@ enum {
struct lo_data {
pthread_mutex_t mutex;
int debug;
- int norace;
int writeback;
int flock;
int posix_lock;
@@ -176,7 +175,6 @@ static const struct fuse_opt lo_opts[] = {
{ "cache=none", offsetof(struct lo_data, cache), CACHE_NONE },
{ "cache=auto", offsetof(struct lo_data, cache), CACHE_AUTO },
{ "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS },
- { "norace", offsetof(struct lo_data, norace), 1 },
{ "readdirplus", offsetof(struct lo_data, readdirplus_set), 1 },
{ "no_readdirplus", offsetof(struct lo_data, readdirplus_clear), 1 },
FUSE_OPT_END
@@ -592,136 +590,6 @@ static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
fuse_reply_attr(req, &buf, lo->timeout);
}
-/*
- * Increments parent->nlookup and caller must release refcount using
- * lo_inode_put(&parent).
- */
-static int lo_parent_and_name(struct lo_data *lo, struct lo_inode *inode,
- char path[PATH_MAX], struct lo_inode **parent)
-{
- char procname[64];
- char *last;
- struct stat stat;
- struct lo_inode *p;
- int retries = 2;
- int res;
-
-retry:
- sprintf(procname, "%i", inode->fd);
-
- res = readlinkat(lo->proc_self_fd, procname, path, PATH_MAX);
- if (res < 0) {
- fuse_log(FUSE_LOG_WARNING, "%s: readlink failed: %m\n", __func__);
- goto fail_noretry;
- }
-
- if (res >= PATH_MAX) {
- fuse_log(FUSE_LOG_WARNING, "%s: readlink overflowed\n", __func__);
- goto fail_noretry;
- }
- path[res] = '\0';
-
- last = strrchr(path, '/');
- if (last == NULL) {
- /* Shouldn't happen */
- fuse_log(
- FUSE_LOG_WARNING,
- "%s: INTERNAL ERROR: bad path read from proc\n", __func__);
- goto fail_noretry;
- }
- if (last == path) {
- p = &lo->root;
- pthread_mutex_lock(&lo->mutex);
- p->nlookup++;
- g_atomic_int_inc(&p->refcount);
- pthread_mutex_unlock(&lo->mutex);
- } else {
- *last = '\0';
- res = fstatat(AT_FDCWD, last == path ? "/" : path, &stat, 0);
- if (res == -1) {
- if (!retries) {
- fuse_log(FUSE_LOG_WARNING,
- "%s: failed to stat parent: %m\n", __func__);
- }
- goto fail;
- }
- p = lo_find(lo, &stat);
- if (p == NULL) {
- if (!retries) {
- fuse_log(FUSE_LOG_WARNING,
- "%s: failed to find parent\n", __func__);
- }
- goto fail;
- }
- }
- last++;
- res = fstatat(p->fd, last, &stat, AT_SYMLINK_NOFOLLOW);
- if (res == -1) {
- if (!retries) {
- fuse_log(FUSE_LOG_WARNING,
- "%s: failed to stat last\n", __func__);
- }
- goto fail_unref;
- }
- if (stat.st_dev != inode->key.dev || stat.st_ino != inode->key.ino) {
- if (!retries) {
- fuse_log(FUSE_LOG_WARNING,
- "%s: failed to match last\n", __func__);
- }
- goto fail_unref;
- }
- *parent = p;
- memmove(path, last, strlen(last) + 1);
-
- return 0;
-
-fail_unref:
- unref_inode_lolocked(lo, p, 1);
- lo_inode_put(lo, &p);
-fail:
- if (retries) {
- retries--;
- goto retry;
- }
-fail_noretry:
- errno = EIO;
- return -1;
-}
-
-static int utimensat_empty(struct lo_data *lo, struct lo_inode *inode,
- const struct timespec *tv)
-{
- int res;
- struct lo_inode *parent;
- char path[PATH_MAX];
-
- if (S_ISLNK(inode->filetype)) {
- res = utimensat(inode->fd, "", tv, AT_EMPTY_PATH);
- if (res == -1 && errno == EINVAL) {
- /* Sorry, no race free way to set times on symlink. */
- if (lo->norace) {
- errno = EPERM;
- } else {
- goto fallback;
- }
- }
- return res;
- }
- sprintf(path, "%i", inode->fd);
-
- return utimensat(lo->proc_self_fd, path, tv, 0);
-
-fallback:
- res = lo_parent_and_name(lo, inode, path, &parent);
- if (res != -1) {
- res = utimensat(parent->fd, path, tv, AT_SYMLINK_NOFOLLOW);
- unref_inode_lolocked(lo, parent, 1);
- lo_inode_put(lo, &parent);
- }
-
- return res;
-}
-
static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi)
{
struct lo_data *lo = lo_data(req);
@@ -828,7 +696,8 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
if (fi) {
res = futimens(fd, tv);
} else {
- res = utimensat_empty(lo, inode, tv);
+ sprintf(procname, "%i", inode->fd);
+ res = utimensat(lo->proc_self_fd, procname, tv, 0);
}
if (res == -1) {
goto out_err;
@@ -1129,41 +998,6 @@ static void lo_symlink(fuse_req_t req, const char *link, fuse_ino_t parent,
lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
}
-static int linkat_empty_nofollow(struct lo_data *lo, struct lo_inode *inode,
- int dfd, const char *name)
-{
- int res;
- struct lo_inode *parent;
- char path[PATH_MAX];
-
- if (S_ISLNK(inode->filetype)) {
- res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
- if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
- /* Sorry, no race free way to hard-link a symlink. */
- if (lo->norace) {
- errno = EPERM;
- } else {
- goto fallback;
- }
- }
- return res;
- }
-
- sprintf(path, "%i", inode->fd);
-
- return linkat(lo->proc_self_fd, path, dfd, name, AT_SYMLINK_FOLLOW);
-
-fallback:
- res = lo_parent_and_name(lo, inode, path, &parent);
- if (res != -1) {
- res = linkat(parent->fd, path, dfd, name, 0);
- unref_inode_lolocked(lo, parent, 1);
- lo_inode_put(lo, &parent);
- }
-
- return res;
-}
-
static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
const char *name)
{
@@ -1172,6 +1006,7 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
struct lo_inode *parent_inode;
struct lo_inode *inode;
struct fuse_entry_param e;
+ char procname[64];
int saverr;
if (!is_safe_path_component(name)) {
@@ -1190,7 +1025,9 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
e.attr_timeout = lo->timeout;
e.entry_timeout = lo->timeout;
- res = linkat_empty_nofollow(lo, inode, parent_inode->fd, name);
+ sprintf(procname, "%i", inode->fd);
+ res = linkat(lo->proc_self_fd, procname, parent_inode->fd, name,
+ AT_SYMLINK_FOLLOW);
if (res == -1) {
goto out_err;
}