diff --git a/.cirrus.yml b/.cirrus.yml index 20843a420c..4895987da4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,9 +10,9 @@ windows_msys2_task: memory: 8G env: CIRRUS_SHELL: powershell - MSYS: winsymlinks:nativestrict + MSYS: winsymlinks:native MSYSTEM: MINGW64 - MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2022-05-03/msys2-base-x86_64-20220503.sfx.exe + MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-base-x86_64-20220603.sfx.exe MSYS2_FINGERPRINT: 0 MSYS2_PACKAGES: " diffutils git grep make pkg-config sed diff --git a/.gitignore b/.gitignore index 09a811a4a3..5a09dda9ff 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /qemu_libafl_bridge/target/ /GNUmakefile /build/ +/.cache/ *.pyc .sdk .stgit-* diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 1931b77b49..6c05c46397 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -41,8 +41,7 @@ build-system-ubuntu: job: amd64-ubuntu2004-container variables: IMAGE: ubuntu2004 - CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system - --enable-capstone + CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-capstone TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build @@ -120,7 +119,7 @@ build-system-fedora: variables: IMAGE: fedora CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs - --enable-fdt=system --enable-slirp=system --enable-capstone + --enable-fdt=system --enable-slirp --enable-capstone TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu MAKE_CHECK_ARGS: check-build @@ -339,10 +338,8 @@ clang-user: # On gitlab runners, default value sometimes end up calling 2 lds concurrently and # triggers an Out-Of-Memory error # -# Since slirp callbacks are used in QEMU Timers, slirp needs to be compiled together -# with QEMU and linked as a static library to avoid false positives in CFI checks. -# This can be accomplished by using -enable-slirp=git, which avoids the use of -# a system-wide version of the library +# Since slirp callbacks are used in QEMU Timers, we cannot use libslirp with +# CFI builds, and thus have to disable it here. # # Split in three sets of build/check/avocado to limit the execution time of each # job @@ -355,7 +352,7 @@ build-cfi-aarch64: AR: llvm-ar IMAGE: fedora CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug - --enable-safe-stack --enable-slirp=git + --enable-safe-stack --disable-slirp TARGETS: aarch64-softmmu MAKE_CHECK_ARGS: check-build # FIXME: This job is often failing, likely due to out-of-memory problems in @@ -395,7 +392,7 @@ build-cfi-ppc64-s390x: AR: llvm-ar IMAGE: fedora CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug - --enable-safe-stack --enable-slirp=git + --enable-safe-stack --disable-slirp TARGETS: ppc64-softmmu s390x-softmmu MAKE_CHECK_ARGS: check-build # FIXME: This job is often failing, likely due to out-of-memory problems in @@ -435,7 +432,7 @@ build-cfi-x86_64: AR: llvm-ar IMAGE: fedora CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug - --enable-safe-stack --enable-slirp=git + --enable-safe-stack --disable-slirp TARGETS: x86_64-softmmu MAKE_CHECK_ARGS: check-build timeout: 70m @@ -469,7 +466,7 @@ tsan-build: variables: IMAGE: ubuntu2004 CONFIGURE_ARGS: --enable-tsan --cc=clang-10 --cxx=clang++-10 - --enable-trace-backends=ust --enable-fdt=system --enable-slirp=system + --enable-trace-backends=ust --enable-fdt=system --disable-slirp TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user MAKE_CHECK_ARGS: bench V=1 @@ -571,7 +568,6 @@ build-without-default-features: --disable-capstone --disable-pie --disable-qom-cast-debug - --disable-slirp --disable-strip TARGETS: avr-softmmu i386-softmmu mips64-softmmu s390x-softmmu sh4-softmmu sparc64-softmmu hexagon-linux-user i386-linux-user s390x-linux-user diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index 609c364308..d70da61248 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -63,7 +63,7 @@ x64-freebsd-13-build: NAME: freebsd-13 CIRRUS_VM_INSTANCE_TYPE: freebsd_instance CIRRUS_VM_IMAGE_SELECTOR: image_family - CIRRUS_VM_IMAGE_NAME: freebsd-13-0 + CIRRUS_VM_IMAGE_NAME: freebsd-13-1 CIRRUS_VM_CPUS: 8 CIRRUS_VM_RAM: 8G UPDATE_COMMAND: pkg update diff --git a/.gitlab-ci.d/cirrus/build.yml b/.gitlab-ci.d/cirrus/build.yml index c555f5d36e..7ef6af8d33 100644 --- a/.gitlab-ci.d/cirrus/build.yml +++ b/.gitlab-ci.d/cirrus/build.yml @@ -32,5 +32,6 @@ build_task: - $MAKE -j$(sysctl -n hw.ncpu) - for TARGET in $TEST_TARGETS ; do - $MAKE -j$(sysctl -n hw.ncpu) $TARGET V=1 ; + $MAKE -j$(sysctl -n hw.ncpu) $TARGET V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; done diff --git a/.gitlab-ci.d/cirrus/freebsd-12.vars b/.gitlab-ci.d/cirrus/freebsd-12.vars index f59263731f..c3db1d7d30 100644 --- a/.gitlab-ci.d/cirrus/freebsd-12.vars +++ b/.gitlab-ci.d/cirrus/freebsd-12.vars @@ -1,5 +1,4 @@ # THIS FILE WAS AUTO-GENERATED -# ... and then edited to fix py39, pending proper lcitool update. # # $ lcitool variables freebsd-12 qemu # @@ -12,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-virtualenv py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars index 40fc961398..d31faa787f 100644 --- a/.gitlab-ci.d/cirrus/freebsd-13.vars +++ b/.gitlab-ci.d/cirrus/freebsd-13.vars @@ -1,5 +1,4 @@ # THIS FILE WAS AUTO-GENERATED -# ... and then edited to fix py39, pending proper lcitool update. # # $ lcitool variables freebsd-13 qemu # @@ -12,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-virtualenv py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/macos-11.vars b/.gitlab-ci.d/cirrus/macos-11.vars index cfe9181fd4..aee9f50de6 100644 --- a/.gitlab-ci.d/cirrus/macos-11.vars +++ b/.gitlab-ci.d/cirrus/macos-11.vars @@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='brew' PIP3='/usr/local/bin/pip3' -PKGS='bash bc bzip2 capstone ccache ctags curl dbus diffutils dtc gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd' -PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme virtualenv' +PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd' +PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/container-core.yml b/.gitlab-ci.d/container-core.yml index e8dd1f476a..08f8450fa1 100644 --- a/.gitlab-ci.d/container-core.yml +++ b/.gitlab-ci.d/container-core.yml @@ -10,8 +10,3 @@ amd64-fedora-container: extends: .container_job_template variables: NAME: fedora - -amd64-debian10-container: - extends: .container_job_template - variables: - NAME: debian10 diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index b7963498a3..2d560e9764 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -1,21 +1,18 @@ alpha-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-alpha-cross amd64-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-amd64-cross amd64-debian-user-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-all-test-cross @@ -65,22 +62,19 @@ hexagon-cross-container: hppa-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-hppa-cross m68k-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-m68k-cross mips64-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-mips64-cross @@ -92,8 +86,7 @@ mips64el-debian-cross-container: mips-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-mips-cross @@ -105,8 +98,7 @@ mipsel-debian-cross-container: powerpc-test-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian11-container'] + stage: containers variables: NAME: debian-powerpc-test-cross @@ -127,8 +119,7 @@ riscv64-debian-cross-container: # we can however build TCG tests using a non-sid base riscv64-debian-test-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian11-container'] + stage: containers variables: NAME: debian-riscv64-test-cross @@ -140,22 +131,19 @@ s390x-debian-cross-container: sh4-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-sh4-cross sparc64-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-sparc64-cross tricore-debian-cross-container: extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + stage: containers variables: NAME: debian-tricore-cross diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index be34cbc7ba..96d2a3b58b 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -7,11 +7,6 @@ amd64-alpine-container: variables: NAME: alpine -amd64-debian11-container: - extends: .container_job_template - variables: - NAME: debian11 - amd64-debian-container: extends: .container_job_template stage: containers diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index 28b2142ec2..5e8892fd49 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -46,5 +46,8 @@ - cd build - PKG_CONFIG_PATH=$PKG_CONFIG_PATH ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS - --disable-system + --disable-system --target-list-exclude="aarch64_be-linux-user + alpha-linux-user cris-linux-user m68k-linux-user microblazeel-linux-user + nios2-linux-user or1k-linux-user ppc-linux-user sparc-linux-user + xtensa-linux-user $CROSS_SKIP_TARGETS" - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index 4a5fb6ea2a..c4cd96433d 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -70,20 +70,6 @@ cross-i386-tci: EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user MAKE_CHECK_ARGS: check check-tcg -cross-mips-system: - extends: .cross_system_build_job - needs: - job: mips-debian-cross-container - variables: - IMAGE: debian-mips-cross - -cross-mips-user: - extends: .cross_user_build_job - needs: - job: mips-debian-cross-container - variables: - IMAGE: debian-mips-cross - cross-mipsel-system: extends: .cross_system_build_job needs: diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml index 15aaccc481..97f99e29c2 100644 --- a/.gitlab-ci.d/custom-runners.yml +++ b/.gitlab-ci.d/custom-runners.yml @@ -15,6 +15,6 @@ variables: include: - local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml' - - local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml' - - local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml' + - local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml' + - local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml' - local: '/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml' diff --git a/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml b/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml index 49aa703f55..068b0c4335 100644 --- a/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml +++ b/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml @@ -23,6 +23,8 @@ centos-stream-8-x86_64: - mkdir build - cd build - ../scripts/ci/org.centos/stream/8/x86_64/configure + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make -j"$JOBS" - make NINJA=":" check + || { cat meson-logs/testlog.txt; exit 1; } ; - ../scripts/ci/org.centos/stream/8/x86_64/test-avocado diff --git a/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml b/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml index 03e74c97db..0c835939db 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml @@ -17,9 +17,12 @@ ubuntu-20.04-s390x-all-linux-static: - mkdir build - cd build - ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; - make --output-sync -j`nproc` check-tcg V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-all: needs: [] @@ -35,8 +38,10 @@ ubuntu-20.04-s390x-all: - mkdir build - cd build - ../configure --disable-libssh + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-alldbg: needs: [] @@ -55,9 +60,11 @@ ubuntu-20.04-s390x-alldbg: - mkdir build - cd build - ../configure --enable-debug --disable-libssh + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make clean - make --output-sync -j`nproc` - make --output-sync -j`nproc` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-clang: needs: [] @@ -76,8 +83,10 @@ ubuntu-20.04-s390x-clang: - mkdir build - cd build - ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-tci: needs: [] @@ -96,6 +105,7 @@ ubuntu-20.04-s390x-tci: - mkdir build - cd build - ../configure --disable-libssh --enable-tcg-interpreter + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` ubuntu-20.04-s390x-notcg: @@ -115,5 +125,7 @@ ubuntu-20.04-s390x-notcg: - mkdir build - cd build - ../configure --disable-libssh --disable-tcg + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml similarity index 72% rename from .gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml rename to .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml index 1998460d06..1a2f9b8dbe 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch32.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml @@ -1,12 +1,12 @@ -# All ubuntu-20.04 jobs should run successfully in an environment +# All ubuntu-22.04 jobs should run successfully in an environment # setup by the scripts/ci/setup/qemu/build-environment.yml task # "Install basic packages to build QEMU on Ubuntu 20.04" -ubuntu-20.04-aarch32-all: +ubuntu-22.04-aarch32-all: needs: [] stage: build tags: - - ubuntu_20.04 + - ubuntu_22.04 - aarch32 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -19,5 +19,7 @@ ubuntu-20.04-aarch32-all: - mkdir build - cd build - ../configure --cross-prefix=arm-linux-gnueabihf- + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml similarity index 68% rename from .gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml rename to .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml index 65718a188a..ce0b18af6f 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml @@ -2,30 +2,33 @@ # setup by the scripts/ci/setup/qemu/build-environment.yml task # "Install basic packages to build QEMU on Ubuntu 20.04" -ubuntu-20.04-aarch64-all-linux-static: +ubuntu-22.04-aarch64-all-linux-static: needs: [] stage: build tags: - - ubuntu_20.04 + - ubuntu_22.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - if: "$AARCH64_RUNNER_AVAILABLE" script: - # --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763 - # --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages - mkdir build - cd build - - ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh + # Disable -static-pie due to build error with system libc: + # https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1987438 + - ../configure --enable-debug --static --disable-system --disable-pie + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; - make --output-sync -j`nproc --ignore=40` check-tcg V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; -ubuntu-20.04-aarch64-all: +ubuntu-22.04-aarch64-all: needs: [] stage: build tags: - - ubuntu_20.04 + - ubuntu_22.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -37,15 +40,17 @@ ubuntu-20.04-aarch64-all: script: - mkdir build - cd build - - ../configure --disable-libssh + - ../configure + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; -ubuntu-20.04-aarch64-alldbg: +ubuntu-22.04-aarch64-alldbg: needs: [] stage: build tags: - - ubuntu_20.04 + - ubuntu_22.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -53,16 +58,18 @@ ubuntu-20.04-aarch64-alldbg: script: - mkdir build - cd build - - ../configure --enable-debug --disable-libssh + - ../configure --enable-debug + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make clean - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; -ubuntu-20.04-aarch64-clang: +ubuntu-22.04-aarch64-clang: needs: [] stage: build tags: - - ubuntu_20.04 + - ubuntu_22.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -75,14 +82,16 @@ ubuntu-20.04-aarch64-clang: - mkdir build - cd build - ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; -ubuntu-20.04-aarch64-tci: +ubuntu-22.04-aarch64-tci: needs: [] stage: build tags: - - ubuntu_20.04 + - ubuntu_22.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -94,14 +103,15 @@ ubuntu-20.04-aarch64-tci: script: - mkdir build - cd build - - ../configure --disable-libssh --enable-tcg-interpreter + - ../configure --enable-tcg-interpreter + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` -ubuntu-20.04-aarch64-notcg: +ubuntu-22.04-aarch64-notcg: needs: [] stage: build tags: - - ubuntu_20.04 + - ubuntu_22.04 - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' @@ -113,6 +123,8 @@ ubuntu-20.04-aarch64-notcg: script: - mkdir build - cd build - - ../configure --disable-libssh --disable-tcg + - ../configure --disable-tcg + || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check V=1 + || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/stages.yml b/.gitlab-ci.d/stages.yml index f50826018d..f92f57a27d 100644 --- a/.gitlab-ci.d/stages.yml +++ b/.gitlab-ci.d/stages.yml @@ -3,6 +3,5 @@ # - test (for test stages, using build artefacts from a build stage) stages: - containers - - containers-layer2 - build - test diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index 1b2ede49e1..a3e7a37022 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -17,7 +17,7 @@ } - If ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) { Invoke-WebRequest - "https://github.com/msys2/msys2-installer/releases/download/2022-05-03/msys2-base-x86_64-20220503.sfx.exe" + "https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-base-x86_64-20220603.sfx.exe" -outfile "msys64\var\cache\msys2.exe" } - msys64\var\cache\msys2.exe -y @@ -33,7 +33,8 @@ msys2-64bit: extends: .shared_msys2_builder script: - .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed - diffutils git grep make sed + bison diffutils flex + git grep make sed mingw-w64-x86_64-capstone mingw-w64-x86_64-curl mingw-w64-x86_64-cyrus-sasl @@ -57,17 +58,18 @@ msys2-64bit: mingw-w64-x86_64-zstd " - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory - $env:MSYSTEM = 'MINGW64' # Start a 64 bit Mingw environment + - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink - .\msys64\usr\bin\bash -lc './configure --target-list=x86_64-softmmu --enable-capstone --without-default-devices' - - .\msys64\usr\bin\bash -lc "sed -i '/^ROMS=/d' build/config-host.mak" - - .\msys64\usr\bin\bash -lc 'make -j2' - - .\msys64\usr\bin\bash -lc 'make check' + - .\msys64\usr\bin\bash -lc 'make' + - .\msys64\usr\bin\bash -lc 'make check || { cat build/meson-logs/testlog.txt; exit 1; } ;' msys2-32bit: extends: .shared_msys2_builder script: - .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed - diffutils git grep make sed + bison diffutils flex + git grep make sed mingw-w64-i686-capstone mingw-w64-i686-curl mingw-w64-i686-cyrus-sasl @@ -89,8 +91,9 @@ msys2-32bit: mingw-w64-i686-usbredir " - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory - $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinG environment + - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink - mkdir output - cd output - ..\msys64\usr\bin\bash -lc "../configure --target-list=ppc64-softmmu" - - ..\msys64\usr\bin\bash -lc 'make -j2' - - ..\msys64\usr\bin\bash -lc 'make check' + - ..\msys64\usr\bin\bash -lc 'make' + - ..\msys64\usr\bin\bash -lc 'make check || { cat meson-logs/testlog.txt; exit 1; } ;' diff --git a/.gitmodules b/.gitmodules index aedd9a03d4..24cffa87d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -46,9 +46,6 @@ [submodule "roms/edk2"] path = roms/edk2 url = https://gitlab.com/qemu-project/edk2.git -[submodule "slirp"] - path = slirp - url = https://gitlab.com/qemu-project/libslirp.git [submodule "roms/opensbi"] path = roms/opensbi url = https://gitlab.com/qemu-project/opensbi.git diff --git a/.mailmap b/.mailmap index 8c326709cf..1f7319b70b 100644 --- a/.mailmap +++ b/.mailmap @@ -65,6 +65,7 @@ James Hogan Leif Lindholm Leif Lindholm Radoslaw Biernacki +Paul Brook Paul Burton Paul Burton Paul Burton diff --git a/MAINTAINERS b/MAINTAINERS index 6af9cd985c..8ae2e43c83 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1129,7 +1129,7 @@ Virt M: Xiaojuan Yang M: Song Gao S: Maintained -F: docs/system/loongarch/loongson3.rst +F: docs/system/loongarch/virt.rst F: configs/targets/loongarch64-softmmu.mak F: configs/devices/loongarch64-softmmu/default.mak F: hw/loongarch/ @@ -1282,7 +1282,7 @@ F: hw/openrisc/openrisc_sim.c PowerPC Machines ---------------- -405 (ref405ep and taihu) +405 (ref405ep) L: qemu-ppc@nongnu.org S: Orphan F: hw/ppc/ppc405_boards.c @@ -2030,8 +2030,10 @@ virtio-blk M: Stefan Hajnoczi L: qemu-block@nongnu.org S: Supported +F: hw/block/virtio-blk-common.c F: hw/block/virtio-blk.c F: hw/block/dataplane/* +F: include/hw/virtio/virtio-blk-common.h F: tests/qtest/virtio-blk-test.c T: git https://github.com/stefanha/qemu.git block @@ -2098,6 +2100,14 @@ F: hw/virtio/vhost-user-rng-pci.c F: include/hw/virtio/vhost-user-rng.h F: tools/vhost-user-rng/* +vhost-user-gpio +M: Alex Bennée +R: Viresh Kumar +S: Maintained +F: hw/virtio/vhost-user-gpio* +F: include/hw/virtio/vhost-user-gpio.h +F: tests/qtest/libqos/virtio-gpio.* + virtio-crypto M: Gonglei S: Supported @@ -2271,11 +2281,13 @@ S: Maintained F: contrib/vhost-user-blk/ F: contrib/vhost-user-scsi/ F: hw/block/vhost-user-blk.c +F: hw/block/virtio-blk-common.c F: hw/scsi/vhost-user-scsi.c F: hw/virtio/vhost-user-blk-pci.c F: hw/virtio/vhost-user-scsi-pci.c F: include/hw/virtio/vhost-user-blk.h F: include/hw/virtio/vhost-user-scsi.h +F: include/hw/virtio/virtio-blk-common.h vhost-user-gpu M: Marc-André Lureau @@ -2438,6 +2450,7 @@ X: audio/jackaudio.c X: audio/ossaudio.c X: audio/paaudio.c X: audio/sdlaudio.c +X: audio/sndioaudio.c X: audio/spiceaudio.c F: qapi/audio.json @@ -2482,6 +2495,12 @@ R: Thomas Huth S: Odd Fixes F: audio/sdlaudio.c +Sndio Audio backend +M: Gerd Hoffmann +R: Alexandre Ratchov +S: Odd Fixes +F: audio/sndioaudio.c + Block layer core M: Kevin Wolf M: Hanna Reitz @@ -2670,7 +2689,7 @@ GDB stub M: Alex Bennée R: Philippe Mathieu-Daudé S: Maintained -F: gdbstub* +F: gdbstub/* F: include/exec/gdbstub.h F: gdb-xml/ F: tests/tcg/multiarch/gdbstub/ @@ -2978,7 +2997,6 @@ F: include/hw/registerfields.h SLIRP M: Samuel Thibault S: Maintained -F: slirp/ F: net/slirp.c F: include/net/slirp.h T: git https://people.debian.org/~sthibault/qemu.git slirp @@ -3724,7 +3742,8 @@ GitLab custom runner (Works On Arm Sponsored) M: Alex Bennée M: Philippe Mathieu-Daudé S: Maintained -F: .gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml +F: .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml +F: .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml Documentation ------------- diff --git a/Makefile b/Makefile index 13234f2aa4..a48103cc8a 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,9 @@ configure: ; ifneq ($(wildcard config-host.mak),) include config-host.mak +include Makefile.prereqs +Makefile.prereqs: config-host.mak + git-submodule-update: .git-submodule-status: git-submodule-update config-host.mak Makefile: .git-submodule-status @@ -145,7 +148,7 @@ NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \ $(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \ -d keepdepfile ninja-cmd-goals = $(or $(MAKECMDGOALS), all) -ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g)))) +ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g)) makefile-targets := build.ninja ctags TAGS cscope dist clean uninstall # "ninja -t targets" also lists all prerequisites. If build system @@ -186,7 +189,7 @@ include $(SRC_PATH)/tests/Makefile.include all: recurse-all -ROMS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROMS))) +ROMS_RULES=$(foreach t, all clean distclean, $(addsuffix /$(t), $(ROMS))) .PHONY: $(ROMS_RULES) $(ROMS_RULES): $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),) @@ -194,6 +197,7 @@ $(ROMS_RULES): .PHONY: recurse-all recurse-clean recurse-all: $(addsuffix /all, $(ROMS)) recurse-clean: $(addsuffix /clean, $(ROMS)) +recurse-distclean: $(addsuffix /distclean, $(ROMS)) ###################################################################### @@ -214,10 +218,10 @@ dist: qemu-$(VERSION).tar.bz2 qemu-%.tar.bz2: $(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)" -distclean: clean +distclean: clean recurse-distclean -$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || : - rm -f config-host.mak qemu-bundle - rm -f tests/tcg/config-*.mak + rm -f config-host.mak Makefile.prereqs qemu-bundle + rm -f tests/tcg/*/config-target.mak tests/tcg/config-host.mak rm -f config.status rm -f roms/seabios/config.mak rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols diff --git a/README.qemu.rst b/README.qemu.rst index 23795b8377..21df79ef43 100644 --- a/README.qemu.rst +++ b/README.qemu.rst @@ -39,7 +39,7 @@ Documentation can be found hosted online at current development version that is available at ``_ is generated from the ``docs/`` folder in the source tree, and is built by `Sphinx -_`. +`_. Building @@ -78,7 +78,7 @@ format-patch' and/or 'git send-email' to format & send the mail to the qemu-devel@nongnu.org mailing list. All patches submitted must contain a 'Signed-off-by' line from the author. Patches should follow the guidelines set out in the `style section -` of +`_ of the Developers Guide. Additional information on submitting patches can be found online via diff --git a/VERSION b/VERSION index 59f2fcbfc0..72cf60d0ec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.50 +7.1.50 diff --git a/accel/accel-common.c b/accel/accel-common.c index 50035bda55..df72cc989a 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -129,6 +129,16 @@ bool accel_cpu_realizefn(CPUState *cpu, Error **errp) return true; } +int accel_supported_gdbstub_sstep_flags(void) +{ + AccelState *accel = current_accel(); + AccelClass *acc = ACCEL_GET_CLASS(accel); + if (acc->gdbstub_supported_sstep_flags) { + return acc->gdbstub_supported_sstep_flags(); + } + return 0; +} + static const TypeInfo accel_cpu_type = { .name = TYPE_ACCEL_CPU, .parent = TYPE_OBJECT, diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index c4244a23c6..fbf4fe3497 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -16,12 +16,14 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "sysemu/kvm.h" #include "sysemu/kvm_int.h" #include "sysemu/runstate.h" #include "sysemu/cpus.h" #include "qemu/guest-random.h" #include "qapi/error.h" +#include #include "kvm-cpus.h" static void *kvm_vcpu_thread_fn(void *arg) @@ -95,6 +97,13 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) ops->synchronize_post_init = kvm_cpu_synchronize_post_init; ops->synchronize_state = kvm_cpu_synchronize_state; ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm; + +#ifdef KVM_CAP_SET_GUEST_DEBUG + ops->supports_guest_debug = kvm_supports_guest_debug; + ops->insert_breakpoint = kvm_insert_breakpoint; + ops->remove_breakpoint = kvm_remove_breakpoint; + ops->remove_all_breakpoints = kvm_remove_all_breakpoints; +#endif } static const TypeInfo kvm_accel_ops_type = { diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f165074e99..423fb1936f 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -175,7 +175,7 @@ bool kvm_direct_msi_allowed; bool kvm_ioeventfd_any_length_allowed; bool kvm_msi_use_devid; bool kvm_has_guest_debug; -int kvm_sstep_flags; +static int kvm_sstep_flags; static bool kvm_immediate_exit; static hwaddr kvm_max_slot_size = ~0; @@ -719,12 +719,32 @@ static void kvm_dirty_ring_mark_page(KVMState *s, uint32_t as_id, static bool dirty_gfn_is_dirtied(struct kvm_dirty_gfn *gfn) { - return gfn->flags == KVM_DIRTY_GFN_F_DIRTY; + /* + * Read the flags before the value. Pairs with barrier in + * KVM's kvm_dirty_ring_push() function. + */ + return qatomic_load_acquire(&gfn->flags) == KVM_DIRTY_GFN_F_DIRTY; } static void dirty_gfn_set_collected(struct kvm_dirty_gfn *gfn) { - gfn->flags = KVM_DIRTY_GFN_F_RESET; + /* + * Use a store-release so that the CPU that executes KVM_RESET_DIRTY_RINGS + * sees the full content of the ring: + * + * CPU0 CPU1 CPU2 + * ------------------------------------------------------------------------------ + * fill gfn0 + * store-rel flags for gfn0 + * load-acq flags for gfn0 + * store-rel RESET for gfn0 + * ioctl(RESET_RINGS) + * load-acq flags for gfn0 + * check if flags have RESET + * + * The synchronization goes from CPU2 to CPU0 to CPU1. + */ + qatomic_store_release(&gfn->flags, KVM_DIRTY_GFN_F_RESET); } /* @@ -2265,7 +2285,7 @@ static void kvm_irqchip_create(KVMState *s) ret = kvm_arch_irqchip_create(s); if (ret == 0) { if (s->kernel_irqchip_split == ON_OFF_AUTO_ON) { - perror("Split IRQ chip mode not supported."); + error_report("Split IRQ chip mode not supported."); exit(1); } else { ret = kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP); @@ -3267,8 +3287,13 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) return data.err; } -int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) +bool kvm_supports_guest_debug(void) +{ + /* probed during kvm_init() */ + return kvm_has_guest_debug; +} + +int kvm_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len) { struct kvm_sw_breakpoint *bp; int err; @@ -3306,8 +3331,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, return 0; } -int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) +int kvm_remove_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len) { struct kvm_sw_breakpoint *bp; int err; @@ -3371,28 +3395,6 @@ void kvm_remove_all_breakpoints(CPUState *cpu) } } -#else /* !KVM_CAP_SET_GUEST_DEBUG */ - -int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) -{ - return -EINVAL; -} - -int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) -{ - return -EINVAL; -} - -int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) -{ - return -EINVAL; -} - -void kvm_remove_all_breakpoints(CPUState *cpu) -{ -} #endif /* !KVM_CAP_SET_GUEST_DEBUG */ static int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset) @@ -3692,6 +3694,17 @@ static void kvm_accel_instance_init(Object *obj) s->kvm_dirty_ring_size = 0; } +/** + * kvm_gdbstub_sstep_flags(): + * + * Returns: SSTEP_* flags that KVM supports for guest debug. The + * support is probed during kvm_init() + */ +static int kvm_gdbstub_sstep_flags(void) +{ + return kvm_sstep_flags; +} + static void kvm_accel_class_init(ObjectClass *oc, void *data) { AccelClass *ac = ACCEL_CLASS(oc); @@ -3699,6 +3712,7 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data) ac->init_machine = kvm_init; ac->has_memory = kvm_accel_has_memory; ac->allowed = &kvm_allowed; + ac->gdbstub_supported_sstep_flags = kvm_gdbstub_sstep_flags; object_class_property_add(oc, "kernel-irqchip", "on|off|split", NULL, kvm_set_kernel_irqchip, @@ -3888,7 +3902,7 @@ exit: typedef struct StatsDescriptors { const char *ident; /* cache key, currently the StatsTarget */ struct kvm_stats_desc *kvm_stats_desc; - struct kvm_stats_header *kvm_stats_header; + struct kvm_stats_header kvm_stats_header; QTAILQ_ENTRY(StatsDescriptors) next; } StatsDescriptors; @@ -3919,7 +3933,7 @@ static StatsDescriptors *find_stats_descriptors(StatsTarget target, int stats_fd descriptors = g_new0(StatsDescriptors, 1); /* Read stats header */ - kvm_stats_header = g_malloc(sizeof(*kvm_stats_header)); + kvm_stats_header = &descriptors->kvm_stats_header; ret = read(stats_fd, kvm_stats_header, sizeof(*kvm_stats_header)); if (ret != sizeof(*kvm_stats_header)) { error_setg(errp, "KVM stats: failed to read stats header: " @@ -3944,7 +3958,6 @@ static StatsDescriptors *find_stats_descriptors(StatsTarget target, int stats_fd g_free(kvm_stats_desc); return NULL; } - descriptors->kvm_stats_header = kvm_stats_header; descriptors->kvm_stats_desc = kvm_stats_desc; descriptors->ident = ident; QTAILQ_INSERT_TAIL(&stats_descriptors, descriptors, next); @@ -3969,7 +3982,7 @@ static void query_stats(StatsResultList **result, StatsTarget target, return; } - kvm_stats_header = descriptors->kvm_stats_header; + kvm_stats_header = &descriptors->kvm_stats_header; kvm_stats_desc = descriptors->kvm_stats_desc; size_desc = sizeof(*kvm_stats_desc) + kvm_stats_header->name_size; @@ -4034,7 +4047,7 @@ static void query_stats_schema(StatsSchemaList **result, StatsTarget target, return; } - kvm_stats_header = descriptors->kvm_stats_header; + kvm_stats_header = &descriptors->kvm_stats_header; kvm_stats_desc = descriptors->kvm_stats_desc; size_desc = sizeof(*kvm_stats_desc) + kvm_stats_header->name_size; @@ -4131,7 +4144,9 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp) query_stats_schema(result, STATS_TARGET_VM, stats_fd, errp); close(stats_fd); - stats_args.result.schema = result; - stats_args.errp = errp; - run_on_cpu(first_cpu, query_stats_schema_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args)); + if (first_cpu) { + stats_args.result.schema = result; + stats_args.errp = errp; + run_on_cpu(first_cpu, query_stats_schema_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args)); + } } diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h index bf0bd1bee4..fd63fe6a59 100644 --- a/accel/kvm/kvm-cpus.h +++ b/accel/kvm/kvm-cpus.h @@ -18,5 +18,9 @@ void kvm_destroy_vcpu(CPUState *cpu); void kvm_cpu_synchronize_post_reset(CPUState *cpu); void kvm_cpu_synchronize_post_init(CPUState *cpu); void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu); +bool kvm_supports_guest_debug(void); +int kvm_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len); +int kvm_remove_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len); +void kvm_remove_all_breakpoints(CPUState *cpu); #endif /* KVM_CPUS_H */ diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 2ac5f9c036..5d2dd8f351 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -46,27 +46,6 @@ int kvm_has_many_ioeventfds(void) return 0; } -int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) -{ - return -ENOSYS; -} - -int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) -{ - return -EINVAL; -} - -int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) -{ - return -EINVAL; -} - -void kvm_remove_all_breakpoints(CPUState *cpu) -{ -} - int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { return 1; diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index 6ce8a34228..c1b05767c0 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -21,6 +21,10 @@ void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) { } +void tcg_flush_jmp_cache(CPUState *cpu) +{ +} + int probe_access_flags(CPUArchState *env, target_ulong addr, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, uintptr_t retaddr) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index cabb04fb1e..11ae212680 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -42,6 +42,7 @@ #include "sysemu/replay.h" #include "sysemu/tcg.h" #include "exec/helper-proto.h" +#include "tb-jmp-cache.h" #include "tb-hash.h" #include "tb-context.h" #include "internal.h" @@ -170,22 +171,95 @@ uint32_t curr_cflags(CPUState *cpu) return cflags; } +struct tb_desc { + target_ulong pc; + target_ulong cs_base; + CPUArchState *env; + tb_page_addr_t page_addr0; + uint32_t flags; + uint32_t cflags; + uint32_t trace_vcpu_dstate; +}; + +static bool tb_lookup_cmp(const void *p, const void *d) +{ + const TranslationBlock *tb = p; + const struct tb_desc *desc = d; + + if ((TARGET_TB_PCREL || tb_pc(tb) == desc->pc) && + tb->page_addr[0] == desc->page_addr0 && + tb->cs_base == desc->cs_base && + tb->flags == desc->flags && + tb->trace_vcpu_dstate == desc->trace_vcpu_dstate && + tb_cflags(tb) == desc->cflags) { + /* check next page if needed */ + if (tb->page_addr[1] == -1) { + return true; + } else { + tb_page_addr_t phys_page1; + target_ulong virt_page1; + + /* + * We know that the first page matched, and an otherwise valid TB + * encountered an incomplete instruction at the end of that page, + * therefore we know that generating a new TB from the current PC + * must also require reading from the next page -- even if the + * second pages do not match, and therefore the resulting insn + * is different for the new TB. Therefore any exception raised + * here by the faulting lookup is not premature. + */ + virt_page1 = TARGET_PAGE_ALIGN(desc->pc); + phys_page1 = get_page_addr_code(desc->env, virt_page1); + if (tb->page_addr[1] == phys_page1) { + return true; + } + } + } + return false; +} + +static TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc, + target_ulong cs_base, uint32_t flags, + uint32_t cflags) +{ + tb_page_addr_t phys_pc; + struct tb_desc desc; + uint32_t h; + + desc.env = cpu->env_ptr; + desc.cs_base = cs_base; + desc.flags = flags; + desc.cflags = cflags; + desc.trace_vcpu_dstate = *cpu->trace_dstate; + desc.pc = pc; + phys_pc = get_page_addr_code(desc.env, pc); + if (phys_pc == -1) { + return NULL; + } + desc.page_addr0 = phys_pc; + h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : pc), + flags, cflags, *cpu->trace_dstate); + return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp); +} + /* Might cause an exception, so have a longjmp destination ready */ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc, target_ulong cs_base, uint32_t flags, uint32_t cflags) { TranslationBlock *tb; + CPUJumpCache *jc; uint32_t hash; /* we should never be trying to look up an INVALID tb */ tcg_debug_assert(!(cflags & CF_INVALID)); hash = tb_jmp_cache_hash_func(pc); - tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash]); + jc = cpu->tb_jmp_cache; + tb = tb_jmp_cache_get_tb(jc, hash); if (likely(tb && - tb->pc == pc && + tb_jmp_cache_get_pc(jc, hash, tb) == pc && tb->cs_base == cs_base && tb->flags == flags && tb->trace_vcpu_dstate == *cpu->trace_dstate && @@ -196,16 +270,14 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc, if (tb == NULL) { return NULL; } - qatomic_set(&cpu->tb_jmp_cache[hash], tb); + tb_jmp_cache_set(jc, hash, tb, pc); return tb; } -static inline void log_cpu_exec(target_ulong pc, CPUState *cpu, - const TranslationBlock *tb) +static void log_cpu_exec(target_ulong pc, CPUState *cpu, + const TranslationBlock *tb) { - if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC)) - && qemu_log_in_addr_range(pc)) { - + if (qemu_log_in_addr_range(pc)) { qemu_log_mask(CPU_LOG_EXEC, "Trace %d: %p [" TARGET_FMT_lx "/" TARGET_FMT_lx "/%08x/%08x] %s\n", @@ -329,7 +401,9 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env) return tcg_code_gen_epilogue; } - log_cpu_exec(pc, cpu, tb); + if (qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC)) { + log_cpu_exec(pc, cpu, tb); + } return tb->tc.ptr; } @@ -352,7 +426,9 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) TranslationBlock *last_tb; const void *tb_ptr = itb->tc.ptr; - log_cpu_exec(itb->pc, cpu, itb); + if (qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC)) { + log_cpu_exec(log_pc(cpu, itb), cpu, itb); + } qemu_thread_jit_execute(); ret = tcg_qemu_tb_exec(env, tb_ptr); @@ -376,16 +452,21 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) * of the start of the TB. */ CPUClass *cc = CPU_GET_CLASS(cpu); - qemu_log_mask_and_addr(CPU_LOG_EXEC, last_tb->pc, - "Stopped execution of TB chain before %p [" - TARGET_FMT_lx "] %s\n", - last_tb->tc.ptr, last_tb->pc, - lookup_symbol(last_tb->pc)); + if (cc->tcg_ops->synchronize_from_tb) { cc->tcg_ops->synchronize_from_tb(cpu, last_tb); } else { + assert(!TARGET_TB_PCREL); assert(cc->set_pc); - cc->set_pc(cpu, last_tb->pc); + cc->set_pc(cpu, tb_pc(last_tb)); + } + if (qemu_loglevel_mask(CPU_LOG_EXEC)) { + target_ulong pc = log_pc(cpu, last_tb); + if (qemu_log_in_addr_range(pc)) { + qemu_log("Stopped execution of TB chain before %p [" + TARGET_FMT_lx "] %s\n", + last_tb->tc.ptr, pc, lookup_symbol(pc)); + } } } @@ -462,13 +543,11 @@ void cpu_exec_step_atomic(CPUState *cpu) cpu_tb_exec(cpu, tb, &tb_exit); cpu_exec_exit(cpu); } else { - /* - * The mmap_lock is dropped by tb_gen_code if it runs out of - * memory. - */ #ifndef CONFIG_SOFTMMU clear_helper_retaddr(); - tcg_debug_assert(!have_mmap_lock()); + if (have_mmap_lock()) { + mmap_unlock(); + } #endif if (qemu_mutex_iothread_locked()) { qemu_mutex_unlock_iothread(); @@ -487,67 +566,6 @@ void cpu_exec_step_atomic(CPUState *cpu) end_exclusive(); } -struct tb_desc { - target_ulong pc; - target_ulong cs_base; - CPUArchState *env; - tb_page_addr_t phys_page1; - uint32_t flags; - uint32_t cflags; - uint32_t trace_vcpu_dstate; -}; - -static bool tb_lookup_cmp(const void *p, const void *d) -{ - const TranslationBlock *tb = p; - const struct tb_desc *desc = d; - - if (tb->pc == desc->pc && - tb->page_addr[0] == desc->phys_page1 && - tb->cs_base == desc->cs_base && - tb->flags == desc->flags && - tb->trace_vcpu_dstate == desc->trace_vcpu_dstate && - tb_cflags(tb) == desc->cflags) { - /* check next page if needed */ - if (tb->page_addr[1] == -1) { - return true; - } else { - tb_page_addr_t phys_page2; - target_ulong virt_page2; - - virt_page2 = (desc->pc & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; - phys_page2 = get_page_addr_code(desc->env, virt_page2); - if (tb->page_addr[1] == phys_page2) { - return true; - } - } - } - return false; -} - -TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc, - target_ulong cs_base, uint32_t flags, - uint32_t cflags) -{ - tb_page_addr_t phys_pc; - struct tb_desc desc; - uint32_t h; - - desc.env = cpu->env_ptr; - desc.cs_base = cs_base; - desc.flags = flags; - desc.cflags = cflags; - desc.trace_vcpu_dstate = *cpu->trace_dstate; - desc.pc = pc; - phys_pc = get_page_addr_code(desc.env, pc); - if (phys_pc == -1) { - return NULL; - } - desc.phys_page1 = phys_pc & TARGET_PAGE_MASK; - h = tb_hash_func(phys_pc, pc, flags, cflags, *cpu->trace_dstate); - return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp); -} - void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr) { if (TCG_TARGET_HAS_direct_jump) { @@ -590,11 +608,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, qemu_spin_unlock(&tb_next->jmp_lock); - qemu_log_mask_and_addr(CPU_LOG_EXEC, tb->pc, - "Linking TBs %p [" TARGET_FMT_lx - "] index %d -> %p [" TARGET_FMT_lx "]\n", - tb->tc.ptr, tb->pc, n, - tb_next->tc.ptr, tb_next->pc); + qemu_log_mask(CPU_LOG_EXEC, "Linking TBs %p index %d -> %p\n", + tb->tc.ptr, n, tb_next->tc.ptr); return; out_unlock_next: @@ -852,11 +867,12 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, } static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, + target_ulong pc, TranslationBlock **last_tb, int *tb_exit) { int32_t insns_left; - trace_exec_tb(tb, tb->pc); + trace_exec_tb(tb, pc); tb = cpu_tb_exec(cpu, tb, tb_exit); if (*tb_exit != TB_EXIT_REQUESTED) { *last_tb = tb; @@ -964,7 +980,9 @@ int cpu_exec(CPUState *cpu) #ifndef CONFIG_SOFTMMU clear_helper_retaddr(); - tcg_debug_assert(!have_mmap_lock()); + if (have_mmap_lock()) { + mmap_unlock(); + } #endif if (qemu_mutex_iothread_locked()) { qemu_mutex_unlock_iothread(); @@ -1006,6 +1024,8 @@ int cpu_exec(CPUState *cpu) tb = tb_lookup(cpu, pc, cs_base, flags, cflags); if (tb == NULL) { + uint32_t h; + mmap_lock(); tb = tb_gen_code(cpu, pc, cs_base, flags, cflags); mmap_unlock(); @@ -1013,7 +1033,8 @@ int cpu_exec(CPUState *cpu) * We add the TB in the virtual pc hash table * for the fast lookup */ - qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb); + h = tb_jmp_cache_hash_func(pc); + tb_jmp_cache_set(cpu->tb_jmp_cache, h, tb, pc); } #ifndef CONFIG_USER_ONLY @@ -1052,7 +1073,7 @@ int cpu_exec(CPUState *cpu) //// --- End LibAFL code --- } - cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit); + cpu_loop_exec_tb(cpu, tb, pc, &last_tb, &tb_exit); /* Try to align the host and virtual clocks if the guest is in advance */ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index a46f3a654d..6f1c00682b 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -100,21 +100,14 @@ static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns, static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr) { - unsigned int i, i0 = tb_jmp_cache_hash_page(page_addr); + int i, i0 = tb_jmp_cache_hash_page(page_addr); + CPUJumpCache *jc = cpu->tb_jmp_cache; for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { - qatomic_set(&cpu->tb_jmp_cache[i0 + i], NULL); + qatomic_set(&jc->array[i0 + i].tb, NULL); } } -static void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr) -{ - /* Discard jump cache entries for any tb which might potentially - overlap the flushed page. */ - tb_jmp_cache_clear_page(cpu, addr - TARGET_PAGE_SIZE); - tb_jmp_cache_clear_page(cpu, addr); -} - /** * tlb_mmu_resize_locked() - perform TLB resize bookkeeping; resize if necessary * @desc: The CPUTLBDesc portion of the TLB @@ -200,13 +193,13 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast, } g_free(fast->table); - g_free(desc->iotlb); + g_free(desc->fulltlb); tlb_window_reset(desc, now, 0); /* desc->n_used_entries is cleared by the caller */ fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS; fast->table = g_try_new(CPUTLBEntry, new_size); - desc->iotlb = g_try_new(CPUIOTLBEntry, new_size); + desc->fulltlb = g_try_new(CPUTLBEntryFull, new_size); /* * If the allocations fail, try smaller sizes. We just freed some @@ -215,7 +208,7 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast, * allocations to fail though, so we progressively reduce the allocation * size, aborting if we cannot even allocate the smallest TLB we support. */ - while (fast->table == NULL || desc->iotlb == NULL) { + while (fast->table == NULL || desc->fulltlb == NULL) { if (new_size == (1 << CPU_TLB_DYN_MIN_BITS)) { error_report("%s: %s", __func__, strerror(errno)); abort(); @@ -224,9 +217,9 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast, fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS; g_free(fast->table); - g_free(desc->iotlb); + g_free(desc->fulltlb); fast->table = g_try_new(CPUTLBEntry, new_size); - desc->iotlb = g_try_new(CPUIOTLBEntry, new_size); + desc->fulltlb = g_try_new(CPUTLBEntryFull, new_size); } } @@ -258,7 +251,7 @@ static void tlb_mmu_init(CPUTLBDesc *desc, CPUTLBDescFast *fast, int64_t now) desc->n_used_entries = 0; fast->mask = (n_entries - 1) << CPU_TLB_ENTRY_BITS; fast->table = g_new(CPUTLBEntry, n_entries); - desc->iotlb = g_new(CPUIOTLBEntry, n_entries); + desc->fulltlb = g_new(CPUTLBEntryFull, n_entries); tlb_mmu_flush_locked(desc, fast); } @@ -299,7 +292,7 @@ void tlb_destroy(CPUState *cpu) CPUTLBDescFast *fast = &env_tlb(env)->f[i]; g_free(fast->table); - g_free(desc->iotlb); + g_free(desc->fulltlb); } } @@ -364,7 +357,7 @@ static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) qemu_spin_unlock(&env_tlb(env)->c.lock); - cpu_tb_jmp_cache_clear(cpu); + tcg_flush_jmp_cache(cpu); if (to_clean == ALL_MMUIDX_BITS) { qatomic_set(&env_tlb(env)->c.full_flush_count, @@ -541,7 +534,12 @@ static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, } qemu_spin_unlock(&env_tlb(env)->c.lock); - tb_flush_jmp_cache(cpu, addr); + /* + * Discard jump cache entries for any tb which might potentially + * overlap the flushed page, which includes the previous. + */ + tb_jmp_cache_clear_page(cpu, addr - TARGET_PAGE_SIZE); + tb_jmp_cache_clear_page(cpu, addr); } /** @@ -788,12 +786,18 @@ static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, * longer to clear each entry individually than it will to clear it all. */ if (d.len >= (TARGET_PAGE_SIZE * TB_JMP_CACHE_SIZE)) { - cpu_tb_jmp_cache_clear(cpu); + tcg_flush_jmp_cache(cpu); return; } - for (target_ulong i = 0; i < d.len; i += TARGET_PAGE_SIZE) { - tb_flush_jmp_cache(cpu, d.addr + i); + /* + * Discard jump cache entries for any tb which might potentially + * overlap the flushed pages, which includes the previous. + */ + d.addr -= TARGET_PAGE_SIZE; + for (target_ulong i = 0, n = d.len / TARGET_PAGE_SIZE + 1; i < n; i++) { + tb_jmp_cache_clear_page(cpu, d.addr); + d.addr += TARGET_PAGE_SIZE; } } @@ -951,7 +955,8 @@ void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *src_cpu, can be detected */ void tlb_protect_code(ram_addr_t ram_addr) { - cpu_physical_memory_test_and_clear_dirty(ram_addr, TARGET_PAGE_SIZE, + cpu_physical_memory_test_and_clear_dirty(ram_addr & TARGET_PAGE_MASK, + TARGET_PAGE_SIZE, DIRTY_MEMORY_CODE); } @@ -1095,16 +1100,16 @@ static void tlb_add_large_page(CPUArchState *env, int mmu_idx, env_tlb(env)->d[mmu_idx].large_page_mask = lp_mask; } -/* Add a new TLB entry. At most one entry for a given virtual address +/* + * Add a new TLB entry. At most one entry for a given virtual address * is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the * supplied size is only used by tlb_flush_page. * * Called from TCG-generated code, which is under an RCU read-side * critical section. */ -void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, - hwaddr paddr, MemTxAttrs attrs, int prot, - int mmu_idx, target_ulong size) +void tlb_set_page_full(CPUState *cpu, int mmu_idx, + target_ulong vaddr, CPUTLBEntryFull *full) { CPUArchState *env = cpu->env_ptr; CPUTLB *tlb = env_tlb(env); @@ -1117,35 +1122,36 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, CPUTLBEntry *te, tn; hwaddr iotlb, xlat, sz, paddr_page; target_ulong vaddr_page; - int asidx = cpu_asidx_from_attrs(cpu, attrs); - int wp_flags; + int asidx, wp_flags, prot; bool is_ram, is_romd; assert_cpu_is_self(cpu); - if (size <= TARGET_PAGE_SIZE) { + if (full->lg_page_size <= TARGET_PAGE_BITS) { sz = TARGET_PAGE_SIZE; } else { - tlb_add_large_page(env, mmu_idx, vaddr, size); - sz = size; + sz = (hwaddr)1 << full->lg_page_size; + tlb_add_large_page(env, mmu_idx, vaddr, sz); } vaddr_page = vaddr & TARGET_PAGE_MASK; - paddr_page = paddr & TARGET_PAGE_MASK; + paddr_page = full->phys_addr & TARGET_PAGE_MASK; + prot = full->prot; + asidx = cpu_asidx_from_attrs(cpu, full->attrs); section = address_space_translate_for_iotlb(cpu, asidx, paddr_page, - &xlat, &sz, attrs, &prot); + &xlat, &sz, full->attrs, &prot); assert(sz >= TARGET_PAGE_SIZE); tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx " prot=%x idx=%d\n", - vaddr, paddr, prot, mmu_idx); + vaddr, full->phys_addr, prot, mmu_idx); address = vaddr_page; - if (size < TARGET_PAGE_SIZE) { + if (full->lg_page_size < TARGET_PAGE_BITS) { /* Repeat the MMU check and TLB fill on every access. */ address |= TLB_INVALID_MASK; } - if (attrs.byte_swap) { + if (full->attrs.byte_swap) { address |= TLB_BSWAP; } @@ -1219,7 +1225,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, /* Evict the old entry into the victim tlb. */ copy_tlb_helper_locked(tv, te); - desc->viotlb[vidx] = desc->iotlb[index]; + desc->vfulltlb[vidx] = desc->fulltlb[index]; tlb_n_used_entries_dec(env, mmu_idx); } @@ -1236,8 +1242,10 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, * subtract here is that of the page base, and not the same as the * vaddr we add back in io_readx()/io_writex()/get_page_addr_code(). */ - desc->iotlb[index].addr = iotlb - vaddr_page; - desc->iotlb[index].attrs = attrs; + desc->fulltlb[index] = *full; + desc->fulltlb[index].xlat_section = iotlb - vaddr_page; + desc->fulltlb[index].phys_addr = paddr_page; + desc->fulltlb[index].prot = prot; /* Now calculate the new entry */ tn.addend = addend - vaddr_page; @@ -1272,9 +1280,21 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, qemu_spin_unlock(&tlb->c.lock); } -/* Add a new TLB entry, but without specifying the memory - * transaction attributes to be used. - */ +void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, + hwaddr paddr, MemTxAttrs attrs, int prot, + int mmu_idx, target_ulong size) +{ + CPUTLBEntryFull full = { + .phys_addr = paddr, + .attrs = attrs, + .prot = prot, + .lg_page_size = ctz64(size) + }; + + assert(is_power_of_2(size)); + tlb_set_page_full(cpu, mmu_idx, vaddr, &full); +} + void tlb_set_page(CPUState *cpu, target_ulong vaddr, hwaddr paddr, int prot, int mmu_idx, target_ulong size) @@ -1283,18 +1303,6 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr, prot, mmu_idx, size); } -static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr) -{ - ram_addr_t ram_addr; - - ram_addr = qemu_ram_addr_from_host(ptr); - if (ram_addr == RAM_ADDR_INVALID) { - error_report("Bad ram pointer %p", ptr); - abort(); - } - return ram_addr; -} - /* * Note: tlb_fill() can trigger a resize of the TLB. This means that all of the * caller's prior references to the TLB table (e.g. CPUTLBEntry pointers) must @@ -1303,15 +1311,14 @@ static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr) static void tlb_fill(CPUState *cpu, target_ulong addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { - CPUClass *cc = CPU_GET_CLASS(cpu); bool ok; /* * This is not a probe, so only valid return is success; failure * should result in exception + longjmp to the cpu loop. */ - ok = cc->tcg_ops->tlb_fill(cpu, addr, size, - access_type, mmu_idx, false, retaddr); + ok = cpu->cc->tcg_ops->tlb_fill(cpu, addr, size, + access_type, mmu_idx, false, retaddr); assert(ok); } @@ -1319,9 +1326,8 @@ static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { - CPUClass *cc = CPU_GET_CLASS(cpu); - - cc->tcg_ops->do_unaligned_access(cpu, addr, access_type, mmu_idx, retaddr); + cpu->cc->tcg_ops->do_unaligned_access(cpu, addr, access_type, + mmu_idx, retaddr); } static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr, @@ -1341,7 +1347,7 @@ static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr, } } -static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, +static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, int mmu_idx, target_ulong addr, uintptr_t retaddr, MMUAccessType access_type, MemOp op) { @@ -1353,9 +1359,9 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, bool locked = false; MemTxResult r; - section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); + section = iotlb_to_section(cpu, full->xlat_section, full->attrs); mr = section->mr; - mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; + mr_offset = (full->xlat_section & TARGET_PAGE_MASK) + addr; cpu->mem_io_pc = retaddr; if (!cpu->can_do_io) { cpu_io_recompile(cpu, retaddr); @@ -1365,14 +1371,14 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, qemu_mutex_lock_iothread(); locked = true; } - r = memory_region_dispatch_read(mr, mr_offset, &val, op, iotlbentry->attrs); + r = memory_region_dispatch_read(mr, mr_offset, &val, op, full->attrs); if (r != MEMTX_OK) { hwaddr physaddr = mr_offset + section->offset_within_address_space - section->offset_within_region; cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), access_type, - mmu_idx, iotlbentry->attrs, r, retaddr); + mmu_idx, full->attrs, r, retaddr); } if (locked) { qemu_mutex_unlock_iothread(); @@ -1382,22 +1388,21 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, } /* - * Save a potentially trashed IOTLB entry for later lookup by plugin. - * This is read by tlb_plugin_lookup if the iotlb entry doesn't match + * Save a potentially trashed CPUTLBEntryFull for later lookup by plugin. + * This is read by tlb_plugin_lookup if the fulltlb entry doesn't match * because of the side effect of io_writex changing memory layout. */ -static void save_iotlb_data(CPUState *cs, hwaddr addr, - MemoryRegionSection *section, hwaddr mr_offset) +static void save_iotlb_data(CPUState *cs, MemoryRegionSection *section, + hwaddr mr_offset) { #ifdef CONFIG_PLUGIN SavedIOTLB *saved = &cs->saved_iotlb; - saved->addr = addr; saved->section = section; saved->mr_offset = mr_offset; #endif } -static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, +static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, int mmu_idx, uint64_t val, target_ulong addr, uintptr_t retaddr, MemOp op) { @@ -1408,9 +1413,9 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, bool locked = false; MemTxResult r; - section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); + section = iotlb_to_section(cpu, full->xlat_section, full->attrs); mr = section->mr; - mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; + mr_offset = (full->xlat_section & TARGET_PAGE_MASK) + addr; if (!cpu->can_do_io) { cpu_io_recompile(cpu, retaddr); } @@ -1420,20 +1425,20 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, * The memory_region_dispatch may trigger a flush/resize * so for plugins we save the iotlb_data just in case. */ - save_iotlb_data(cpu, iotlbentry->addr, section, mr_offset); + save_iotlb_data(cpu, section, mr_offset); if (!qemu_mutex_iothread_locked()) { qemu_mutex_lock_iothread(); locked = true; } - r = memory_region_dispatch_write(mr, mr_offset, val, op, iotlbentry->attrs); + r = memory_region_dispatch_write(mr, mr_offset, val, op, full->attrs); if (r != MEMTX_OK) { hwaddr physaddr = mr_offset + section->offset_within_address_space - section->offset_within_region; cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), - MMU_DATA_STORE, mmu_idx, iotlbentry->attrs, r, + MMU_DATA_STORE, mmu_idx, full->attrs, r, retaddr); } if (locked) { @@ -1480,9 +1485,10 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, copy_tlb_helper_locked(vtlb, &tmptlb); qemu_spin_unlock(&env_tlb(env)->c.lock); - CPUIOTLBEntry tmpio, *io = &env_tlb(env)->d[mmu_idx].iotlb[index]; - CPUIOTLBEntry *vio = &env_tlb(env)->d[mmu_idx].viotlb[vidx]; - tmpio = *io; *io = *vio; *vio = tmpio; + CPUTLBEntryFull *f1 = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + CPUTLBEntryFull *f2 = &env_tlb(env)->d[mmu_idx].vfulltlb[vidx]; + CPUTLBEntryFull tmpf; + tmpf = *f1; *f1 = *f2; *f2 = tmpf; return true; } } @@ -1494,65 +1500,10 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \ (ADDR) & TARGET_PAGE_MASK) -/* - * Return a ram_addr_t for the virtual address for execution. - * - * Return -1 if we can't translate and execute from an entire page - * of RAM. This will force us to execute by loading and translating - * one insn at a time, without caching. - * - * NOTE: This function will trigger an exception if the page is - * not executable. - */ -tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, - void **hostp) -{ - uintptr_t mmu_idx = cpu_mmu_index(env, true); - uintptr_t index = tlb_index(env, mmu_idx, addr); - CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); - void *p; - - if (unlikely(!tlb_hit(entry->addr_code, addr))) { - if (!VICTIM_TLB_HIT(addr_code, addr)) { - tlb_fill(env_cpu(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0); - index = tlb_index(env, mmu_idx, addr); - entry = tlb_entry(env, mmu_idx, addr); - - if (unlikely(entry->addr_code & TLB_INVALID_MASK)) { - /* - * The MMU protection covers a smaller range than a target - * page, so we must redo the MMU check for every insn. - */ - return -1; - } - } - assert(tlb_hit(entry->addr_code, addr)); - } - - if (unlikely(entry->addr_code & TLB_MMIO)) { - /* The region is not backed by RAM. */ - if (hostp) { - *hostp = NULL; - } - return -1; - } - - p = (void *)((uintptr_t)addr + entry->addend); - if (hostp) { - *hostp = p; - } - return qemu_ram_addr_from_host_nofail(p); -} - -tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) -{ - return get_page_addr_code_hostp(env, addr, NULL); -} - static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, - CPUIOTLBEntry *iotlbentry, uintptr_t retaddr) + CPUTLBEntryFull *full, uintptr_t retaddr) { - ram_addr_t ram_addr = mem_vaddr + iotlbentry->addr; + ram_addr_t ram_addr = mem_vaddr + full->xlat_section; trace_memory_notdirty_write_access(mem_vaddr, ram_addr, size); @@ -1579,7 +1530,8 @@ static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, static int probe_access_internal(CPUArchState *env, target_ulong addr, int fault_size, MMUAccessType access_type, int mmu_idx, bool nonfault, - void **phost, uintptr_t retaddr) + void **phost, CPUTLBEntryFull **pfull, + uintptr_t retaddr) { uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); @@ -1602,25 +1554,36 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr, } tlb_addr = tlb_read_ofs(entry, elt_ofs); + flags = TLB_FLAGS_MASK; page_addr = addr & TARGET_PAGE_MASK; if (!tlb_hit_page(tlb_addr, page_addr)) { if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page_addr)) { CPUState *cs = env_cpu(env); - CPUClass *cc = CPU_GET_CLASS(cs); - if (!cc->tcg_ops->tlb_fill(cs, addr, fault_size, access_type, - mmu_idx, nonfault, retaddr)) { + if (!cs->cc->tcg_ops->tlb_fill(cs, addr, fault_size, access_type, + mmu_idx, nonfault, retaddr)) { /* Non-faulting page table read failed. */ *phost = NULL; + *pfull = NULL; return TLB_INVALID_MASK; } /* TLB resize via tlb_fill may have moved the entry. */ + index = tlb_index(env, mmu_idx, addr); entry = tlb_entry(env, mmu_idx, addr); + + /* + * With PAGE_WRITE_INV, we set TLB_INVALID_MASK immediately, + * to force the next access through tlb_fill. We've just + * called tlb_fill, so we know that this entry *is* valid. + */ + flags &= ~TLB_INVALID_MASK; } tlb_addr = tlb_read_ofs(entry, elt_ofs); } - flags = tlb_addr & TLB_FLAGS_MASK; + flags &= tlb_addr; + + *pfull = &env_tlb(env)->d[mmu_idx].fulltlb[index]; /* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */ if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) { @@ -1633,37 +1596,44 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr, return flags; } -int probe_access_flags(CPUArchState *env, target_ulong addr, - MMUAccessType access_type, int mmu_idx, - bool nonfault, void **phost, uintptr_t retaddr) +int probe_access_full(CPUArchState *env, target_ulong addr, + MMUAccessType access_type, int mmu_idx, + bool nonfault, void **phost, CPUTLBEntryFull **pfull, + uintptr_t retaddr) { - int flags; - - flags = probe_access_internal(env, addr, 0, access_type, mmu_idx, - nonfault, phost, retaddr); + int flags = probe_access_internal(env, addr, 0, access_type, mmu_idx, + nonfault, phost, pfull, retaddr); /* Handle clean RAM pages. */ if (unlikely(flags & TLB_NOTDIRTY)) { - uintptr_t index = tlb_index(env, mmu_idx, addr); - CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; - - notdirty_write(env_cpu(env), addr, 1, iotlbentry, retaddr); + notdirty_write(env_cpu(env), addr, 1, *pfull, retaddr); flags &= ~TLB_NOTDIRTY; } return flags; } +int probe_access_flags(CPUArchState *env, target_ulong addr, + MMUAccessType access_type, int mmu_idx, + bool nonfault, void **phost, uintptr_t retaddr) +{ + CPUTLBEntryFull *full; + + return probe_access_full(env, addr, access_type, mmu_idx, + nonfault, phost, &full, retaddr); +} + void *probe_access(CPUArchState *env, target_ulong addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { + CPUTLBEntryFull *full; void *host; int flags; g_assert(-(addr | TARGET_PAGE_MASK) >= size); flags = probe_access_internal(env, addr, size, access_type, mmu_idx, - false, &host, retaddr); + false, &host, &full, retaddr); /* Per the interface, size == 0 merely faults the access. */ if (size == 0) { @@ -1671,20 +1641,17 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, } if (unlikely(flags & (TLB_NOTDIRTY | TLB_WATCHPOINT))) { - uintptr_t index = tlb_index(env, mmu_idx, addr); - CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; - /* Handle watchpoints. */ if (flags & TLB_WATCHPOINT) { int wp_access = (access_type == MMU_DATA_STORE ? BP_MEM_WRITE : BP_MEM_READ); cpu_check_watchpoint(env_cpu(env), addr, size, - iotlbentry->attrs, wp_access, retaddr); + full->attrs, wp_access, retaddr); } /* Handle clean RAM pages. */ if (flags & TLB_NOTDIRTY) { - notdirty_write(env_cpu(env), addr, 1, iotlbentry, retaddr); + notdirty_write(env_cpu(env), addr, 1, full, retaddr); } } @@ -1694,16 +1661,44 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, MMUAccessType access_type, int mmu_idx) { + CPUTLBEntryFull *full; void *host; int flags; flags = probe_access_internal(env, addr, 0, access_type, - mmu_idx, true, &host, 0); + mmu_idx, true, &host, &full, 0); /* No combination of flags are expected by the caller. */ return flags ? NULL : host; } +/* + * Return a ram_addr_t for the virtual address for execution. + * + * Return -1 if we can't translate and execute from an entire page + * of RAM. This will force us to execute by loading and translating + * one insn at a time, without caching. + * + * NOTE: This function will trigger an exception if the page is + * not executable. + */ +tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, + void **hostp) +{ + CPUTLBEntryFull *full; + void *p; + + (void)probe_access_internal(env, addr, 1, MMU_INST_FETCH, + cpu_mmu_index(env, true), false, &p, &full, 0); + if (p == NULL) { + return -1; + } + if (hostp) { + *hostp = p; + } + return qemu_ram_addr_from_host_nofail(p); +} + #ifdef CONFIG_PLUGIN /* * Perform a TLB lookup and populate the qemu_plugin_hwaddr structure. @@ -1715,7 +1710,7 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, * should have just filled the TLB. The one corner case is io_writex * which can cause TLB flushes and potential resizing of the TLBs * losing the information we need. In those cases we need to recover - * data from a copy of the iotlbentry. As long as this always occurs + * data from a copy of the CPUTLBEntryFull. As long as this always occurs * from the same thread (which a mem callback will be) this is safe. */ @@ -1730,11 +1725,12 @@ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, if (likely(tlb_hit(tlb_addr, addr))) { /* We must have an iotlb entry for MMIO */ if (tlb_addr & TLB_MMIO) { - CPUIOTLBEntry *iotlbentry; - iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; + CPUTLBEntryFull *full; + full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; data->is_io = true; - data->v.io.section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); - data->v.io.offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; + data->v.io.section = + iotlb_to_section(cpu, full->xlat_section, full->attrs); + data->v.io.offset = (full->xlat_section & TARGET_PAGE_MASK) + addr; } else { data->is_io = false; data->v.ram.hostaddr = (void *)((uintptr_t)addr + tlbe->addend); @@ -1842,7 +1838,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, if (unlikely(tlb_addr & TLB_NOTDIRTY)) { notdirty_write(env_cpu(env), addr, size, - &env_tlb(env)->d[mmu_idx].iotlb[index], retaddr); + &env_tlb(env)->d[mmu_idx].fulltlb[index], retaddr); } return hostaddr; @@ -1950,7 +1946,7 @@ load_helper(CPUArchState *env, target_ulong addr, MemOpIdx oi, /* Handle anything that isn't just a straight memory access. */ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { - CPUIOTLBEntry *iotlbentry; + CPUTLBEntryFull *full; bool need_swap; /* For anything that is unaligned, recurse through full_load. */ @@ -1958,20 +1954,20 @@ load_helper(CPUArchState *env, target_ulong addr, MemOpIdx oi, goto do_unaligned_access; } - iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; + full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; /* Handle watchpoints. */ if (unlikely(tlb_addr & TLB_WATCHPOINT)) { /* On watchpoint hit, this will longjmp out. */ cpu_check_watchpoint(env_cpu(env), addr, size, - iotlbentry->attrs, BP_MEM_READ, retaddr); + full->attrs, BP_MEM_READ, retaddr); } need_swap = size > 1 && (tlb_addr & TLB_BSWAP); /* Handle I/O access. */ if (likely(tlb_addr & TLB_MMIO)) { - return io_readx(env, iotlbentry, mmu_idx, addr, retaddr, + return io_readx(env, full, mmu_idx, addr, retaddr, access_type, op ^ (need_swap * MO_BSWAP)); } @@ -2286,12 +2282,12 @@ store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val, */ if (unlikely(tlb_addr & TLB_WATCHPOINT)) { cpu_check_watchpoint(env_cpu(env), addr, size - size2, - env_tlb(env)->d[mmu_idx].iotlb[index].attrs, + env_tlb(env)->d[mmu_idx].fulltlb[index].attrs, BP_MEM_WRITE, retaddr); } if (unlikely(tlb_addr2 & TLB_WATCHPOINT)) { cpu_check_watchpoint(env_cpu(env), page2, size2, - env_tlb(env)->d[mmu_idx].iotlb[index2].attrs, + env_tlb(env)->d[mmu_idx].fulltlb[index2].attrs, BP_MEM_WRITE, retaddr); } @@ -2355,7 +2351,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, /* Handle anything that isn't just a straight memory access. */ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { - CPUIOTLBEntry *iotlbentry; + CPUTLBEntryFull *full; bool need_swap; /* For anything that is unaligned, recurse through byte stores. */ @@ -2363,20 +2359,20 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, goto do_unaligned_access; } - iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; + full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; /* Handle watchpoints. */ if (unlikely(tlb_addr & TLB_WATCHPOINT)) { /* On watchpoint hit, this will longjmp out. */ cpu_check_watchpoint(env_cpu(env), addr, size, - iotlbentry->attrs, BP_MEM_WRITE, retaddr); + full->attrs, BP_MEM_WRITE, retaddr); } need_swap = size > 1 && (tlb_addr & TLB_BSWAP); /* Handle I/O access. */ if (tlb_addr & TLB_MMIO) { - io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, + io_writex(env, full, mmu_idx, val, addr, retaddr, op ^ (need_swap * MO_BSWAP)); return; } @@ -2388,7 +2384,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, /* Handle clean RAM pages. */ if (tlb_addr & TLB_NOTDIRTY) { - notdirty_write(env_cpu(env), addr, size, iotlbentry, retaddr); + notdirty_write(env_cpu(env), addr, size, full, retaddr); } haddr = (void *)((uintptr_t)addr + entry->addend); diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h index 3092bfa964..dc800fd485 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal.h @@ -18,4 +18,14 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); void page_init(void); void tb_htable_init(void); +/* Return the current PC from CPU, which may be cached in TB. */ +static inline target_ulong log_pc(CPUState *cpu, const TranslationBlock *tb) +{ +#if TARGET_TB_PCREL + return cpu->cc->get_pc(cpu); +#else + return tb_pc(tb); +#endif +} + #endif /* ACCEL_TCG_INTERNAL_H */ diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index 3d0b101e34..80dff68934 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -852,7 +852,8 @@ static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb) pr_ops(); } -bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_only) +bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db, + bool mem_only) { bool ret = false; @@ -870,9 +871,9 @@ bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_onl ret = true; - ptb->vaddr = tb->pc; + ptb->vaddr = db->pc_first; ptb->vaddr2 = -1; - get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1); + ptb->haddr1 = db->host_addr[0]; ptb->haddr2 = NULL; ptb->mem_only = mem_only; @@ -898,16 +899,15 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db) * Note that we skip this when haddr1 == NULL, e.g. when we're * fetching instructions from a region not backed by RAM. */ - if (likely(ptb->haddr1 != NULL && ptb->vaddr2 == -1) && - unlikely((db->pc_next & TARGET_PAGE_MASK) != - (db->pc_first & TARGET_PAGE_MASK))) { - get_page_addr_code_hostp(cpu->env_ptr, db->pc_next, - &ptb->haddr2); - ptb->vaddr2 = db->pc_next; - } - if (likely(ptb->vaddr2 == -1)) { + if (ptb->haddr1 == NULL) { + pinsn->haddr = NULL; + } else if (is_same_page(db, db->pc_next)) { pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr; } else { + if (ptb->vaddr2 == -1) { + ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first); + get_page_addr_code_hostp(cpu->env_ptr, ptb->vaddr2, &ptb->haddr2); + } pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2; } } diff --git a/accel/tcg/tb-hash.h b/accel/tcg/tb-hash.h index 0a273d9605..83dc610e4c 100644 --- a/accel/tcg/tb-hash.h +++ b/accel/tcg/tb-hash.h @@ -23,6 +23,7 @@ #include "exec/cpu-defs.h" #include "exec/exec-all.h" #include "qemu/xxhash.h" +#include "tb-jmp-cache.h" #ifdef CONFIG_SOFTMMU diff --git a/accel/tcg/tb-jmp-cache.h b/accel/tcg/tb-jmp-cache.h new file mode 100644 index 0000000000..ff5ffc8fc2 --- /dev/null +++ b/accel/tcg/tb-jmp-cache.h @@ -0,0 +1,65 @@ +/* + * The per-CPU TranslationBlock jump cache. + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef ACCEL_TCG_TB_JMP_CACHE_H +#define ACCEL_TCG_TB_JMP_CACHE_H + +#define TB_JMP_CACHE_BITS 12 +#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) + +/* + * Accessed in parallel; all accesses to 'tb' must be atomic. + * For TARGET_TB_PCREL, accesses to 'pc' must be protected by + * a load_acquire/store_release to 'tb'. + */ +struct CPUJumpCache { + struct { + TranslationBlock *tb; +#if TARGET_TB_PCREL + target_ulong pc; +#endif + } array[TB_JMP_CACHE_SIZE]; +}; + +static inline TranslationBlock * +tb_jmp_cache_get_tb(CPUJumpCache *jc, uint32_t hash) +{ +#if TARGET_TB_PCREL + /* Use acquire to ensure current load of pc from jc. */ + return qatomic_load_acquire(&jc->array[hash].tb); +#else + /* Use rcu_read to ensure current load of pc from *tb. */ + return qatomic_rcu_read(&jc->array[hash].tb); +#endif +} + +static inline target_ulong +tb_jmp_cache_get_pc(CPUJumpCache *jc, uint32_t hash, TranslationBlock *tb) +{ +#if TARGET_TB_PCREL + return jc->array[hash].pc; +#else + return tb_pc(tb); +#endif +} + +static inline void +tb_jmp_cache_set(CPUJumpCache *jc, uint32_t hash, + TranslationBlock *tb, target_ulong pc) +{ +#if TARGET_TB_PCREL + jc->array[hash].pc = pc; + /* Use store_release on tb to ensure pc is written first. */ + qatomic_store_release(&jc->array[hash].tb, tb); +#else + /* Use the pc value already stored in tb->pc. */ + qatomic_set(&jc->array[hash].tb, tb); +#endif +} + +#endif /* ACCEL_TCG_TB_JMP_CACHE_H */ diff --git a/accel/tcg/tcg-accel-ops-icount.c b/accel/tcg/tcg-accel-ops-icount.c index 8f1dda4344..84cc7421be 100644 --- a/accel/tcg/tcg-accel-ops-icount.c +++ b/accel/tcg/tcg-accel-ops-icount.c @@ -109,7 +109,13 @@ void icount_prepare_for_run(CPUState *cpu) replay_mutex_lock(); if (cpu->icount_budget == 0) { + /* + * We're called without the iothread lock, so must take it while + * we're calling timer handlers. + */ + qemu_mutex_lock_iothread(); icount_notify_aio_contexts(); + qemu_mutex_unlock_iothread(); } } diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 786d90c08f..19cbf1db3a 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -32,6 +32,8 @@ #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "exec/exec-all.h" +#include "exec/hwaddr.h" +#include "exec/gdbstub.h" #include "tcg-accel-ops.h" #include "tcg-accel-ops-mttcg.h" @@ -91,6 +93,97 @@ void tcg_handle_interrupt(CPUState *cpu, int mask) } } +static bool tcg_supports_guest_debug(void) +{ + return true; +} + +/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */ +static inline int xlat_gdb_type(CPUState *cpu, int gdbtype) +{ + static const int xlat[] = { + [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, + [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ, + [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS, + }; + + CPUClass *cc = CPU_GET_CLASS(cpu); + int cputype = xlat[gdbtype]; + + if (cc->gdb_stop_before_watchpoint) { + cputype |= BP_STOP_BEFORE_ACCESS; + } + return cputype; +} + +static int tcg_insert_breakpoint(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + CPUState *cpu; + int err = 0; + + switch (type) { + case GDB_BREAKPOINT_SW: + case GDB_BREAKPOINT_HW: + CPU_FOREACH(cpu) { + err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL); + if (err) { + break; + } + } + return err; + case GDB_WATCHPOINT_WRITE: + case GDB_WATCHPOINT_READ: + case GDB_WATCHPOINT_ACCESS: + CPU_FOREACH(cpu) { + err = cpu_watchpoint_insert(cpu, addr, len, + xlat_gdb_type(cpu, type), NULL); + if (err) { + break; + } + } + return err; + default: + return -ENOSYS; + } +} + +static int tcg_remove_breakpoint(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + CPUState *cpu; + int err = 0; + + switch (type) { + case GDB_BREAKPOINT_SW: + case GDB_BREAKPOINT_HW: + CPU_FOREACH(cpu) { + err = cpu_breakpoint_remove(cpu, addr, BP_GDB); + if (err) { + break; + } + } + return err; + case GDB_WATCHPOINT_WRITE: + case GDB_WATCHPOINT_READ: + case GDB_WATCHPOINT_ACCESS: + CPU_FOREACH(cpu) { + err = cpu_watchpoint_remove(cpu, addr, len, + xlat_gdb_type(cpu, type)); + if (err) { + break; + } + } + return err; + default: + return -ENOSYS; + } +} + +static inline void tcg_remove_all_breakpoints(CPUState *cpu) +{ + cpu_breakpoint_remove_all(cpu, BP_GDB); + cpu_watchpoint_remove_all(cpu, BP_GDB); +} + static void tcg_accel_ops_init(AccelOpsClass *ops) { if (qemu_tcg_mttcg_enabled()) { @@ -109,6 +202,11 @@ static void tcg_accel_ops_init(AccelOpsClass *ops) ops->handle_interrupt = tcg_handle_interrupt; } } + + ops->supports_guest_debug = tcg_supports_guest_debug; + ops->insert_breakpoint = tcg_insert_breakpoint; + ops->remove_breakpoint = tcg_remove_breakpoint; + ops->remove_all_breakpoints = tcg_remove_all_breakpoints; } static void tcg_accel_ops_class_init(ObjectClass *oc, void *data) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 2eb56760f9..4cdf93b378 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "sysemu/tcg.h" +#include "sysemu/replay.h" #include "sysemu/cpu-timers.h" #include "tcg/tcg.h" #include "qapi/error.h" @@ -215,12 +216,28 @@ static void tcg_set_splitwx(Object *obj, bool value, Error **errp) s->splitwx_enabled = value; } +static int tcg_gdbstub_supported_sstep_flags(void) +{ + /* + * In replay mode all events will come from the log and can't be + * suppressed otherwise we would break determinism. However as those + * events are tied to the number of executed instructions we won't see + * them occurring every time we single step. + */ + if (replay_mode != REPLAY_MODE_NONE) { + return SSTEP_ENABLE; + } else { + return SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; + } +} + static void tcg_accel_class_init(ObjectClass *oc, void *data) { AccelClass *ac = ACCEL_CLASS(oc); ac->name = "tcg"; ac->init_machine = tcg_init_machine; ac->allowed = &tcg_allowed; + ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags; object_class_property_add_str(oc, "thread", tcg_get_thread, diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 81e665aeaa..40491b8025 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -46,6 +46,7 @@ #include "exec/cputlb.h" #include "exec/translate-all.h" +#include "exec/translator.h" #include "qemu/bitmap.h" #include "qemu/qemu-print.h" #include "qemu/timer.h" @@ -57,6 +58,7 @@ #include "sysemu/tcg.h" #include "qapi/error.h" #include "hw/core/tcg-cpu-ops.h" +#include "tb-jmp-cache.h" #include "tb-hash.h" #include "tb-context.h" #include "internal.h" @@ -730,21 +732,14 @@ void libafl_add_backdoor_hook(void (*exec)(target_ulong id, uint64_t data), #define assert_memory_lock() tcg_debug_assert(have_mmap_lock()) #endif -#define SMC_BITMAP_USE_THRESHOLD 10 - typedef struct PageDesc { /* list of TBs intersecting this ram page */ uintptr_t first_tb; -#ifdef CONFIG_SOFTMMU - /* in order to optimize self modifying code, we count the number - of lookups we do to a given page to use a bitmap */ - unsigned long *code_bitmap; - unsigned int code_write_count; -#else +#ifdef CONFIG_USER_ONLY unsigned long flags; void *target_data; #endif -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_SOFTMMU QemuSpin lock; #endif } PageDesc; @@ -933,7 +928,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block) for (j = 0; j < TARGET_INSN_START_WORDS; ++j) { if (i == 0) { - prev = (j == 0 ? tb->pc : 0); + prev = (!TARGET_TB_PCREL && j == 0 ? tb_pc(tb) : 0); } else { prev = tcg_ctx->gen_insn_data[i - 1][j]; } @@ -961,7 +956,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block) static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, uintptr_t searched_pc, bool reset_icount) { - target_ulong data[TARGET_INSN_START_WORDS] = { tb->pc }; + target_ulong data[TARGET_INSN_START_WORDS]; uintptr_t host_pc = (uintptr_t)tb->tc.ptr; CPUArchState *env = cpu->env_ptr; const uint8_t *p = tb->tc.ptr + tb->tc.size; @@ -977,6 +972,11 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, return -1; } + memset(data, 0, sizeof(data)); + if (!TARGET_TB_PCREL) { + data[0] = tb_pc(tb); + } + /* Reconstruct the stored insn data while looking for the point at which the end of the insn exceeds the searched_pc. */ for (i = 0; i < num_insns; ++i) { @@ -1100,7 +1100,7 @@ void page_init(void) #endif } -static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) +static PageDesc *page_find_alloc(tb_page_addr_t index, bool alloc) { PageDesc *pd; void **lp; @@ -1168,11 +1168,11 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) static inline PageDesc *page_find(tb_page_addr_t index) { - return page_find_alloc(index, 0); + return page_find_alloc(index, false); } static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1, - PageDesc **ret_p2, tb_page_addr_t phys2, int alloc); + PageDesc **ret_p2, tb_page_addr_t phys2, bool alloc); /* In user-mode page locks aren't used; mmap_lock is enough */ #ifdef CONFIG_USER_ONLY @@ -1286,7 +1286,7 @@ static inline void page_unlock(PageDesc *pd) /* lock the page(s) of a TB in the correct acquisition order */ static inline void page_lock_tb(const TranslationBlock *tb) { - page_lock_pair(NULL, tb->page_addr[0], NULL, tb->page_addr[1], 0); + page_lock_pair(NULL, tb->page_addr[0], NULL, tb->page_addr[1], false); } static inline void page_unlock_tb(const TranslationBlock *tb) @@ -1475,7 +1475,7 @@ void page_collection_unlock(struct page_collection *set) #endif /* !CONFIG_USER_ONLY */ static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1, - PageDesc **ret_p2, tb_page_addr_t phys2, int alloc) + PageDesc **ret_p2, tb_page_addr_t phys2, bool alloc) { PageDesc *p1, *p2; tb_page_addr_t page1; @@ -1519,13 +1519,13 @@ static bool tb_cmp(const void *ap, const void *bp) const TranslationBlock *a = ap; const TranslationBlock *b = bp; - return a->pc == b->pc && - a->cs_base == b->cs_base && - a->flags == b->flags && - (tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) && - a->trace_vcpu_dstate == b->trace_vcpu_dstate && - a->page_addr[0] == b->page_addr[0] && - a->page_addr[1] == b->page_addr[1]; + return ((TARGET_TB_PCREL || tb_pc(a) == tb_pc(b)) && + a->cs_base == b->cs_base && + a->flags == b->flags && + (tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) && + a->trace_vcpu_dstate == b->trace_vcpu_dstate && + a->page_addr[0] == b->page_addr[0] && + a->page_addr[1] == b->page_addr[1]); } void tb_htable_init(void) @@ -1535,17 +1535,6 @@ void tb_htable_init(void) qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode); } -/* call with @p->lock held */ -static inline void invalidate_page_bitmap(PageDesc *p) -{ - assert_page_locked(p); -#ifdef CONFIG_SOFTMMU - g_free(p->code_bitmap); - p->code_bitmap = NULL; - p->code_write_count = 0; -#endif -} - /* Set to NULL all the 'first_tb' fields in all PageDescs. */ static void page_flush_tb_1(int level, void **lp) { @@ -1560,7 +1549,6 @@ static void page_flush_tb_1(int level, void **lp) for (i = 0; i < V_L2_SIZE; ++i) { page_lock(&pd[i]); pd[i].first_tb = (uintptr_t)NULL; - invalidate_page_bitmap(pd + i); page_unlock(&pd[i]); } } else { @@ -1614,7 +1602,7 @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) } CPU_FOREACH(cpu) { - cpu_tb_jmp_cache_clear(cpu); + tcg_flush_jmp_cache(cpu); } qht_reset_size(&tb_ctx.htable, CODE_GEN_HTABLE_SIZE); @@ -1659,9 +1647,10 @@ static void do_tb_invalidate_check(void *p, uint32_t hash, void *userp) TranslationBlock *tb = p; target_ulong addr = *(target_ulong *)userp; - if (!(addr + TARGET_PAGE_SIZE <= tb->pc || addr >= tb->pc + tb->size)) { + if (!(addr + TARGET_PAGE_SIZE <= tb_pc(tb) || + addr >= tb_pc(tb) + tb->size)) { printf("ERROR invalidate: address=" TARGET_FMT_lx - " PC=%08lx size=%04x\n", addr, (long)tb->pc, tb->size); + " PC=%08lx size=%04x\n", addr, (long)tb_pc(tb), tb->size); } } @@ -1680,11 +1669,11 @@ static void do_tb_page_check(void *p, uint32_t hash, void *userp) TranslationBlock *tb = p; int flags1, flags2; - flags1 = page_get_flags(tb->pc); - flags2 = page_get_flags(tb->pc + tb->size - 1); + flags1 = page_get_flags(tb_pc(tb)); + flags2 = page_get_flags(tb_pc(tb) + tb->size - 1); if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n", - (long)tb->pc, tb->size, flags1, flags2); + (long)tb_pc(tb), tb->size, flags1, flags2); } } @@ -1793,6 +1782,28 @@ static inline void tb_jmp_unlink(TranslationBlock *dest) qemu_spin_unlock(&dest->jmp_lock); } +static void tb_jmp_cache_inval_tb(TranslationBlock *tb) +{ + CPUState *cpu; + + if (TARGET_TB_PCREL) { + /* A TB may be at any virtual address */ + CPU_FOREACH(cpu) { + tcg_flush_jmp_cache(cpu); + } + } else { + uint32_t h = tb_jmp_cache_hash_func(tb_pc(tb)); + + CPU_FOREACH(cpu) { + CPUJumpCache *jc = cpu->tb_jmp_cache; + + if (qatomic_read(&jc->array[h].tb) == tb) { + qatomic_set(&jc->array[h].tb, NULL); + } + } + } +} + /* * In user-mode, call with mmap_lock held. * In !user-mode, if @rm_from_page_list is set, call with the TB's pages' @@ -1800,7 +1811,6 @@ static inline void tb_jmp_unlink(TranslationBlock *dest) */ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) { - CPUState *cpu; PageDesc *p; uint32_t h; tb_page_addr_t phys_pc; @@ -1814,9 +1824,9 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) qemu_spin_unlock(&tb->jmp_lock); /* remove the TB from the hash list */ - phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); - h = tb_hash_func(phys_pc, tb->pc, tb->flags, orig_cflags, - tb->trace_vcpu_dstate); + phys_pc = tb->page_addr[0]; + h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : tb_pc(tb)), + tb->flags, orig_cflags, tb->trace_vcpu_dstate); if (!qht_remove(&tb_ctx.htable, tb, h)) { return; } @@ -1825,21 +1835,14 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) if (rm_from_page_list) { p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); tb_page_remove(p, tb); - invalidate_page_bitmap(p); if (tb->page_addr[1] != -1) { p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); tb_page_remove(p, tb); - invalidate_page_bitmap(p); } } /* remove the TB from the hash list */ - h = tb_jmp_cache_hash_func(tb->pc); - CPU_FOREACH(cpu) { - if (qatomic_read(&cpu->tb_jmp_cache[h]) == tb) { - qatomic_set(&cpu->tb_jmp_cache[h], NULL); - } - } + tb_jmp_cache_inval_tb(tb); /* suppress this TB from the two jump lists */ tb_remove_from_jmp_list(tb, 0); @@ -1874,35 +1877,6 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) } } -#ifdef CONFIG_SOFTMMU -/* call with @p->lock held */ -static void build_page_bitmap(PageDesc *p) -{ - int n, tb_start, tb_end; - TranslationBlock *tb; - - assert_page_locked(p); - p->code_bitmap = bitmap_new(TARGET_PAGE_SIZE); - - PAGE_FOR_EACH_TB(p, tb, n) { - /* NOTE: this is subtle as a TB may span two physical pages */ - if (n == 0) { - /* NOTE: tb_end may be after the end of the page, but - it is not a problem */ - tb_start = tb->pc & ~TARGET_PAGE_MASK; - tb_end = tb_start + tb->size; - if (tb_end > TARGET_PAGE_SIZE) { - tb_end = TARGET_PAGE_SIZE; - } - } else { - tb_start = 0; - tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); - } - bitmap_set(p->code_bitmap, tb_start, tb_end - tb_start); - } -} -#endif - /* add the tb in the target page and protect it if necessary * * Called with mmap_lock held for user-mode emulation. @@ -1923,7 +1897,6 @@ static inline void tb_page_add(PageDesc *p, TranslationBlock *tb, page_already_protected = p->first_tb != (uintptr_t)NULL; #endif p->first_tb = (uintptr_t)tb | n; - invalidate_page_bitmap(p); #if defined(CONFIG_USER_ONLY) /* translator_loop() must have made all TB pages non-writable */ @@ -1969,8 +1942,8 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, * Note that inserting into the hash table first isn't an option, since * we can only insert TBs that are fully initialized. */ - page_lock_pair(&p, phys_pc, &p2, phys_page2, 1); - tb_page_add(p, tb, 0, phys_pc & TARGET_PAGE_MASK); + page_lock_pair(&p, phys_pc, &p2, phys_page2, true); + tb_page_add(p, tb, 0, phys_pc); if (p2) { tb_page_add(p2, tb, 1, phys_page2); } else { @@ -1978,17 +1951,15 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, } /* add in the hash table */ - h = tb_hash_func(phys_pc, tb->pc, tb->flags, tb->cflags, - tb->trace_vcpu_dstate); + h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : tb_pc(tb)), + tb->flags, tb->cflags, tb->trace_vcpu_dstate); qht_insert(&tb_ctx.htable, tb, h, &existing_tb); /* remove TB from the page(s) if we couldn't insert it */ if (unlikely(existing_tb)) { tb_page_remove(p, tb); - invalidate_page_bitmap(p); if (p2) { tb_page_remove(p2, tb); - invalidate_page_bitmap(p2); } tb = existing_tb; } @@ -2202,19 +2173,19 @@ TranslationBlock *tb_gen_code(CPUState *cpu, { CPUArchState *env = cpu->env_ptr; TranslationBlock *tb, *existing_tb; - tb_page_addr_t phys_pc, phys_page2; - target_ulong virt_page2; + tb_page_addr_t phys_pc; tcg_insn_unit *gen_code_buf; int gen_code_size, search_size, max_insns; #ifdef CONFIG_PROFILER TCGProfile *prof = &tcg_ctx->prof; int64_t ti; #endif + void *host_pc; assert_memory_lock(); qemu_thread_jit_write(); - phys_pc = get_page_addr_code(env, pc); + phys_pc = get_page_addr_code_hostp(env, pc, &host_pc); if (phys_pc == -1) { /* Generate a one-shot TB with 1 insn in it */ @@ -2240,11 +2211,15 @@ TranslationBlock *tb_gen_code(CPUState *cpu, gen_code_buf = tcg_ctx->code_gen_ptr; tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf); +#if !TARGET_TB_PCREL tb->pc = pc; +#endif tb->cs_base = cs_base; tb->flags = flags; tb->cflags = cflags; tb->trace_vcpu_dstate = *cpu->trace_dstate; + tb->page_addr[0] = phys_pc; + tb->page_addr[1] = -1; tcg_ctx->tb_cflags = cflags; tb_overflow: @@ -2283,12 +2258,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu, //// --- End LibAFL code --- - gen_intermediate_code(cpu, tb, max_insns); + gen_intermediate_code(cpu, tb, max_insns, pc, host_pc); assert(tb->size != 0); tcg_ctx->cpu = NULL; max_insns = tb->icount; - trace_translate_block(tb, tb->pc, tb->tc.ptr); + trace_translate_block(tb, pc, tb->tc.ptr); /* generate machine code */ tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID; @@ -2309,7 +2284,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, ti = profile_getclock(); #endif - gen_code_size = tcg_gen_code(tcg_ctx, tb); + gen_code_size = tcg_gen_code(tcg_ctx, tb, pc); if (unlikely(gen_code_size < 0)) { error_return: switch (gen_code_size) { @@ -2365,7 +2340,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) && - qemu_log_in_addr_range(tb->pc)) { + qemu_log_in_addr_range(pc)) { FILE *logfile = qemu_log_trylock(); if (logfile) { int code_size, data_size; @@ -2459,13 +2434,11 @@ TranslationBlock *tb_gen_code(CPUState *cpu, } /* - * If the TB is not associated with a physical RAM page then - * it must be a temporary one-insn TB, and we have nothing to do - * except fill in the page_addr[] fields. Return early before - * attempting to link to other TBs or add to the lookup table. + * If the TB is not associated with a physical RAM page then it must be + * a temporary one-insn TB, and we have nothing left to do. Return early + * before attempting to link to other TBs or add to the lookup table. */ - if (phys_pc == -1) { - tb->page_addr[0] = tb->page_addr[1] = -1; + if (tb->page_addr[0] == -1) { return tb; } @@ -2476,17 +2449,11 @@ TranslationBlock *tb_gen_code(CPUState *cpu, */ tcg_tb_insert(tb); - /* check next page if needed */ - virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; - phys_page2 = -1; - if ((pc & TARGET_PAGE_MASK) != virt_page2) { - phys_page2 = get_page_addr_code(env, virt_page2); - } /* * No explicit memory barrier is required -- tb_link_page() makes the * TB visible in a consistent state. */ - existing_tb = tb_link_page(tb, phys_pc, phys_page2); + existing_tb = tb_link_page(tb, tb->page_addr[0], tb->page_addr[1]); /* if the TB already exists, discard what we just translated */ if (unlikely(existing_tb != tb)) { uintptr_t orig_aligned = (uintptr_t)gen_code_buf; @@ -2541,11 +2508,12 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages, if (n == 0) { /* NOTE: tb_end may be after the end of the page, but it is not a problem */ - tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + tb_start = tb->page_addr[0]; tb_end = tb_start + tb->size; } else { tb_start = tb->page_addr[1]; - tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); + tb_end = tb_start + ((tb->page_addr[0] + tb->size) + & ~TARGET_PAGE_MASK); } if (!(tb_end <= start || tb_start >= end)) { #ifdef TARGET_HAS_PRECISE_SMC @@ -2575,7 +2543,6 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages, #if !defined(CONFIG_USER_ONLY) /* if no code remaining, no need to continue to use slow writes */ if (!p->first_tb) { - invalidate_page_bitmap(p); tlb_unprotect_code(start); } #endif @@ -2671,24 +2638,8 @@ void tb_invalidate_phys_page_fast(struct page_collection *pages, } assert_page_locked(p); - if (!p->code_bitmap && - ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) { - build_page_bitmap(p); - } - if (p->code_bitmap) { - unsigned int nr; - unsigned long b; - - nr = start & ~TARGET_PAGE_MASK; - b = p->code_bitmap[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG - 1)); - if (b & ((1 << len) - 1)) { - goto do_invalidate; - } - } else { - do_invalidate: - tb_invalidate_phys_page_range__locked(pages, p, start, start + len, - retaddr); - } + tb_invalidate_phys_page_range__locked(pages, p, start, start + len, + retaddr); } #else /* Called with mmap_lock held. If pc is not 0 then it indicates the @@ -2829,9 +2780,13 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) */ cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | CF_LAST_IO | n; - qemu_log_mask_and_addr(CPU_LOG_EXEC, tb->pc, - "cpu_io_recompile: rewound execution of TB to " - TARGET_FMT_lx "\n", tb->pc); + if (qemu_loglevel_mask(CPU_LOG_EXEC)) { + target_ulong pc = log_pc(cpu, tb); + if (qemu_log_in_addr_range(pc)) { + qemu_log("cpu_io_recompile: rewound execution of TB to " + TARGET_FMT_lx "\n", pc); + } + } cpu_loop_exit_noexc(cpu); } @@ -3102,7 +3057,7 @@ int page_get_flags(target_ulong address) #ifndef PAGE_TARGET_STICKY #define PAGE_TARGET_STICKY 0 #endif -#define PAGE_STICKY (PAGE_ANON | PAGE_TARGET_STICKY) +#define PAGE_STICKY (PAGE_ANON | PAGE_PASSTHROUGH | PAGE_TARGET_STICKY) /* Modify the flags of a page and invalidate the code if necessary. The flag PAGE_WRITE_ORG is positioned automatically depending @@ -3133,7 +3088,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) for (addr = start, len = end - start; len != 0; len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { - PageDesc *p = page_find_alloc(addr >> TARGET_PAGE_BITS, 1); + PageDesc *p = page_find_alloc(addr >> TARGET_PAGE_BITS, true); /* If the write protection bit is set, then we invalidate the code inside. */ @@ -3153,6 +3108,32 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) } } +void page_reset_target_data(target_ulong start, target_ulong end) +{ + target_ulong addr, len; + + /* + * This function should never be called with addresses outside the + * guest address space. If this assert fires, it probably indicates + * a missing call to h2g_valid. + */ + assert(end - 1 <= GUEST_ADDR_MAX); + assert(start < end); + assert_memory_lock(); + + start = start & TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + + for (addr = start, len = end - start; + len != 0; + len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { + PageDesc *p = page_find_alloc(addr >> TARGET_PAGE_BITS, 1); + + g_free(p->target_data); + p->target_data = NULL; + } +} + void *page_get_target_data(target_ulong address) { PageDesc *p = page_find(address >> TARGET_PAGE_BITS); @@ -3330,6 +3311,26 @@ int page_unprotect(target_ulong address, uintptr_t pc) } #endif /* CONFIG_USER_ONLY */ +/* + * Called by generic code at e.g. cpu reset after cpu creation, + * therefore we must be prepared to allocate the jump cache. + */ +void tcg_flush_jmp_cache(CPUState *cpu) +{ + CPUJumpCache *jc = cpu->tb_jmp_cache; + + if (likely(jc)) { + for (int i = 0; i < TB_JMP_CACHE_SIZE; i++) { + qatomic_set(&jc->array[i].tb, NULL); + } + } else { + /* This should happen once during realize, and thus never race. */ + jc = g_new0(CPUJumpCache, 1); + jc = qatomic_xchg(&cpu->tb_jmp_cache, jc); + assert(jc == NULL); + } +} + /* This is a wrapper for common code that can not use CONFIG_SOFTMMU */ void tcg_flush_softmmu_tlb(CPUState *cs) { diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 3e2ce30f3a..0706b4517c 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -78,30 +78,27 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0; } -static inline void translator_page_protect(DisasContextBase *dcbase, - target_ulong pc) -{ -#ifdef CONFIG_USER_ONLY - dcbase->page_protect_end = pc | ~TARGET_PAGE_MASK; - page_protect(pc); -#endif -} - -void translator_loop(const TranslatorOps *ops, DisasContextBase *db, - CPUState *cpu, TranslationBlock *tb, int max_insns) +void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc, + const TranslatorOps *ops, DisasContextBase *db) { uint32_t cflags = tb_cflags(tb); bool plugin_enabled; /* Initialize DisasContext */ db->tb = tb; - db->pc_first = tb->pc; - db->pc_next = db->pc_first; + db->pc_first = pc; + db->pc_next = pc; db->is_jmp = DISAS_NEXT; db->num_insns = 0; db->max_insns = max_insns; db->singlestep_enabled = cflags & CF_SINGLE_STEP; - translator_page_protect(db, db->pc_next); + db->host_addr[0] = host_pc; + db->host_addr[1] = NULL; + +#ifdef CONFIG_USER_ONLY + page_protect(pc); +#endif ops->init_disas_context(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ @@ -114,7 +111,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, ops->tb_start(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ - plugin_enabled = plugin_gen_tb_start(cpu, tb, cflags & CF_MEMI_ONLY); + plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY); while (true) { db->num_insns++; @@ -255,31 +252,103 @@ post_translate_insn: #endif } -static inline void translator_maybe_page_protect(DisasContextBase *dcbase, - target_ulong pc, size_t len) +static void *translator_access(CPUArchState *env, DisasContextBase *db, + target_ulong pc, size_t len) { -#ifdef CONFIG_USER_ONLY - target_ulong end = pc + len - 1; + void *host; + target_ulong base, end; + TranslationBlock *tb; - if (end > dcbase->page_protect_end) { - translator_page_protect(dcbase, end); + tb = db->tb; + + /* Use slow path if first page is MMIO. */ + if (unlikely(tb->page_addr[0] == -1)) { + return NULL; } + + end = pc + len - 1; + if (likely(is_same_page(db, end))) { + host = db->host_addr[0]; + base = db->pc_first; + } else { + host = db->host_addr[1]; + base = TARGET_PAGE_ALIGN(db->pc_first); + if (host == NULL) { + tb->page_addr[1] = + get_page_addr_code_hostp(env, base, &db->host_addr[1]); +#ifdef CONFIG_USER_ONLY + page_protect(end); #endif + /* We cannot handle MMIO as second page. */ + assert(tb->page_addr[1] != -1); + host = db->host_addr[1]; + } + + /* Use slow path when crossing pages. */ + if (is_same_page(db, pc)) { + return NULL; + } + } + + tcg_debug_assert(pc >= base); + return host + (pc - base); } -#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \ - type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \ - abi_ptr pc, bool do_swap) \ - { \ - translator_maybe_page_protect(dcbase, pc, sizeof(type)); \ - type ret = load_fn(env, pc); \ - if (do_swap) { \ - ret = swap_fn(ret); \ - } \ - plugin_insn_append(pc, &ret, sizeof(ret)); \ - return ret; \ +uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc) +{ + uint8_t ret; + void *p = translator_access(env, db, pc, sizeof(ret)); + + if (p) { + plugin_insn_append(pc, p, sizeof(ret)); + return ldub_p(p); } + ret = cpu_ldub_code(env, pc); + plugin_insn_append(pc, &ret, sizeof(ret)); + return ret; +} -FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD) +uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc) +{ + uint16_t ret, plug; + void *p = translator_access(env, db, pc, sizeof(ret)); -#undef GEN_TRANSLATOR_LD + if (p) { + plugin_insn_append(pc, p, sizeof(ret)); + return lduw_p(p); + } + ret = cpu_lduw_code(env, pc); + plug = tswap16(ret); + plugin_insn_append(pc, &plug, sizeof(ret)); + return ret; +} + +uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc) +{ + uint32_t ret, plug; + void *p = translator_access(env, db, pc, sizeof(ret)); + + if (p) { + plugin_insn_append(pc, p, sizeof(ret)); + return ldl_p(p); + } + ret = cpu_ldl_code(env, pc); + plug = tswap32(ret); + plugin_insn_append(pc, &plug, sizeof(ret)); + return ret; +} + +uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc) +{ + uint64_t ret, plug; + void *p = translator_access(env, db, pc, sizeof(ret)); + + if (p) { + plugin_insn_append(pc, p, sizeof(ret)); + return ldq_p(p); + } + ret = cpu_ldq_code(env, pc); + plug = tswap64(ret); + plugin_insn_append(pc, &plug, sizeof(ret)); + return ret; +} diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 20ada5472b..521aa8b61e 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -80,10 +80,7 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write) * (and if the translator doesn't handle page boundaries correctly * there's little we can do about that here). Therefore, do not * trigger the unwinder. - * - * Like tb_gen_code, release the memory lock before cpu_loop_exit. */ - mmap_unlock(); *pc = 0; return MMU_INST_FETCH; } @@ -199,6 +196,20 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, return size ? g2h(env_cpu(env), addr) : NULL; } +tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, + void **hostp) +{ + int flags; + + flags = probe_access_internal(env, addr, 1, MMU_INST_FETCH, false, 0); + g_assert(flags == 0); + + if (hostp) { + *hostp = g2h_untagged(addr); + } + return addr; +} + /* The softmmu versions of these helpers are in cputlb.c. */ /* diff --git a/audio/audio.c b/audio/audio.c index a02f3ce5c6..df6818ed55 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -32,6 +32,7 @@ #include "qapi/qapi-visit-audio.h" #include "qemu/cutils.h" #include "qemu/module.h" +#include "qemu/help_option.h" #include "sysemu/sysemu.h" #include "sysemu/replay.h" #include "sysemu/runstate.h" @@ -137,7 +138,7 @@ static inline int audio_bits_to_index (int bits) default: audio_bug ("bits_to_index", 1); AUD_log (NULL, "invalid bits %d\n", bits); - abort(); + return 0; } } @@ -155,7 +156,7 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size) AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n", funcname); AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len); - abort(); + return NULL; } return g_malloc0 (len); @@ -542,7 +543,7 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw) size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw); if (audio_bug(__func__, live > hw->conv_buf->size)) { dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size); - abort(); + return 0; } return live; } @@ -580,7 +581,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size) } if (audio_bug(__func__, live > hw->conv_buf->size)) { dolog("live_in=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size); - abort(); + return 0; } rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size); @@ -655,7 +656,7 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live) if (audio_bug(__func__, live > hw->mix_buf->size)) { dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size); - abort(); + return 0; } return live; } @@ -705,7 +706,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size) live = sw->total_hw_samples_mixed; if (audio_bug(__func__, live > hwsamples)) { dolog("live=%zu hw->mix_buf->size=%zu\n", live, hwsamples); - abort(); + return 0; } if (live == hwsamples) { @@ -997,7 +998,7 @@ static size_t audio_get_avail (SWVoiceIn *sw) if (audio_bug(__func__, live > sw->hw->conv_buf->size)) { dolog("live=%zu sw->hw->conv_buf->size=%zu\n", live, sw->hw->conv_buf->size); - abort(); + return 0; } ldebug ( @@ -1027,7 +1028,7 @@ static size_t audio_get_free(SWVoiceOut *sw) if (audio_bug(__func__, live > sw->hw->mix_buf->size)) { dolog("live=%zu sw->hw->mix_buf->size=%zu\n", live, sw->hw->mix_buf->size); - abort(); + return 0; } dead = sw->hw->mix_buf->size - live; @@ -1169,7 +1170,7 @@ static void audio_run_out (AudioState *s) if (audio_bug(__func__, live > hw->mix_buf->size)) { dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size); - abort(); + continue; } if (hw->pending_disable && !nb_live) { @@ -1202,7 +1203,7 @@ static void audio_run_out (AudioState *s) if (audio_bug(__func__, hw->mix_buf->pos >= hw->mix_buf->size)) { dolog("hw->mix_buf->pos=%zu hw->mix_buf->size=%zu played=%zu\n", hw->mix_buf->pos, hw->mix_buf->size, played); - abort(); + hw->mix_buf->pos = 0; } #ifdef DEBUG_OUT @@ -1222,7 +1223,7 @@ static void audio_run_out (AudioState *s) if (audio_bug(__func__, played > sw->total_hw_samples_mixed)) { dolog("played=%zu sw->total_hw_samples_mixed=%zu\n", played, sw->total_hw_samples_mixed); - abort(); + played = sw->total_hw_samples_mixed; } sw->total_hw_samples_mixed -= played; @@ -1345,7 +1346,7 @@ static void audio_run_capture (AudioState *s) if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) { dolog("captured=%zu sw->total_hw_samples_mixed=%zu\n", captured, sw->total_hw_samples_mixed); - abort(); + captured = sw->total_hw_samples_mixed; } sw->total_hw_samples_mixed -= captured; @@ -1743,7 +1744,6 @@ static AudioState *audio_init(Audiodev *dev, const char *name) atexit(audio_cleanup); atexit_registered = true; } - QTAILQ_INSERT_TAIL(&audio_states, s, list); s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); @@ -1769,6 +1769,10 @@ static AudioState *audio_init(Audiodev *dev, const char *name) } else { dolog ("Unknown audio driver `%s'\n", drvname); } + if (!done) { + free_audio_state(s); + return NULL; + } } else { for (i = 0; audio_prio_list[i]; i++) { AudiodevListEntry *e = audiodev_find(&head, audio_prio_list[i]); @@ -1806,6 +1810,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name) "(Audio can continue looping even after stopping the VM)\n"); } + QTAILQ_INSERT_TAIL(&audio_states, s, list); QLIST_INIT (&s->card_head); vmstate_register (NULL, 0, &vmstate_audio, s); return s; @@ -2025,6 +2030,7 @@ void audio_create_pdos(Audiodev *dev) CASE(OSS, oss, Oss); CASE(PA, pa, Pa); CASE(SDL, sdl, Sdl); + CASE(SNDIO, sndio, ); CASE(SPICE, spice, ); CASE(WAV, wav, ); @@ -2097,10 +2103,28 @@ static void audio_validate_opts(Audiodev *dev, Error **errp) } } +void audio_help(void) +{ + int i; + + printf("Available audio drivers:\n"); + + for (i = 0; i < AUDIODEV_DRIVER__MAX; i++) { + audio_driver *driver = audio_driver_lookup(AudiodevDriver_str(i)); + if (driver) { + printf("%s\n", driver->name); + } + } +} + void audio_parse_option(const char *opt) { Audiodev *dev = NULL; + if (is_help_option(opt)) { + audio_help(); + exit(EXIT_SUCCESS); + } Visitor *v = qobject_input_visitor_new_str(opt, "driver", &error_fatal); visit_type_Audiodev(v, NULL, &dev, &error_fatal); visit_free(v); @@ -2119,13 +2143,17 @@ void audio_define(Audiodev *dev) QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next); } -void audio_init_audiodevs(void) +bool audio_init_audiodevs(void) { AudiodevListEntry *e; QSIMPLEQ_FOREACH(e, &audiodevs, next) { - audio_init(e->dev, NULL); + if (!audio_init(e->dev, NULL)) { + return false; + } } + + return true; } audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo) diff --git a/audio/audio.h b/audio/audio.h index b5e17cd218..01bdc567fb 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -170,7 +170,8 @@ void audio_sample_from_uint64(void *samples, int pos, void audio_define(Audiodev *audio); void audio_parse_option(const char *opt); -void audio_init_audiodevs(void); +bool audio_init_audiodevs(void); +void audio_help(void); void audio_legacy_help(void); AudioState *audio_state_by_name(const char *name); diff --git a/audio/audio_template.h b/audio/audio_template.h index 7192b19e73..98ab557684 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -59,13 +59,12 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s, if (audio_bug(__func__, !voice_size && max_voices)) { dolog ("drv=`%s' voice_size=0 max_voices=%d\n", drv->name, max_voices); - abort(); + glue (s->nb_hw_voices_, TYPE) = 0; } if (audio_bug(__func__, voice_size && !max_voices)) { dolog ("drv=`%s' voice_size=%d max_voices=0\n", drv->name, voice_size); - abort(); } } @@ -82,7 +81,6 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw) size_t samples = hw->samples; if (audio_bug(__func__, samples == 0)) { dolog("Attempted to allocate empty buffer\n"); - abort(); } HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples); @@ -254,12 +252,12 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s, if (audio_bug(__func__, !drv)) { dolog ("No host audio driver\n"); - abort(); + return NULL; } if (audio_bug(__func__, !drv->pcm_ops)) { dolog ("Host audio driver without pcm_ops\n"); - abort(); + return NULL; } hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE)); @@ -277,13 +275,12 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s, QLIST_INIT (&hw->cap_head); #endif if (glue (hw->pcm_ops->init_, TYPE) (hw, as, s->drv_opaque)) { - g_free(hw); - return NULL; + goto err0; } if (audio_bug(__func__, hw->samples <= 0)) { dolog("hw->samples=%zd\n", hw->samples); - abort(); + goto err1; } if (hw->info.is_float) { @@ -312,6 +309,12 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s, audio_attach_capture (hw); #endif return hw; + + err1: + glue (hw->pcm_ops->fini_, TYPE) (hw); + err0: + g_free (hw); + return NULL; } AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev) @@ -336,6 +339,8 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev) return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE); case AUDIODEV_DRIVER_SDL: return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE); + case AUDIODEV_DRIVER_SNDIO: + return dev->u.sndio.TYPE; case AUDIODEV_DRIVER_SPICE: return dev->u.spice.TYPE; case AUDIODEV_DRIVER_WAV: @@ -432,7 +437,7 @@ void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw) if (sw) { if (audio_bug(__func__, !card)) { dolog ("card=%p\n", card); - abort(); + return; } glue (audio_close_, TYPE) (sw); @@ -454,7 +459,7 @@ SW *glue (AUD_open_, TYPE) ( if (audio_bug(__func__, !card || !name || !callback_fn || !as)) { dolog ("card=%p name=%p callback_fn=%p as=%p\n", card, name, callback_fn, as); - abort(); + goto fail; } s = card->state; @@ -465,12 +470,12 @@ SW *glue (AUD_open_, TYPE) ( if (audio_bug(__func__, audio_validate_settings(as))) { audio_print_settings (as); - abort(); + goto fail; } if (audio_bug(__func__, !s->drv)) { dolog ("Can not open `%s' (no host audio driver)\n", name); - abort(); + goto fail; } if (sw && audio_pcm_info_eq (&sw->info, as)) { diff --git a/audio/meson.build b/audio/meson.build index 3abee90860..34aed78342 100644 --- a/audio/meson.build +++ b/audio/meson.build @@ -17,6 +17,7 @@ foreach m : [ ['pa', pulse, files('paaudio.c')], ['sdl', sdl, files('sdlaudio.c')], ['jack', jack, files('jackaudio.c')], + ['sndio', sndio, files('sndioaudio.c')], ['spice', spice, files('spiceaudio.c')] ] if m[1].found() diff --git a/audio/sndioaudio.c b/audio/sndioaudio.c new file mode 100644 index 0000000000..7c45276d36 --- /dev/null +++ b/audio/sndioaudio.c @@ -0,0 +1,565 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2019 Alexandre Ratchov + */ + +/* + * TODO : + * + * Use a single device and open it in full-duplex rather than + * opening it twice (once for playback once for recording). + * + * This is the only way to ensure that playback doesn't drift with respect + * to recording, which is what guest systems expect. + */ + +#include +#include +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "audio.h" +#include "trace.h" + +#define AUDIO_CAP "sndio" +#include "audio_int.h" + +/* default latency in microseconds if no option is set */ +#define SNDIO_LATENCY_US 50000 + +typedef struct SndioVoice { + union { + HWVoiceOut out; + HWVoiceIn in; + } hw; + struct sio_par par; + struct sio_hdl *hdl; + struct pollfd *pfds; + struct pollindex { + struct SndioVoice *self; + int index; + } *pindexes; + unsigned char *buf; + size_t buf_size; + size_t sndio_pos; + size_t qemu_pos; + unsigned int mode; + unsigned int nfds; + bool enabled; +} SndioVoice; + +typedef struct SndioConf { + const char *devname; + unsigned int latency; +} SndioConf; + +/* needed for forward reference */ +static void sndio_poll_in(void *arg); +static void sndio_poll_out(void *arg); + +/* + * stop polling descriptors + */ +static void sndio_poll_clear(SndioVoice *self) +{ + struct pollfd *pfd; + int i; + + for (i = 0; i < self->nfds; i++) { + pfd = &self->pfds[i]; + qemu_set_fd_handler(pfd->fd, NULL, NULL, NULL); + } + + self->nfds = 0; +} + +/* + * write data to the device until it blocks or + * all of our buffered data is written + */ +static void sndio_write(SndioVoice *self) +{ + size_t todo, n; + + todo = self->qemu_pos - self->sndio_pos; + + /* + * transfer data to device, until it blocks + */ + while (todo > 0) { + n = sio_write(self->hdl, self->buf + self->sndio_pos, todo); + if (n == 0) { + break; + } + self->sndio_pos += n; + todo -= n; + } + + if (self->sndio_pos == self->buf_size) { + /* + * we complete the block + */ + self->sndio_pos = 0; + self->qemu_pos = 0; + } +} + +/* + * read data from the device until it blocks or + * there no room any longer + */ +static void sndio_read(SndioVoice *self) +{ + size_t todo, n; + + todo = self->buf_size - self->sndio_pos; + + /* + * transfer data from the device, until it blocks + */ + while (todo > 0) { + n = sio_read(self->hdl, self->buf + self->sndio_pos, todo); + if (n == 0) { + break; + } + self->sndio_pos += n; + todo -= n; + } +} + +/* + * Set handlers for all descriptors libsndio needs to + * poll + */ +static void sndio_poll_wait(SndioVoice *self) +{ + struct pollfd *pfd; + int events, i; + + events = 0; + if (self->mode == SIO_PLAY) { + if (self->sndio_pos < self->qemu_pos) { + events |= POLLOUT; + } + } else { + if (self->sndio_pos < self->buf_size) { + events |= POLLIN; + } + } + + /* + * fill the given array of descriptors with the events sndio + * wants, they are different from our 'event' variable because + * sndio may use descriptors internally. + */ + self->nfds = sio_pollfd(self->hdl, self->pfds, events); + + for (i = 0; i < self->nfds; i++) { + pfd = &self->pfds[i]; + if (pfd->fd < 0) { + continue; + } + qemu_set_fd_handler(pfd->fd, + (pfd->events & POLLIN) ? sndio_poll_in : NULL, + (pfd->events & POLLOUT) ? sndio_poll_out : NULL, + &self->pindexes[i]); + pfd->revents = 0; + } +} + +/* + * call-back called when one of the descriptors + * became readable or writable + */ +static void sndio_poll_event(SndioVoice *self, int index, int event) +{ + int revents; + + /* + * ensure we're not called twice this cycle + */ + sndio_poll_clear(self); + + /* + * make self->pfds[] look as we're returning from poll syscal, + * this is how sio_revents expects events to be. + */ + self->pfds[index].revents = event; + + /* + * tell sndio to handle events and return whether we can read or + * write without blocking. + */ + revents = sio_revents(self->hdl, self->pfds); + if (self->mode == SIO_PLAY) { + if (revents & POLLOUT) { + sndio_write(self); + } + + if (self->qemu_pos < self->buf_size) { + audio_run(self->hw.out.s, "sndio_out"); + } + } else { + if (revents & POLLIN) { + sndio_read(self); + } + + if (self->qemu_pos < self->sndio_pos) { + audio_run(self->hw.in.s, "sndio_in"); + } + } + + /* + * audio_run() may have changed state + */ + if (self->enabled) { + sndio_poll_wait(self); + } +} + +/* + * return the upper limit of the amount of free play buffer space + */ +static size_t sndio_buffer_get_free(HWVoiceOut *hw) +{ + SndioVoice *self = (SndioVoice *) hw; + + return self->buf_size - self->qemu_pos; +} + +/* + * return a buffer where data to play can be stored, + * its size is stored in the location pointed by the size argument. + */ +static void *sndio_get_buffer_out(HWVoiceOut *hw, size_t *size) +{ + SndioVoice *self = (SndioVoice *) hw; + + *size = self->buf_size - self->qemu_pos; + return self->buf + self->qemu_pos; +} + +/* + * put back to sndio back-end a buffer returned by sndio_get_buffer_out() + */ +static size_t sndio_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size) +{ + SndioVoice *self = (SndioVoice *) hw; + + self->qemu_pos += size; + sndio_poll_wait(self); + return size; +} + +/* + * return a buffer from where recorded data is available, + * its size is stored in the location pointed by the size argument. + * it may not exceed the initial value of "*size". + */ +static void *sndio_get_buffer_in(HWVoiceIn *hw, size_t *size) +{ + SndioVoice *self = (SndioVoice *) hw; + size_t todo, max_todo; + + /* + * unlike the get_buffer_out() method, get_buffer_in() + * must return a buffer of at most the given size, see audio.c + */ + max_todo = *size; + + todo = self->sndio_pos - self->qemu_pos; + if (todo > max_todo) { + todo = max_todo; + } + + *size = todo; + return self->buf + self->qemu_pos; +} + +/* + * discard the given amount of recorded data + */ +static void sndio_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size) +{ + SndioVoice *self = (SndioVoice *) hw; + + self->qemu_pos += size; + if (self->qemu_pos == self->buf_size) { + self->qemu_pos = 0; + self->sndio_pos = 0; + } + sndio_poll_wait(self); +} + +/* + * call-back called when one of our descriptors becomes writable + */ +static void sndio_poll_out(void *arg) +{ + struct pollindex *pindex = (struct pollindex *) arg; + + sndio_poll_event(pindex->self, pindex->index, POLLOUT); +} + +/* + * call-back called when one of our descriptors becomes readable + */ +static void sndio_poll_in(void *arg) +{ + struct pollindex *pindex = (struct pollindex *) arg; + + sndio_poll_event(pindex->self, pindex->index, POLLIN); +} + +static void sndio_fini(SndioVoice *self) +{ + if (self->hdl) { + sio_close(self->hdl); + self->hdl = NULL; + } + + g_free(self->pfds); + g_free(self->pindexes); + g_free(self->buf); +} + +static int sndio_init(SndioVoice *self, + struct audsettings *as, int mode, Audiodev *dev) +{ + AudiodevSndioOptions *opts = &dev->u.sndio; + unsigned long long latency; + const char *dev_name; + struct sio_par req; + unsigned int nch; + int i, nfds; + + dev_name = opts->has_dev ? opts->dev : SIO_DEVANY; + latency = opts->has_latency ? opts->latency : SNDIO_LATENCY_US; + + /* open the device in non-blocking mode */ + self->hdl = sio_open(dev_name, mode, 1); + if (self->hdl == NULL) { + dolog("failed to open device\n"); + return -1; + } + + self->mode = mode; + + sio_initpar(&req); + + switch (as->fmt) { + case AUDIO_FORMAT_S8: + req.bits = 8; + req.sig = 1; + break; + case AUDIO_FORMAT_U8: + req.bits = 8; + req.sig = 0; + break; + case AUDIO_FORMAT_S16: + req.bits = 16; + req.sig = 1; + break; + case AUDIO_FORMAT_U16: + req.bits = 16; + req.sig = 0; + break; + case AUDIO_FORMAT_S32: + req.bits = 32; + req.sig = 1; + break; + case AUDIO_FORMAT_U32: + req.bits = 32; + req.sig = 0; + break; + default: + dolog("unknown audio sample format\n"); + return -1; + } + + if (req.bits > 8) { + req.le = as->endianness ? 0 : 1; + } + + req.rate = as->freq; + if (mode == SIO_PLAY) { + req.pchan = as->nchannels; + } else { + req.rchan = as->nchannels; + } + + /* set on-device buffer size */ + req.appbufsz = req.rate * latency / 1000000; + + if (!sio_setpar(self->hdl, &req)) { + dolog("failed set audio params\n"); + goto fail; + } + + if (!sio_getpar(self->hdl, &self->par)) { + dolog("failed get audio params\n"); + goto fail; + } + + nch = (mode == SIO_PLAY) ? self->par.pchan : self->par.rchan; + + /* + * With the default setup, sndio supports any combination of parameters + * so these checks are mostly to catch configuration errors. + */ + if (self->par.bits != req.bits || self->par.bps != req.bits / 8 || + self->par.sig != req.sig || (req.bits > 8 && self->par.le != req.le) || + self->par.rate != as->freq || nch != as->nchannels) { + dolog("unsupported audio params\n"); + goto fail; + } + + /* + * we use one block as buffer size; this is how + * transfers get well aligned + */ + self->buf_size = self->par.round * self->par.bps * nch; + + self->buf = g_malloc(self->buf_size); + if (self->buf == NULL) { + dolog("failed to allocate audio buffer\n"); + goto fail; + } + + nfds = sio_nfds(self->hdl); + + self->pfds = g_malloc_n(nfds, sizeof(struct pollfd)); + if (self->pfds == NULL) { + dolog("failed to allocate pollfd structures\n"); + goto fail; + } + + self->pindexes = g_malloc_n(nfds, sizeof(struct pollindex)); + if (self->pindexes == NULL) { + dolog("failed to allocate pollindex structures\n"); + goto fail; + } + + for (i = 0; i < nfds; i++) { + self->pindexes[i].self = self; + self->pindexes[i].index = i; + } + + return 0; +fail: + sndio_fini(self); + return -1; +} + +static void sndio_enable(SndioVoice *self, bool enable) +{ + if (enable) { + sio_start(self->hdl); + self->enabled = true; + sndio_poll_wait(self); + } else { + self->enabled = false; + sndio_poll_clear(self); + sio_stop(self->hdl); + } +} + +static void sndio_enable_out(HWVoiceOut *hw, bool enable) +{ + SndioVoice *self = (SndioVoice *) hw; + + sndio_enable(self, enable); +} + +static void sndio_enable_in(HWVoiceIn *hw, bool enable) +{ + SndioVoice *self = (SndioVoice *) hw; + + sndio_enable(self, enable); +} + +static int sndio_init_out(HWVoiceOut *hw, struct audsettings *as, void *opaque) +{ + SndioVoice *self = (SndioVoice *) hw; + + if (sndio_init(self, as, SIO_PLAY, opaque) == -1) { + return -1; + } + + audio_pcm_init_info(&hw->info, as); + hw->samples = self->par.round; + return 0; +} + +static int sndio_init_in(HWVoiceIn *hw, struct audsettings *as, void *opaque) +{ + SndioVoice *self = (SndioVoice *) hw; + + if (sndio_init(self, as, SIO_REC, opaque) == -1) { + return -1; + } + + audio_pcm_init_info(&hw->info, as); + hw->samples = self->par.round; + return 0; +} + +static void sndio_fini_out(HWVoiceOut *hw) +{ + SndioVoice *self = (SndioVoice *) hw; + + sndio_fini(self); +} + +static void sndio_fini_in(HWVoiceIn *hw) +{ + SndioVoice *self = (SndioVoice *) hw; + + sndio_fini(self); +} + +static void *sndio_audio_init(Audiodev *dev) +{ + assert(dev->driver == AUDIODEV_DRIVER_SNDIO); + return dev; +} + +static void sndio_audio_fini(void *opaque) +{ +} + +static struct audio_pcm_ops sndio_pcm_ops = { + .init_out = sndio_init_out, + .fini_out = sndio_fini_out, + .enable_out = sndio_enable_out, + .write = audio_generic_write, + .buffer_get_free = sndio_buffer_get_free, + .get_buffer_out = sndio_get_buffer_out, + .put_buffer_out = sndio_put_buffer_out, + .init_in = sndio_init_in, + .fini_in = sndio_fini_in, + .read = audio_generic_read, + .enable_in = sndio_enable_in, + .get_buffer_in = sndio_get_buffer_in, + .put_buffer_in = sndio_put_buffer_in, +}; + +static struct audio_driver sndio_audio_driver = { + .name = "sndio", + .descr = "sndio https://sndio.org", + .init = sndio_audio_init, + .fini = sndio_audio_fini, + .pcm_ops = &sndio_pcm_ops, + .can_be_default = 1, + .max_voices_out = INT_MAX, + .max_voices_in = INT_MAX, + .voice_size_out = sizeof(SndioVoice), + .voice_size_in = sizeof(SndioVoice) +}; + +static void register_audio_sndio(void) +{ + audio_driver_register(&sndio_audio_driver); +} + +type_init(register_audio_sndio); diff --git a/backends/dbus-vmstate.c b/backends/dbus-vmstate.c index 9cfd758c42..57369ec0f2 100644 --- a/backends/dbus-vmstate.c +++ b/backends/dbus-vmstate.c @@ -114,14 +114,19 @@ dbus_get_proxies(DBusVMState *self, GError **err) "org.qemu.VMState1", NULL, err); if (!proxy) { - return NULL; + if (err != NULL && *err != NULL) { + warn_report("%s: Failed to create proxy: %s", + __func__, (*err)->message); + g_clear_error(err); + } + continue; } result = g_dbus_proxy_get_cached_property(proxy, "Id"); if (!result) { - g_set_error_literal(err, G_IO_ERROR, G_IO_ERROR_FAILED, - "VMState Id property is missing."); - return NULL; + warn_report("%s: VMState Id property is missing.", __func__); + g_clear_object(&proxy); + continue; } id = g_variant_dup_string(result, &size); diff --git a/backends/hostmem.c b/backends/hostmem.c index 624bb7ecd3..4428e06738 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -306,22 +306,12 @@ bool host_memory_backend_is_mapped(HostMemoryBackend *backend) return backend->is_mapped; } -#ifdef __linux__ size_t host_memory_backend_pagesize(HostMemoryBackend *memdev) { - Object *obj = OBJECT(memdev); - char *path = object_property_get_str(obj, "mem-path", NULL); - size_t pagesize = qemu_mempath_getpagesize(path); - - g_free(path); + size_t pagesize = qemu_ram_pagesize(memdev->mr.ram_block); + g_assert(pagesize >= qemu_real_host_page_size()); return pagesize; } -#else -size_t host_memory_backend_pagesize(HostMemoryBackend *memdev) -{ - return qemu_real_host_page_size(); -} -#endif static void host_memory_backend_memory_complete(UserCreatable *uc, Error **errp) diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c index 87d061e9bb..49cc3d749d 100644 --- a/backends/tpm/tpm_emulator.c +++ b/backends/tpm/tpm_emulator.c @@ -32,8 +32,10 @@ #include "qemu/sockets.h" #include "qemu/lockable.h" #include "io/channel-socket.h" +#include "sysemu/runstate.h" #include "sysemu/tpm_backend.h" #include "sysemu/tpm_util.h" +#include "sysemu/runstate.h" #include "tpm_int.h" #include "tpm_ioctl.h" #include "migration/blocker.h" @@ -81,6 +83,9 @@ struct TPMEmulator { unsigned int established_flag_cached:1; TPMBlobBuffers state_blobs; + + bool relock_storage; + VMChangeStateEntry *vmstate; }; struct tpm_error { @@ -302,6 +307,35 @@ static int tpm_emulator_stop_tpm(TPMBackend *tb) return 0; } +static int tpm_emulator_lock_storage(TPMEmulator *tpm_emu) +{ + ptm_lockstorage pls; + + if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_LOCK_STORAGE)) { + trace_tpm_emulator_lock_storage_cmd_not_supt(); + return 0; + } + + /* give failing side 300 * 10ms time to release lock */ + pls.u.req.retries = cpu_to_be32(300); + if (tpm_emulator_ctrlcmd(tpm_emu, CMD_LOCK_STORAGE, &pls, + sizeof(pls.u.req), sizeof(pls.u.resp)) < 0) { + error_report("tpm-emulator: Could not lock storage within 3 seconds: " + "%s", strerror(errno)); + return -1; + } + + pls.u.resp.tpm_result = be32_to_cpu(pls.u.resp.tpm_result); + if (pls.u.resp.tpm_result != 0) { + error_report("tpm-emulator: TPM result for CMD_LOCK_STORAGE: 0x%x %s", + pls.u.resp.tpm_result, + tpm_emulator_strerror(pls.u.resp.tpm_result)); + return -1; + } + + return 0; +} + static int tpm_emulator_set_buffer_size(TPMBackend *tb, size_t wanted_size, size_t *actual_size) @@ -383,6 +417,15 @@ err_exit: static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize) { + /* TPM startup will be done from post_load hook */ + if (runstate_check(RUN_STATE_INMIGRATE)) { + if (buffersize != 0) { + return tpm_emulator_set_buffer_size(tb, buffersize, NULL); + } + + return 0; + } + return tpm_emulator_startup_tpm_resume(tb, buffersize, false); } @@ -843,13 +886,34 @@ static int tpm_emulator_pre_save(void *opaque) { TPMBackend *tb = opaque; TPMEmulator *tpm_emu = TPM_EMULATOR(tb); + int ret; trace_tpm_emulator_pre_save(); tpm_backend_finish_sync(tb); /* get the state blobs from the TPM */ - return tpm_emulator_get_state_blobs(tpm_emu); + ret = tpm_emulator_get_state_blobs(tpm_emu); + + tpm_emu->relock_storage = ret == 0; + + return ret; +} + +static void tpm_emulator_vm_state_change(void *opaque, bool running, + RunState state) +{ + TPMBackend *tb = opaque; + TPMEmulator *tpm_emu = TPM_EMULATOR(tb); + + trace_tpm_emulator_vm_state_change(running, state); + + if (!running || state != RUN_STATE_RUNNING || !tpm_emu->relock_storage) { + return; + } + + /* lock storage after migration fall-back */ + tpm_emulator_lock_storage(tpm_emu); } /* @@ -911,6 +975,9 @@ static void tpm_emulator_inst_init(Object *obj) tpm_emu->options = g_new0(TPMEmulatorOptions, 1); tpm_emu->cur_locty_number = ~0; qemu_mutex_init(&tpm_emu->mutex); + tpm_emu->vmstate = + qemu_add_vm_change_state_handler(tpm_emulator_vm_state_change, + tpm_emu); vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_tpm_emulator, obj); @@ -960,6 +1027,7 @@ static void tpm_emulator_inst_finalize(Object *obj) tpm_sized_buffer_reset(&state_blobs->savestate); qemu_mutex_destroy(&tpm_emu->mutex); + qemu_del_vm_change_state_handler(tpm_emu->vmstate); vmstate_unregister(NULL, &vmstate_tpm_emulator, obj); } diff --git a/backends/tpm/tpm_ioctl.h b/backends/tpm/tpm_ioctl.h index bd6c12cb86..e506ef5160 100644 --- a/backends/tpm/tpm_ioctl.h +++ b/backends/tpm/tpm_ioctl.h @@ -5,12 +5,19 @@ * * This file is licensed under the terms of the 3-clause BSD license */ +#ifndef _TPM_IOCTL_H_ +#define _TPM_IOCTL_H_ -#ifndef TPM_IOCTL_H -#define TPM_IOCTL_H +#if defined(__CYGWIN__) +# define __USE_LINUX_IOCTL_DEFS +#endif +#include +#include +#ifndef _WIN32 #include #include +#endif #ifdef HAVE_SYS_IOCCOM_H #include @@ -194,6 +201,48 @@ struct ptm_setbuffersize { } u; }; +#define PTM_GETINFO_SIZE (3 * 1024) +/* + * PTM_GET_INFO: Get info about the TPM implementation (from libtpms) + * + * This request allows to indirectly call TPMLIB_GetInfo(flags) and + * retrieve information from libtpms. + * Only one transaction is currently necessary for returning results + * to a client. Therefore, totlength and length will be the same if + * offset is 0. + */ +struct ptm_getinfo { + union { + struct { + uint64_t flags; + uint32_t offset; /* offset from where to read */ + uint32_t pad; /* 32 bit arch */ + } req; /* request */ + struct { + ptm_res tpm_result; + uint32_t totlength; + uint32_t length; + char buffer[PTM_GETINFO_SIZE]; + } resp; /* response */ + } u; +}; + +#define SWTPM_INFO_TPMSPECIFICATION ((uint64_t)1 << 0) +#define SWTPM_INFO_TPMATTRIBUTES ((uint64_t)1 << 1) + +/* + * PTM_LOCK_STORAGE: Lock the storage and retry n times + */ +struct ptm_lockstorage { + union { + struct { + uint32_t retries; /* number of retries */ + } req; /* request */ + struct { + ptm_res tpm_result; + } resp; /* reponse */ + } u; +}; typedef uint64_t ptm_cap; typedef struct ptm_est ptm_est; @@ -205,6 +254,8 @@ typedef struct ptm_getstate ptm_getstate; typedef struct ptm_setstate ptm_setstate; typedef struct ptm_getconfig ptm_getconfig; typedef struct ptm_setbuffersize ptm_setbuffersize; +typedef struct ptm_getinfo ptm_getinfo; +typedef struct ptm_lockstorage ptm_lockstorage; /* capability flags returned by PTM_GET_CAPABILITY */ #define PTM_CAP_INIT (1) @@ -221,7 +272,11 @@ typedef struct ptm_setbuffersize ptm_setbuffersize; #define PTM_CAP_GET_CONFIG (1 << 11) #define PTM_CAP_SET_DATAFD (1 << 12) #define PTM_CAP_SET_BUFFERSIZE (1 << 13) +#define PTM_CAP_GET_INFO (1 << 14) +#define PTM_CAP_SEND_COMMAND_HEADER (1 << 15) +#define PTM_CAP_LOCK_STORAGE (1 << 16) +#ifndef _WIN32 enum { PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap), PTM_INIT = _IOWR('P', 1, ptm_init), @@ -240,7 +295,10 @@ enum { PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig), PTM_SET_DATAFD = _IOR('P', 15, ptm_res), PTM_SET_BUFFERSIZE = _IOWR('P', 16, ptm_setbuffersize), + PTM_GET_INFO = _IOWR('P', 17, ptm_getinfo), + PTM_LOCK_STORAGE = _IOWR('P', 18, ptm_lockstorage), }; +#endif /* * Commands used by the non-CUSE TPMs @@ -253,23 +311,25 @@ enum { * and ptm_set_state:u.req.data) are 0xffffffff. */ enum { - CMD_GET_CAPABILITY = 1, - CMD_INIT, - CMD_SHUTDOWN, - CMD_GET_TPMESTABLISHED, - CMD_SET_LOCALITY, - CMD_HASH_START, - CMD_HASH_DATA, - CMD_HASH_END, - CMD_CANCEL_TPM_CMD, - CMD_STORE_VOLATILE, - CMD_RESET_TPMESTABLISHED, - CMD_GET_STATEBLOB, - CMD_SET_STATEBLOB, - CMD_STOP, - CMD_GET_CONFIG, - CMD_SET_DATAFD, - CMD_SET_BUFFERSIZE, + CMD_GET_CAPABILITY = 1, /* 0x01 */ + CMD_INIT, /* 0x02 */ + CMD_SHUTDOWN, /* 0x03 */ + CMD_GET_TPMESTABLISHED, /* 0x04 */ + CMD_SET_LOCALITY, /* 0x05 */ + CMD_HASH_START, /* 0x06 */ + CMD_HASH_DATA, /* 0x07 */ + CMD_HASH_END, /* 0x08 */ + CMD_CANCEL_TPM_CMD, /* 0x09 */ + CMD_STORE_VOLATILE, /* 0x0a */ + CMD_RESET_TPMESTABLISHED, /* 0x0b */ + CMD_GET_STATEBLOB, /* 0x0c */ + CMD_SET_STATEBLOB, /* 0x0d */ + CMD_STOP, /* 0x0e */ + CMD_GET_CONFIG, /* 0x0f */ + CMD_SET_DATAFD, /* 0x10 */ + CMD_SET_BUFFERSIZE, /* 0x11 */ + CMD_GET_INFO, /* 0x12 */ + CMD_LOCK_STORAGE, /* 0x13 */ }; -#endif /* TPM_IOCTL_H */ +#endif /* _TPM_IOCTL_H_ */ diff --git a/backends/tpm/trace-events b/backends/tpm/trace-events index 3298766dd7..1ecef42a07 100644 --- a/backends/tpm/trace-events +++ b/backends/tpm/trace-events @@ -20,6 +20,8 @@ tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t max tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu" tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d" tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD" +tpm_emulator_lock_storage_cmd_not_supt(void) "Backend does not support LOCK_STORAGE" +tpm_emulator_vm_state_change(int running, int state) "state change to running %d state %d" tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2" tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2" tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified" diff --git a/block.c b/block.c index bc85f46eed..1fbf6b9e69 100644 --- a/block.c +++ b/block.c @@ -631,9 +631,10 @@ static int64_t create_file_fallback_truncate(BlockBackend *blk, * Helper function for bdrv_create_file_fallback(): Zero the first * sector to remove any potentially pre-existing image header. */ -static int create_file_fallback_zero_first_sector(BlockBackend *blk, - int64_t current_size, - Error **errp) +static int coroutine_fn +create_file_fallback_zero_first_sector(BlockBackend *blk, + int64_t current_size, + Error **errp) { int64_t bytes_to_clear; int ret; @@ -4980,8 +4981,8 @@ static void bdrv_close(BlockDriverState *bs) void bdrv_close_all(void) { - assert(job_next(NULL) == NULL); GLOBAL_STATE_CODE(); + assert(job_next(NULL) == NULL); /* Drop references from requests still in flight, such as canceled block * jobs whose AIO context has not been polled yet */ @@ -6167,13 +6168,16 @@ XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp) } } - for (job = block_job_next(NULL); job; job = block_job_next(job)) { - GSList *el; + WITH_JOB_LOCK_GUARD() { + for (job = block_job_next_locked(NULL); job; + job = block_job_next_locked(job)) { + GSList *el; - xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB, - job->job.id); - for (el = job->nodes; el; el = el->next) { - xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data); + xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB, + job->job.id); + for (el = job->nodes; el; el = el->next) { + xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data); + } } } diff --git a/block/accounting.c b/block/accounting.c index 2030851d79..2829745377 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -38,13 +38,31 @@ void block_acct_init(BlockAcctStats *stats) if (qtest_enabled()) { clock_type = QEMU_CLOCK_VIRTUAL; } + stats->account_invalid = true; + stats->account_failed = true; } -void block_acct_setup(BlockAcctStats *stats, bool account_invalid, - bool account_failed) +static bool bool_from_onoffauto(OnOffAuto val, bool def) { - stats->account_invalid = account_invalid; - stats->account_failed = account_failed; + switch (val) { + case ON_OFF_AUTO_AUTO: + return def; + case ON_OFF_AUTO_ON: + return true; + case ON_OFF_AUTO_OFF: + return false; + default: + abort(); + } +} + +void block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid, + enum OnOffAuto account_failed) +{ + stats->account_invalid = bool_from_onoffauto(account_invalid, + stats->account_invalid); + stats->account_failed = bool_from_onoffauto(account_failed, + stats->account_failed); } void block_acct_cleanup(BlockAcctStats *stats) diff --git a/block/blkverify.c b/block/blkverify.c index e4a37af3b2..020b1ae7b6 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -258,7 +258,7 @@ blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true); } -static int blkverify_co_flush(BlockDriverState *bs) +static int coroutine_fn blkverify_co_flush(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; diff --git a/block/block-backend.c b/block/block-backend.c index d4a5df2ac2..aa4adf06ae 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1546,7 +1546,7 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, return &acb->common; } -static void blk_aio_read_entry(void *opaque) +static void coroutine_fn blk_aio_read_entry(void *opaque) { BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; @@ -1558,7 +1558,7 @@ static void blk_aio_read_entry(void *opaque) blk_aio_complete(acb); } -static void blk_aio_write_entry(void *opaque) +static void coroutine_fn blk_aio_write_entry(void *opaque) { BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; @@ -1669,7 +1669,7 @@ int coroutine_fn blk_co_ioctl(BlockBackend *blk, unsigned long int req, return ret; } -static void blk_aio_ioctl_entry(void *opaque) +static void coroutine_fn blk_aio_ioctl_entry(void *opaque) { BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; @@ -1703,7 +1703,7 @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) return bdrv_co_pdiscard(blk->root, offset, bytes); } -static void blk_aio_pdiscard_entry(void *opaque) +static void coroutine_fn blk_aio_pdiscard_entry(void *opaque) { BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; @@ -1747,7 +1747,7 @@ static int coroutine_fn blk_co_do_flush(BlockBackend *blk) return bdrv_co_flush(blk_bs(blk)); } -static void blk_aio_flush_entry(void *opaque) +static void coroutine_fn blk_aio_flush_entry(void *opaque) { BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; diff --git a/block/copy-before-write.c b/block/copy-before-write.c index c24b8dd117..afbdd04489 100644 --- a/block/copy-before-write.c +++ b/block/copy-before-write.c @@ -203,9 +203,9 @@ static int coroutine_fn cbw_co_flush(BlockDriverState *bs) * It's guaranteed that guest writes will not interact in the region until * cbw_snapshot_read_unlock() called. */ -static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, - int64_t offset, int64_t bytes, - int64_t *pnum, BdrvChild **file) +static coroutine_fn BlockReq * +cbw_snapshot_read_lock(BlockDriverState *bs, int64_t offset, int64_t bytes, + int64_t *pnum, BdrvChild **file) { BDRVCopyBeforeWriteState *s = bs->opaque; BlockReq *req = g_new(BlockReq, 1); @@ -240,7 +240,8 @@ static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, return req; } -static void cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) +static coroutine_fn void +cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) { BDRVCopyBeforeWriteState *s = bs->opaque; diff --git a/block/curl.c b/block/curl.c index 1e0f609579..cba4c4cac7 100644 --- a/block/curl.c +++ b/block/curl.c @@ -855,7 +855,7 @@ out_noclean: return -EINVAL; } -static void curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb) +static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb) { CURLState *state; int running; diff --git a/block/file-posix.c b/block/file-posix.c index 48cd096624..23acffb9a4 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -154,7 +154,6 @@ typedef struct BDRVRawState { bool has_discard:1; bool has_write_zeroes:1; - bool discard_zeroes:1; bool use_linux_aio:1; bool use_linux_io_uring:1; int page_cache_inconsistent; /* errno from fdatasync failure */ @@ -755,7 +754,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, ret = -EINVAL; goto fail; } else { - s->discard_zeroes = true; s->has_fallocate = true; } } else { @@ -769,19 +767,12 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, } if (S_ISBLK(st.st_mode)) { -#ifdef BLKDISCARDZEROES - unsigned int arg; - if (ioctl(s->fd, BLKDISCARDZEROES, &arg) == 0 && arg) { - s->discard_zeroes = true; - } -#endif #ifdef __linux__ /* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. Do * not rely on the contents of discarded blocks unless using O_DIRECT. * Same for BLKZEROOUT. */ if (!(bs->open_flags & BDRV_O_NOCACHE)) { - s->discard_zeroes = false; s->has_write_zeroes = false; } #endif @@ -1295,7 +1286,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) } #endif - if (bs->sg || S_ISBLK(st.st_mode)) { + if (bdrv_is_sg(bs) || S_ISBLK(st.st_mode)) { int ret = hdev_get_max_hw_transfer(s->fd, &st); if (ret > 0 && ret <= BDRV_REQUEST_MAX_BYTES) { @@ -2061,6 +2052,28 @@ static int coroutine_fn raw_thread_pool_submit(BlockDriverState *bs, return thread_pool_submit_co(pool, func, arg); } +/* + * Check if all memory in this vector is sector aligned. + */ +static bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) +{ + int i; + size_t alignment = bdrv_min_mem_align(bs); + size_t len = bs->bl.request_alignment; + IO_CODE(); + + for (i = 0; i < qiov->niov; i++) { + if ((uintptr_t) qiov->iov[i].iov_base % alignment) { + return false; + } + if (qiov->iov[i].iov_len % len) { + return false; + } + } + + return true; +} + static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int type) { @@ -2158,7 +2171,7 @@ static void raw_aio_unplug(BlockDriverState *bs) #endif } -static int raw_co_flush_to_disk(BlockDriverState *bs) +static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; RawPosixAIOData acb; diff --git a/block/gluster.c b/block/gluster.c index b60213ab80..bb1144cf6a 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1555,7 +1555,6 @@ static BlockDriver bdrv_gluster = { .format_name = "gluster", .protocol_name = "gluster", .instance_size = sizeof(BDRVGlusterState), - .bdrv_needs_filename = false, .bdrv_file_open = qemu_gluster_open, .bdrv_reopen_prepare = qemu_gluster_reopen_prepare, .bdrv_reopen_commit = qemu_gluster_reopen_commit, @@ -1585,7 +1584,6 @@ static BlockDriver bdrv_gluster_tcp = { .format_name = "gluster", .protocol_name = "gluster+tcp", .instance_size = sizeof(BDRVGlusterState), - .bdrv_needs_filename = false, .bdrv_file_open = qemu_gluster_open, .bdrv_reopen_prepare = qemu_gluster_reopen_prepare, .bdrv_reopen_commit = qemu_gluster_reopen_commit, @@ -1615,7 +1613,6 @@ static BlockDriver bdrv_gluster_unix = { .format_name = "gluster", .protocol_name = "gluster+unix", .instance_size = sizeof(BDRVGlusterState), - .bdrv_needs_filename = true, .bdrv_file_open = qemu_gluster_open, .bdrv_reopen_prepare = qemu_gluster_reopen_prepare, .bdrv_reopen_commit = qemu_gluster_reopen_commit, @@ -1651,7 +1648,6 @@ static BlockDriver bdrv_gluster_rdma = { .format_name = "gluster", .protocol_name = "gluster+rdma", .instance_size = sizeof(BDRVGlusterState), - .bdrv_needs_filename = true, .bdrv_file_open = qemu_gluster_open, .bdrv_reopen_prepare = qemu_gluster_reopen_prepare, .bdrv_reopen_commit = qemu_gluster_reopen_commit, diff --git a/block/io.c b/block/io.c index 0a8cbefe86..d30073036e 100644 --- a/block/io.c +++ b/block/io.c @@ -751,11 +751,11 @@ static void coroutine_fn tracked_request_end(BdrvTrackedRequest *req) /** * Add an active request to the tracked requests list */ -static void tracked_request_begin(BdrvTrackedRequest *req, - BlockDriverState *bs, - int64_t offset, - int64_t bytes, - enum BdrvTrackedRequestType type) +static void coroutine_fn tracked_request_begin(BdrvTrackedRequest *req, + BlockDriverState *bs, + int64_t offset, + int64_t bytes, + enum BdrvTrackedRequestType type) { bdrv_check_request(offset, bytes, &error_abort); @@ -794,7 +794,7 @@ static bool tracked_request_overlaps(BdrvTrackedRequest *req, } /* Called with self->bs->reqs_lock held */ -static BdrvTrackedRequest * +static coroutine_fn BdrvTrackedRequest * bdrv_find_conflicting_request(BdrvTrackedRequest *self) { BdrvTrackedRequest *req; @@ -828,20 +828,16 @@ bdrv_find_conflicting_request(BdrvTrackedRequest *self) } /* Called with self->bs->reqs_lock held */ -static bool coroutine_fn +static void coroutine_fn bdrv_wait_serialising_requests_locked(BdrvTrackedRequest *self) { BdrvTrackedRequest *req; - bool waited = false; while ((req = bdrv_find_conflicting_request(self))) { self->waiting_for = req; qemu_co_queue_wait(&req->wait_queue, &self->bs->reqs_lock); self->waiting_for = NULL; - waited = true; } - - return waited; } /* Called with req->bs->reqs_lock held */ @@ -934,36 +930,31 @@ void bdrv_dec_in_flight(BlockDriverState *bs) bdrv_wakeup(bs); } -static bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self) +static void coroutine_fn +bdrv_wait_serialising_requests(BdrvTrackedRequest *self) { BlockDriverState *bs = self->bs; - bool waited = false; if (!qatomic_read(&bs->serialising_in_flight)) { - return false; + return; } qemu_co_mutex_lock(&bs->reqs_lock); - waited = bdrv_wait_serialising_requests_locked(self); + bdrv_wait_serialising_requests_locked(self); qemu_co_mutex_unlock(&bs->reqs_lock); - - return waited; } -bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, +void coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, uint64_t align) { - bool waited; IO_CODE(); qemu_co_mutex_lock(&req->bs->reqs_lock); tracked_request_set_serialising(req, align); - waited = bdrv_wait_serialising_requests_locked(req); + bdrv_wait_serialising_requests_locked(req); qemu_co_mutex_unlock(&req->bs->reqs_lock); - - return waited; } int bdrv_check_qiov_request(int64_t offset, int64_t bytes, @@ -1644,10 +1635,10 @@ static bool bdrv_init_padding(BlockDriverState *bs, return true; } -static int bdrv_padding_rmw_read(BdrvChild *child, - BdrvTrackedRequest *req, - BdrvRequestPadding *pad, - bool zero_middle) +static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, + BdrvTrackedRequest *req, + BdrvRequestPadding *pad, + bool zero_middle) { QEMUIOVector local_qiov; BlockDriverState *bs = child->bs; @@ -3168,7 +3159,7 @@ out: return ret; } -int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) +int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) { BlockDriver *drv = bs->drv; CoroutineIOCompletion co = { @@ -3236,27 +3227,6 @@ void *qemu_try_blockalign0(BlockDriverState *bs, size_t size) return mem; } -/* - * Check if all memory in this vector is sector aligned. - */ -bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) -{ - int i; - size_t alignment = bdrv_min_mem_align(bs); - IO_CODE(); - - for (i = 0; i < qiov->niov; i++) { - if ((uintptr_t) qiov->iov[i].iov_base % alignment) { - return false; - } - if (qiov->iov[i].iov_len % alignment) { - return false; - } - } - - return true; -} - void bdrv_io_plug(BlockDriverState *bs) { BdrvChild *child; diff --git a/block/io_uring.c b/block/io_uring.c index f8a19fd97f..a1760152e0 100644 --- a/block/io_uring.c +++ b/block/io_uring.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include #include "block/aio.h" +#include "qemu/error-report.h" #include "qemu/queue.h" #include "block/block.h" #include "block/raw-aio.h" diff --git a/block/iscsi.c b/block/iscsi.c index d707d0b354..a316d46d96 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -290,7 +290,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, } } -static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) +static void coroutine_fn +iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) { *iTask = (struct IscsiTask) { .co = qemu_coroutine_self(), @@ -2065,7 +2066,7 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) uint64_t max_xfer_len = iscsilun->use_16_for_rw ? 0xffffffff : 0xffff; unsigned int block_size = MAX(BDRV_SECTOR_SIZE, iscsilun->block_size); - assert(iscsilun->block_size >= BDRV_SECTOR_SIZE || bs->sg); + assert(iscsilun->block_size >= BDRV_SECTOR_SIZE || bdrv_is_sg(bs)); bs->bl.request_alignment = block_size; diff --git a/block/linux-aio.c b/block/linux-aio.c index 9c2393a2f7..d2cfb7f523 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -461,7 +461,7 @@ LinuxAioState *laio_init(Error **errp) s = g_malloc0(sizeof(*s)); rc = event_notifier_init(&s->e, false); if (rc < 0) { - error_setg_errno(errp, -rc, "failed to to initialize event notifier"); + error_setg_errno(errp, -rc, "failed to initialize event notifier"); goto out_free_state; } diff --git a/block/mirror.c b/block/mirror.c index 3c4ab1159d..80c0109d39 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -894,6 +894,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) BlockDriverState *bs = s->mirror_top_bs->backing->bs; BlockDriverState *target_bs = blk_bs(s->target); bool need_drain = true; + BlockDeviceIoStatus iostatus; int64_t length; int64_t target_length; BlockDriverInfo bdi; @@ -1016,8 +1017,11 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) * We do so every BLKOCK_JOB_SLICE_TIME nanoseconds, or when there is * an error, or when the source is clean, whichever comes first. */ delta = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->last_pause_ns; + WITH_JOB_LOCK_GUARD() { + iostatus = s->common.iostatus; + } if (delta < BLOCK_JOB_SLICE_TIME && - s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) { + iostatus == BLOCK_DEVICE_IO_STATUS_OK) { if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 || (cnt == 0 && s->in_flight > 0)) { trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight); @@ -1152,8 +1156,10 @@ static void mirror_complete(Job *job, Error **errp) s->should_complete = true; /* If the job is paused, it will be re-entered when it is resumed */ - if (!job->paused) { - job_enter(job); + WITH_JOB_LOCK_GUARD() { + if (!job->paused) { + job_enter_cond_locked(job, NULL); + } } } @@ -1173,8 +1179,11 @@ static bool mirror_drained_poll(BlockJob *job) * from one of our own drain sections, to avoid a deadlock waiting for * ourselves. */ - if (!s->common.job.paused && !job_is_cancelled(&job->job) && !s->in_drain) { - return true; + WITH_JOB_LOCK_GUARD() { + if (!s->common.job.paused && !job_is_cancelled_locked(&job->job) + && !s->in_drain) { + return true; + } } return !!s->in_flight; diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index bfb3c043a0..939a520d17 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -638,16 +638,16 @@ static void print_block_info(Monitor *mon, BlockInfo *info, assert(!info || !info->has_inserted || info->inserted == inserted); if (info && *info->device) { - monitor_printf(mon, "%s", info->device); + monitor_puts(mon, info->device); if (inserted && inserted->has_node_name) { monitor_printf(mon, " (%s)", inserted->node_name); } } else { assert(info || inserted); - monitor_printf(mon, "%s", - inserted && inserted->has_node_name ? inserted->node_name - : info && info->has_qdev ? info->qdev - : ""); + monitor_puts(mon, + inserted && inserted->has_node_name ? inserted->node_name + : info && info->has_qdev ? info->qdev + : ""); } if (inserted) { diff --git a/block/nbd.c b/block/nbd.c index 97683cce27..494b9d683e 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -983,11 +983,12 @@ static void nbd_iter_request_error(NBDReplyChunkIter *iter, int ret) * nbd_reply_chunk_iter_receive * The pointer stored in @payload requires g_free() to free it. */ -static bool nbd_reply_chunk_iter_receive(BDRVNBDState *s, - NBDReplyChunkIter *iter, - uint64_t handle, - QEMUIOVector *qiov, NBDReply *reply, - void **payload) +static bool coroutine_fn nbd_reply_chunk_iter_receive(BDRVNBDState *s, + NBDReplyChunkIter *iter, + uint64_t handle, + QEMUIOVector *qiov, + NBDReply *reply, + void **payload) { int ret, request_ret; NBDReply local_reply; diff --git a/block/nfs.c b/block/nfs.c index 444c40b458..596ebe98cb 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -223,7 +223,7 @@ static void nfs_process_write(void *arg) qemu_mutex_unlock(&client->mutex); } -static void nfs_co_init_task(BlockDriverState *bs, NFSRPC *task) +static void coroutine_fn nfs_co_init_task(BlockDriverState *bs, NFSRPC *task) { *task = (NFSRPC) { .co = qemu_coroutine_self(), diff --git a/block/nvme.c b/block/nvme.c index 01fb28aa63..2b24f95164 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -293,34 +293,42 @@ static void nvme_kick(NVMeQueuePair *q) q->need_kick = 0; } -/* Find a free request element if any, otherwise: - * a) if in coroutine context, try to wait for one to become available; - * b) if not in coroutine, return NULL; - */ -static NVMeRequest *nvme_get_free_req(NVMeQueuePair *q) +static NVMeRequest *nvme_get_free_req_nofail_locked(NVMeQueuePair *q) { NVMeRequest *req; - qemu_mutex_lock(&q->lock); - - while (q->free_req_head == -1) { - if (qemu_in_coroutine()) { - trace_nvme_free_req_queue_wait(q->s, q->index); - qemu_co_queue_wait(&q->free_req_queue, &q->lock); - } else { - qemu_mutex_unlock(&q->lock); - return NULL; - } - } - req = &q->reqs[q->free_req_head]; q->free_req_head = req->free_req_next; req->free_req_next = -1; - - qemu_mutex_unlock(&q->lock); return req; } +/* Return a free request element if any, otherwise return NULL. */ +static NVMeRequest *nvme_get_free_req_nowait(NVMeQueuePair *q) +{ + QEMU_LOCK_GUARD(&q->lock); + if (q->free_req_head == -1) { + return NULL; + } + return nvme_get_free_req_nofail_locked(q); +} + +/* + * Wait for a free request to become available if necessary, then + * return it. + */ +static coroutine_fn NVMeRequest *nvme_get_free_req(NVMeQueuePair *q) +{ + QEMU_LOCK_GUARD(&q->lock); + + while (q->free_req_head == -1) { + trace_nvme_free_req_queue_wait(q->s, q->index); + qemu_co_queue_wait(&q->free_req_queue, &q->lock); + } + + return nvme_get_free_req_nofail_locked(q); +} + /* With q->lock */ static void nvme_put_free_req_locked(NVMeQueuePair *q, NVMeRequest *req) { @@ -506,7 +514,7 @@ static int nvme_admin_cmd_sync(BlockDriverState *bs, NvmeCmd *cmd) AioContext *aio_context = bdrv_get_aio_context(bs); NVMeRequest *req; int ret = -EINPROGRESS; - req = nvme_get_free_req(q); + req = nvme_get_free_req_nowait(q); if (!req) { return -EBUSY; } @@ -1234,8 +1242,10 @@ static inline bool nvme_qiov_aligned(BlockDriverState *bs, return true; } -static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes, - QEMUIOVector *qiov, bool is_write, int flags) +static coroutine_fn int nvme_co_prw(BlockDriverState *bs, + uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, bool is_write, + int flags) { BDRVNVMeState *s = bs->opaque; int r; diff --git a/block/parallels.c b/block/parallels.c index 8b235b9505..c1523e7dab 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -165,8 +165,9 @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num, return start_off; } -static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, int *pnum) +static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors, int *pnum) { int ret = 0; BDRVParallelsState *s = bs->opaque; @@ -241,8 +242,8 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, return ret; } - ret = bdrv_co_pwritev(bs->file, s->data_end * BDRV_SECTOR_SIZE, - nb_cow_bytes, buf, 0); + ret = bdrv_co_pwrite(bs->file, s->data_end * BDRV_SECTOR_SIZE, + nb_cow_bytes, buf, 0); qemu_vfree(buf); if (ret < 0) { return ret; diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index e98bafe0f4..7197754843 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -787,10 +787,10 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, } } - /* Actually, even in in-place case ignoring QCOW2_OL_BITMAP_DIRECTORY is not - * necessary, because we drop QCOW2_AUTOCLEAR_BITMAPS when updating bitmap - * directory in-place (actually, turn-off the extension), which is checked - * in qcow2_check_metadata_overlap() */ + /* Actually, even in the in-place case ignoring QCOW2_OL_BITMAP_DIRECTORY + * is not necessary, because we drop QCOW2_AUTOCLEAR_BITMAPS when updating + * bitmap directory in-place (actually, turn-off the extension), which is + * checked in qcow2_check_metadata_overlap() */ ret = qcow2_pre_write_overlap_check( bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size, false); @@ -1208,7 +1208,7 @@ int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) } } - g_slist_foreach(ro_dirty_bitmaps, set_readonly_helper, false); + g_slist_foreach(ro_dirty_bitmaps, set_readonly_helper, (gpointer)false); ret = 0; out: diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index fd32316d6f..0f293950a1 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -884,7 +884,7 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, return 0; } -static int perform_cow(BlockDriverState *bs, QCowL2Meta *m) +static int coroutine_fn perform_cow(BlockDriverState *bs, QCowL2Meta *m) { BDRVQcow2State *s = bs->opaque; Qcow2COWRegion *start = &m->cow_start; @@ -1024,7 +1024,8 @@ fail: return ret; } -int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) +int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs, + QCowL2Meta *m) { BDRVQcow2State *s = bs->opaque; int i, j = 0, l2_index, ret; @@ -1397,8 +1398,9 @@ static int count_single_write_clusters(BlockDriverState *bs, int nb_clusters, * information on cluster allocation may be invalid now. The caller * must start over anyway, so consider *cur_bytes undefined. */ -static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, - uint64_t *cur_bytes, QCowL2Meta **m) +static int coroutine_fn handle_dependencies(BlockDriverState *bs, + uint64_t guest_offset, + uint64_t *cur_bytes, QCowL2Meta **m) { BDRVQcow2State *s = bs->opaque; QCowL2Meta *old_alloc; @@ -1772,9 +1774,10 @@ out: * * Return 0 on success and -errno in error cases */ -int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, - unsigned int *bytes, uint64_t *host_offset, - QCowL2Meta **m) +int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, + unsigned int *bytes, + uint64_t *host_offset, + QCowL2Meta **m) { BDRVQcow2State *s = bs->opaque; uint64_t start, remaining; @@ -2105,8 +2108,8 @@ out: return ret; } -int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, - uint64_t bytes, int flags) +int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, int flags) { BDRVQcow2State *s = bs->opaque; uint64_t end_offset = offset + bytes; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index c4d99817b6..1fbb07ca77 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1206,7 +1206,7 @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, } } -int coroutine_fn qcow2_write_caches(BlockDriverState *bs) +int qcow2_write_caches(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; int ret; @@ -1226,7 +1226,7 @@ int coroutine_fn qcow2_write_caches(BlockDriverState *bs) return 0; } -int coroutine_fn qcow2_flush_caches(BlockDriverState *bs) +int qcow2_flush_caches(BlockDriverState *bs) { int ret = qcow2_write_caches(bs); if (ret < 0) { @@ -3706,7 +3706,7 @@ int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size) return -EIO; } -int qcow2_detect_metadata_preallocation(BlockDriverState *bs) +int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; int64_t i, end_cluster, cluster_count = 0, threshold; diff --git a/block/qcow2.c b/block/qcow2.c index c6c6692fb7..b57f7cc8ee 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -275,6 +275,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, if (ret < 0) { error_setg_errno(errp, -ret, "ERROR: ext_feature_table: " "Could not read table"); + g_free(feature_table); return ret; } @@ -1696,16 +1697,27 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, ret = -EINVAL; goto fail; } + + s->image_backing_file = g_malloc(len + 1); ret = bdrv_pread(bs->file, header.backing_file_offset, len, - bs->auto_backing_file, 0); + s->image_backing_file, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read backing file name"); goto fail; } - bs->auto_backing_file[len] = '\0'; - pstrcpy(bs->backing_file, sizeof(bs->backing_file), - bs->auto_backing_file); - s->image_backing_file = g_strdup(bs->auto_backing_file); + s->image_backing_file[len] = '\0'; + + /* + * Update only when something has changed. This function is called by + * qcow2_co_invalidate_cache(), and we do not want to reset + * auto_backing_file unless necessary. + */ + if (!g_str_equal(s->image_backing_file, bs->backing_file)) { + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + s->image_backing_file); + pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file), + s->image_backing_file); + } } /* @@ -2436,7 +2448,7 @@ static bool merge_cow(uint64_t offset, unsigned bytes, * Return 1 if the COW regions read as zeroes, 0 if not, < 0 on error. * Note that returning 0 does not guarantee non-zero data. */ -static int is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) +static int coroutine_fn is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) { /* * This check is designed for optimization shortcut so it must be @@ -2454,7 +2466,8 @@ static int is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) m->cow_end.nb_bytes); } -static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta) +static int coroutine_fn handle_alloc_space(BlockDriverState *bs, + QCowL2Meta *l2meta) { BDRVQcow2State *s = bs->opaque; QCowL2Meta *m; diff --git a/block/qcow2.h b/block/qcow2.h index ba436a8d0d..3e7c5e80b6 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -874,8 +874,8 @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, int qcow2_update_snapshot_refcount(BlockDriverState *bs, int64_t l1_table_offset, int l1_size, int addend); -int coroutine_fn qcow2_flush_caches(BlockDriverState *bs); -int coroutine_fn qcow2_write_caches(BlockDriverState *bs); +int qcow2_flush_caches(BlockDriverState *bs); +int qcow2_write_caches(BlockDriverState *bs); int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); @@ -895,7 +895,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, void *cb_opaque, Error **errp); int qcow2_shrink_reftable(BlockDriverState *bs); int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); -int qcow2_detect_metadata_preallocation(BlockDriverState *bs); +int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs); /* qcow2-cluster.c functions */ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, @@ -908,9 +908,9 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset, unsigned int *bytes, uint64_t *host_offset, QCow2SubclusterType *subcluster_type); -int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, - unsigned int *bytes, uint64_t *host_offset, - QCowL2Meta **m); +int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset, + unsigned int *bytes, + uint64_t *host_offset, QCowL2Meta **m); int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset, int compressed_size, @@ -918,13 +918,14 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry, uint64_t *coffset, int *csize); -int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); +int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs, + QCowL2Meta *m); void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, uint64_t bytes, enum qcow2_discard_type type, bool full_discard); -int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, - uint64_t bytes, int flags); +int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, int flags); int qcow2_expand_zero_clusters(BlockDriverState *bs, BlockDriverAmendStatusCB *status_cb, diff --git a/block/qed.c b/block/qed.c index 40943e679b..bda00e6257 100644 --- a/block/qed.c +++ b/block/qed.c @@ -254,7 +254,7 @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s) return l2_table; } -static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) +static bool coroutine_fn qed_plug_allocating_write_reqs(BDRVQEDState *s) { qemu_co_mutex_lock(&s->table_lock); @@ -273,7 +273,7 @@ static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) return true; } -static void qed_unplug_allocating_write_reqs(BDRVQEDState *s) +static void coroutine_fn qed_unplug_allocating_write_reqs(BDRVQEDState *s) { qemu_co_mutex_lock(&s->table_lock); assert(s->allocating_write_reqs_plugged); @@ -445,6 +445,8 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, } if ((s->header.features & QED_F_BACKING_FILE)) { + g_autofree char *backing_file_str = NULL; + if ((uint64_t)s->header.backing_filename_offset + s->header.backing_filename_size > s->header.cluster_size * s->header.header_size) { @@ -452,16 +454,21 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, return -EINVAL; } + backing_file_str = g_malloc(sizeof(bs->backing_file)); ret = qed_read_string(bs->file, s->header.backing_filename_offset, s->header.backing_filename_size, - bs->auto_backing_file, - sizeof(bs->auto_backing_file)); + backing_file_str, sizeof(bs->backing_file)); if (ret < 0) { error_setg(errp, "Failed to read backing filename"); return ret; } - pstrcpy(bs->backing_file, sizeof(bs->backing_file), - bs->auto_backing_file); + + if (!g_str_equal(backing_file_str, bs->backing_file)) { + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + backing_file_str); + pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file), + backing_file_str); + } if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) { pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw"); diff --git a/block/quorum.c b/block/quorum.c index f33f30d36b..f9e6539ceb 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -161,11 +161,10 @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b) return a->l == b->l; } -static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs, - QEMUIOVector *qiov, - uint64_t offset, - uint64_t bytes, - int flags) +static QuorumAIOCB *coroutine_fn quorum_aio_get(BlockDriverState *bs, + QEMUIOVector *qiov, + uint64_t offset, uint64_t bytes, + int flags) { BDRVQuorumState *s = bs->opaque; QuorumAIOCB *acb = g_new(QuorumAIOCB, 1); @@ -233,8 +232,6 @@ static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb) return false; } -static int read_fifo_child(QuorumAIOCB *acb); - static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source) { int i; @@ -273,7 +270,7 @@ static void quorum_report_bad_versions(BDRVQuorumState *s, } } -static void quorum_rewrite_entry(void *opaque) +static void coroutine_fn quorum_rewrite_entry(void *opaque) { QuorumCo *co = opaque; QuorumAIOCB *acb = co->acb; @@ -574,7 +571,7 @@ free_exit: quorum_free_vote_list(&acb->votes); } -static void read_quorum_children_entry(void *opaque) +static void coroutine_fn read_quorum_children_entry(void *opaque) { QuorumCo *co = opaque; QuorumAIOCB *acb = co->acb; @@ -602,7 +599,7 @@ static void read_quorum_children_entry(void *opaque) } } -static int read_quorum_children(QuorumAIOCB *acb) +static int coroutine_fn read_quorum_children(QuorumAIOCB *acb) { BDRVQuorumState *s = acb->bs->opaque; int i; @@ -643,7 +640,7 @@ static int read_quorum_children(QuorumAIOCB *acb) return acb->vote_ret; } -static int read_fifo_child(QuorumAIOCB *acb) +static int coroutine_fn read_fifo_child(QuorumAIOCB *acb) { BDRVQuorumState *s = acb->bs->opaque; int n, ret; @@ -664,8 +661,10 @@ static int read_fifo_child(QuorumAIOCB *acb) return ret; } -static int quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, - QEMUIOVector *qiov, BdrvRequestFlags flags) +static int coroutine_fn quorum_co_preadv(BlockDriverState *bs, + int64_t offset, int64_t bytes, + QEMUIOVector *qiov, + BdrvRequestFlags flags) { BDRVQuorumState *s = bs->opaque; QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); @@ -684,7 +683,7 @@ static int quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, return ret; } -static void write_quorum_entry(void *opaque) +static void coroutine_fn write_quorum_entry(void *opaque) { QuorumCo *co = opaque; QuorumAIOCB *acb = co->acb; @@ -715,9 +714,9 @@ static void write_quorum_entry(void *opaque) } } -static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset, - int64_t bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) +static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) { BDRVQuorumState *s = bs->opaque; QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); @@ -746,8 +745,9 @@ static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset, return ret; } -static int quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, - int64_t bytes, BdrvRequestFlags flags) +static int coroutine_fn quorum_co_pwrite_zeroes(BlockDriverState *bs, + int64_t offset, int64_t bytes, + BdrvRequestFlags flags) { return quorum_co_pwritev(bs, offset, bytes, NULL, diff --git a/block/raw-format.c b/block/raw-format.c index 69fd650eaf..f337ac7569 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -411,7 +411,8 @@ static void raw_lock_medium(BlockDriverState *bs, bool locked) bdrv_lock_medium(bs->file->bs, locked); } -static int raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) +static int coroutine_fn raw_co_ioctl(BlockDriverState *bs, + unsigned long int req, void *buf) { BDRVRawState *s = bs->opaque; if (s->offset || s->has_size) { @@ -463,7 +464,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, return -EINVAL; } - bs->sg = bs->file->bs->sg; + bs->sg = bdrv_is_sg(bs->file->bs); bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | (BDRV_REQ_FUA & bs->file->bs->supported_write_flags); bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | @@ -489,7 +490,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, return ret; } - if (bs->sg && (s->offset || s->has_size)) { + if (bdrv_is_sg(bs) && (s->offset || s->has_size)) { error_setg(errp, "Cannot use offset/size with SCSI generic devices"); return -EINVAL; } diff --git a/block/replication.c b/block/replication.c index 55c8f894aa..c67f931f37 100644 --- a/block/replication.c +++ b/block/replication.c @@ -142,6 +142,7 @@ static void replication_close(BlockDriverState *bs) { BDRVReplicationState *s = bs->opaque; Job *commit_job; + GLOBAL_STATE_CODE(); if (s->stage == BLOCK_REPLICATION_RUNNING) { replication_stop(s->rs, false, NULL); @@ -726,7 +727,9 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) * disk, secondary disk in backup_job_completed(). */ if (s->backup_job) { + aio_context_release(aio_context); job_cancel_sync(&s->backup_job->job, true); + aio_context_acquire(aio_context); } if (!failover) { diff --git a/block/throttle.c b/block/throttle.c index 6e8d52fa24..ddd450593a 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -162,7 +162,7 @@ static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs, BDRV_REQ_WRITE_COMPRESSED); } -static int throttle_co_flush(BlockDriverState *bs) +static int coroutine_fn throttle_co_flush(BlockDriverState *bs) { return bdrv_co_flush(bs->file->bs); } diff --git a/block/vmdk.c b/block/vmdk.c index fe07a54866..f7d8856dfb 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1787,10 +1787,11 @@ static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs, return ret; } -static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, - int64_t offset_in_cluster, QEMUIOVector *qiov, - uint64_t qiov_offset, uint64_t n_bytes, - uint64_t offset) +static int coroutine_fn +vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, + int64_t offset_in_cluster, QEMUIOVector *qiov, + uint64_t qiov_offset, uint64_t n_bytes, + uint64_t offset) { int ret; VmdkGrainMarker *data = NULL; @@ -1868,9 +1869,10 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, return ret; } -static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, - int64_t offset_in_cluster, QEMUIOVector *qiov, - int bytes) +static int coroutine_fn +vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, + int64_t offset_in_cluster, QEMUIOVector *qiov, + int bytes) { int ret; int cluster_bytes, buf_bytes; @@ -2015,9 +2017,9 @@ fail: * * Returns: error code with 0 for success. */ -static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, - uint64_t bytes, QEMUIOVector *qiov, - bool zeroed, bool zero_dry_run) +static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, + bool zeroed, bool zero_dry_run) { BDRVVmdkState *s = bs->opaque; VmdkExtent *extent = NULL; diff --git a/blockdev.c b/blockdev.c index 9230888e34..a32bafc07a 100644 --- a/blockdev.c +++ b/blockdev.c @@ -150,14 +150,12 @@ void blockdev_mark_auto_del(BlockBackend *blk) return; } - for (job = block_job_next(NULL); job; job = block_job_next(job)) { + JOB_LOCK_GUARD(); + + for (job = block_job_next_locked(NULL); job; + job = block_job_next_locked(job)) { if (block_job_has_bdrv(job, blk_bs(blk))) { - AioContext *aio_context = job->job.aio_context; - aio_context_acquire(aio_context); - - job_cancel(&job->job, false); - - aio_context_release(aio_context); + job_cancel_locked(&job->job, false); } } @@ -455,6 +453,17 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, } } +static OnOffAuto account_get_opt(QemuOpts *opts, const char *name) +{ + if (!qemu_opt_find(opts, name)) { + return ON_OFF_AUTO_AUTO; + } + if (qemu_opt_get_bool(opts, name, true)) { + return ON_OFF_AUTO_ON; + } + return ON_OFF_AUTO_OFF; +} + /* Takes the ownership of bs_opts */ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, Error **errp) @@ -462,7 +471,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, const char *buf; int bdrv_flags = 0; int on_read_error, on_write_error; - bool account_invalid, account_failed; + OnOffAuto account_invalid, account_failed; bool writethrough, read_only; BlockBackend *blk; BlockDriverState *bs; @@ -496,8 +505,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, /* extract parameters */ snapshot = qemu_opt_get_bool(opts, "snapshot", 0); - account_invalid = qemu_opt_get_bool(opts, "stats-account-invalid", true); - account_failed = qemu_opt_get_bool(opts, "stats-account-failed", true); + account_invalid = account_get_opt(opts, "stats-account-invalid"); + account_failed = account_get_opt(opts, "stats-account-failed"); writethrough = !qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true); @@ -1833,14 +1842,7 @@ static void drive_backup_abort(BlkActionState *common) DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); if (state->job) { - AioContext *aio_context; - - aio_context = bdrv_get_aio_context(state->bs); - aio_context_acquire(aio_context); - job_cancel_sync(&state->job->job, true); - - aio_context_release(aio_context); } } @@ -1934,14 +1936,7 @@ static void blockdev_backup_abort(BlkActionState *common) BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); if (state->job) { - AioContext *aio_context; - - aio_context = bdrv_get_aio_context(state->bs); - aio_context_acquire(aio_context); - job_cancel_sync(&state->job->job, true); - - aio_context_release(aio_context); } } @@ -3302,17 +3297,16 @@ out: aio_context_release(aio_context); } -/* Get a block job using its ID and acquire its AioContext */ -static BlockJob *find_block_job(const char *id, AioContext **aio_context, - Error **errp) +/* + * Get a block job using its ID. Called with job_mutex held. + */ +static BlockJob *find_block_job_locked(const char *id, Error **errp) { BlockJob *job; assert(id != NULL); - *aio_context = NULL; - - job = block_job_get(id); + job = block_job_get_locked(id); if (!job) { error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE, @@ -3320,30 +3314,30 @@ static BlockJob *find_block_job(const char *id, AioContext **aio_context, return NULL; } - *aio_context = block_job_get_aio_context(job); - aio_context_acquire(*aio_context); - return job; } void qmp_block_job_set_speed(const char *device, int64_t speed, Error **errp) { - AioContext *aio_context; - BlockJob *job = find_block_job(device, &aio_context, errp); + BlockJob *job; + + JOB_LOCK_GUARD(); + job = find_block_job_locked(device, errp); if (!job) { return; } - block_job_set_speed(job, speed, errp); - aio_context_release(aio_context); + block_job_set_speed_locked(job, speed, errp); } void qmp_block_job_cancel(const char *device, bool has_force, bool force, Error **errp) { - AioContext *aio_context; - BlockJob *job = find_block_job(device, &aio_context, errp); + BlockJob *job; + + JOB_LOCK_GUARD(); + job = find_block_job_locked(device, errp); if (!job) { return; @@ -3353,97 +3347,94 @@ void qmp_block_job_cancel(const char *device, force = false; } - if (job_user_paused(&job->job) && !force) { + if (job_user_paused_locked(&job->job) && !force) { error_setg(errp, "The block job for device '%s' is currently paused", device); - goto out; + return; } trace_qmp_block_job_cancel(job); - job_user_cancel(&job->job, force, errp); -out: - aio_context_release(aio_context); + job_user_cancel_locked(&job->job, force, errp); } void qmp_block_job_pause(const char *device, Error **errp) { - AioContext *aio_context; - BlockJob *job = find_block_job(device, &aio_context, errp); + BlockJob *job; + + JOB_LOCK_GUARD(); + job = find_block_job_locked(device, errp); if (!job) { return; } trace_qmp_block_job_pause(job); - job_user_pause(&job->job, errp); - aio_context_release(aio_context); + job_user_pause_locked(&job->job, errp); } void qmp_block_job_resume(const char *device, Error **errp) { - AioContext *aio_context; - BlockJob *job = find_block_job(device, &aio_context, errp); + BlockJob *job; + + JOB_LOCK_GUARD(); + job = find_block_job_locked(device, errp); if (!job) { return; } trace_qmp_block_job_resume(job); - job_user_resume(&job->job, errp); - aio_context_release(aio_context); + job_user_resume_locked(&job->job, errp); } void qmp_block_job_complete(const char *device, Error **errp) { - AioContext *aio_context; - BlockJob *job = find_block_job(device, &aio_context, errp); + BlockJob *job; + + JOB_LOCK_GUARD(); + job = find_block_job_locked(device, errp); if (!job) { return; } trace_qmp_block_job_complete(job); - job_complete(&job->job, errp); - aio_context_release(aio_context); + job_complete_locked(&job->job, errp); } void qmp_block_job_finalize(const char *id, Error **errp) { - AioContext *aio_context; - BlockJob *job = find_block_job(id, &aio_context, errp); + BlockJob *job; + + JOB_LOCK_GUARD(); + job = find_block_job_locked(id, errp); if (!job) { return; } trace_qmp_block_job_finalize(job); - job_ref(&job->job); - job_finalize(&job->job, errp); + job_ref_locked(&job->job); + job_finalize_locked(&job->job, errp); - /* - * Job's context might have changed via job_finalize (and job_txn_apply - * automatically acquires the new one), so make sure we release the correct - * one. - */ - aio_context = block_job_get_aio_context(job); - job_unref(&job->job); - aio_context_release(aio_context); + job_unref_locked(&job->job); } void qmp_block_job_dismiss(const char *id, Error **errp) { - AioContext *aio_context; - BlockJob *bjob = find_block_job(id, &aio_context, errp); + BlockJob *bjob; Job *job; + JOB_LOCK_GUARD(); + bjob = find_block_job_locked(id, errp); + if (!bjob) { return; } trace_qmp_block_job_dismiss(bjob); job = &bjob->job; - job_dismiss(&job, errp); - aio_context_release(aio_context); + job_dismiss_locked(&job, errp); } void qmp_change_backing_file(const char *device, @@ -3720,17 +3711,16 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) BlockJobInfoList *head = NULL, **tail = &head; BlockJob *job; - for (job = block_job_next(NULL); job; job = block_job_next(job)) { + JOB_LOCK_GUARD(); + + for (job = block_job_next_locked(NULL); job; + job = block_job_next_locked(job)) { BlockJobInfo *value; - AioContext *aio_context; if (block_job_is_internal(job)) { continue; } - aio_context = block_job_get_aio_context(job); - aio_context_acquire(aio_context); - value = block_job_query(job, errp); - aio_context_release(aio_context); + value = block_job_query_locked(job, errp); if (!value) { qapi_free_BlockJobInfoList(head); return NULL; diff --git a/blockjob.c b/blockjob.c index 4868453d74..bdf20a0e35 100644 --- a/blockjob.c +++ b/blockjob.c @@ -36,21 +36,6 @@ #include "qemu/main-loop.h" #include "qemu/timer.h" -/* - * The block job API is composed of two categories of functions. - * - * The first includes functions used by the monitor. The monitor is - * peculiar in that it accesses the block job list with block_job_get, and - * therefore needs consistency across block_job_get and the actual operation - * (e.g. block_job_set_speed). The consistency is achieved with - * aio_context_acquire/release. These functions are declared in blockjob.h. - * - * The second includes functions used by the block job drivers and sometimes - * by the core block layer. These do not care about locking, because the - * whole coroutine runs under the AioContext lock, and are declared in - * blockjob_int.h. - */ - static bool is_block_job(Job *job) { return job_type(job) == JOB_TYPE_BACKUP || @@ -59,21 +44,21 @@ static bool is_block_job(Job *job) job_type(job) == JOB_TYPE_STREAM; } -BlockJob *block_job_next(BlockJob *bjob) +BlockJob *block_job_next_locked(BlockJob *bjob) { Job *job = bjob ? &bjob->job : NULL; GLOBAL_STATE_CODE(); do { - job = job_next(job); + job = job_next_locked(job); } while (job && !is_block_job(job)); return job ? container_of(job, BlockJob, job) : NULL; } -BlockJob *block_job_get(const char *id) +BlockJob *block_job_get_locked(const char *id) { - Job *job = job_get(id); + Job *job = job_get_locked(id); GLOBAL_STATE_CODE(); if (job && is_block_job(job)) { @@ -83,6 +68,12 @@ BlockJob *block_job_get(const char *id) } } +BlockJob *block_job_get(const char *id) +{ + JOB_LOCK_GUARD(); + return block_job_get_locked(id); +} + void block_job_free(Job *job) { BlockJob *bjob = container_of(job, BlockJob, job); @@ -114,8 +105,10 @@ static bool child_job_drained_poll(BdrvChild *c) /* An inactive or completed job doesn't have any pending requests. Jobs * with !job->busy are either already paused or have a pause point after * being reentered, so no job driver code will run before they pause. */ - if (!job->busy || job_is_completed(job)) { - return false; + WITH_JOB_LOCK_GUARD() { + if (!job->busy || job_is_completed_locked(job)) { + return false; + } } /* Otherwise, assume that it isn't fully stopped yet, but allow the job to @@ -163,12 +156,13 @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx, bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore); } - job->job.aio_context = ctx; + job_set_aio_context(&job->job, ctx); } static AioContext *child_job_get_parent_aio_context(BdrvChild *c) { BlockJob *job = c->opaque; + GLOBAL_STATE_CODE(); return job->job.aio_context; } @@ -250,7 +244,8 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, return 0; } -static void block_job_on_idle(Notifier *n, void *opaque) +/* Called with job_mutex lock held. */ +static void block_job_on_idle_locked(Notifier *n, void *opaque) { aio_wait_kick(); } @@ -271,14 +266,14 @@ static bool job_timer_pending(Job *job) return timer_pending(&job->sleep_timer); } -bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) +bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp) { const BlockJobDriver *drv = block_job_driver(job); int64_t old_speed = job->speed; GLOBAL_STATE_CODE(); - if (job_apply_verb(&job->job, JOB_VERB_SET_SPEED, errp) < 0) { + if (job_apply_verb_locked(&job->job, JOB_VERB_SET_SPEED, errp) < 0) { return false; } if (speed < 0) { @@ -292,7 +287,9 @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) job->speed = speed; if (drv->set_speed) { + job_unlock(); drv->set_speed(job, speed); + job_lock(); } if (speed && speed <= old_speed) { @@ -300,18 +297,24 @@ bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) } /* kick only if a timer is pending */ - job_enter_cond(&job->job, job_timer_pending); + job_enter_cond_locked(&job->job, job_timer_pending); return true; } +static bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) +{ + JOB_LOCK_GUARD(); + return block_job_set_speed_locked(job, speed, errp); +} + int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) { IO_CODE(); return ratelimit_calculate_delay(&job->limit, n); } -BlockJobInfo *block_job_query(BlockJob *job, Error **errp) +BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) { BlockJobInfo *info; uint64_t progress_current, progress_total; @@ -329,13 +332,13 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) info = g_new0(BlockJobInfo, 1); info->type = g_strdup(job_type_str(&job->job)); info->device = g_strdup(job->job.id); - info->busy = qatomic_read(&job->job.busy); + info->busy = job->job.busy; info->paused = job->job.pause_count > 0; info->offset = progress_current; info->len = progress_total; info->speed = job->speed; info->io_status = job->iostatus; - info->ready = job_is_ready(&job->job), + info->ready = job_is_ready_locked(&job->job), info->status = job->job.status; info->auto_finalize = job->job.auto_finalize; info->auto_dismiss = job->job.auto_dismiss; @@ -348,7 +351,8 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) return info; } -static void block_job_iostatus_set_err(BlockJob *job, int error) +/* Called with job lock held */ +static void block_job_iostatus_set_err_locked(BlockJob *job, int error) { if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE : @@ -356,7 +360,8 @@ static void block_job_iostatus_set_err(BlockJob *job, int error) } } -static void block_job_event_cancelled(Notifier *n, void *opaque) +/* Called with job_mutex lock held. */ +static void block_job_event_cancelled_locked(Notifier *n, void *opaque) { BlockJob *job = opaque; uint64_t progress_current, progress_total; @@ -375,7 +380,8 @@ static void block_job_event_cancelled(Notifier *n, void *opaque) job->speed); } -static void block_job_event_completed(Notifier *n, void *opaque) +/* Called with job_mutex lock held. */ +static void block_job_event_completed_locked(Notifier *n, void *opaque) { BlockJob *job = opaque; const char *msg = NULL; @@ -401,7 +407,8 @@ static void block_job_event_completed(Notifier *n, void *opaque) msg); } -static void block_job_event_pending(Notifier *n, void *opaque) +/* Called with job_mutex lock held. */ +static void block_job_event_pending_locked(Notifier *n, void *opaque) { BlockJob *job = opaque; @@ -413,7 +420,8 @@ static void block_job_event_pending(Notifier *n, void *opaque) job->job.id); } -static void block_job_event_ready(Notifier *n, void *opaque) +/* Called with job_mutex lock held. */ +static void block_job_event_ready_locked(Notifier *n, void *opaque) { BlockJob *job = opaque; uint64_t progress_current, progress_total; @@ -433,11 +441,6 @@ static void block_job_event_ready(Notifier *n, void *opaque) } -/* - * API for block job drivers and the block layer. These functions are - * declared in blockjob_int.h. - */ - void *block_job_create(const char *job_id, const BlockJobDriver *driver, JobTxn *txn, BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, int64_t speed, int flags, @@ -463,19 +466,21 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, ratelimit_init(&job->limit); - job->finalize_cancelled_notifier.notify = block_job_event_cancelled; - job->finalize_completed_notifier.notify = block_job_event_completed; - job->pending_notifier.notify = block_job_event_pending; - job->ready_notifier.notify = block_job_event_ready; - job->idle_notifier.notify = block_job_on_idle; + job->finalize_cancelled_notifier.notify = block_job_event_cancelled_locked; + job->finalize_completed_notifier.notify = block_job_event_completed_locked; + job->pending_notifier.notify = block_job_event_pending_locked; + job->ready_notifier.notify = block_job_event_ready_locked; + job->idle_notifier.notify = block_job_on_idle_locked; - notifier_list_add(&job->job.on_finalize_cancelled, - &job->finalize_cancelled_notifier); - notifier_list_add(&job->job.on_finalize_completed, - &job->finalize_completed_notifier); - notifier_list_add(&job->job.on_pending, &job->pending_notifier); - notifier_list_add(&job->job.on_ready, &job->ready_notifier); - notifier_list_add(&job->job.on_idle, &job->idle_notifier); + WITH_JOB_LOCK_GUARD() { + notifier_list_add(&job->job.on_finalize_cancelled, + &job->finalize_cancelled_notifier); + notifier_list_add(&job->job.on_finalize_completed, + &job->finalize_completed_notifier); + notifier_list_add(&job->job.on_pending, &job->pending_notifier); + notifier_list_add(&job->job.on_ready, &job->ready_notifier); + notifier_list_add(&job->job.on_idle, &job->idle_notifier); + } error_setg(&job->blocker, "block device is in use by block job: %s", job_type_str(&job->job)); @@ -498,7 +503,7 @@ fail: return NULL; } -void block_job_iostatus_reset(BlockJob *job) +void block_job_iostatus_reset_locked(BlockJob *job) { GLOBAL_STATE_CODE(); if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { @@ -508,6 +513,12 @@ void block_job_iostatus_reset(BlockJob *job) job->iostatus = BLOCK_DEVICE_IO_STATUS_OK; } +static void block_job_iostatus_reset(BlockJob *job) +{ + JOB_LOCK_GUARD(); + block_job_iostatus_reset_locked(job); +} + void block_job_user_resume(Job *job) { BlockJob *bjob = container_of(job, BlockJob, job); @@ -546,12 +557,17 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, action); } if (action == BLOCK_ERROR_ACTION_STOP) { - if (!job->job.user_paused) { - job_pause(&job->job); - /* make the pause user visible, which will be resumed from QMP. */ - job->job.user_paused = true; + WITH_JOB_LOCK_GUARD() { + if (!job->job.user_paused) { + job_pause_locked(&job->job); + /* + * make the pause user visible, which will be + * resumed from QMP. + */ + job->job.user_paused = true; + } + block_job_iostatus_set_err_locked(job, error); } - block_job_iostatus_set_err(job, error); } return action; } diff --git a/chardev/baum.c b/chardev/baum.c index 79d618e350..0a0d12661a 100644 --- a/chardev/baum.c +++ b/chardev/baum.c @@ -87,6 +87,9 @@ #define BUF_SIZE 256 +#define X_MAX 84 +#define Y_MAX 1 + struct BaumChardev { Chardev parent; @@ -244,11 +247,11 @@ static int baum_deferred_init(BaumChardev *baum) brlapi_perror("baum: brlapi__getDisplaySize"); return 0; } - if (baum->y > 1) { - baum->y = 1; + if (baum->y > Y_MAX) { + baum->y = Y_MAX; } - if (baum->x > 84) { - baum->x = 84; + if (baum->x > X_MAX) { + baum->x = X_MAX; } con = qemu_console_lookup_by_index(0); @@ -296,7 +299,8 @@ static void baum_chr_accept_input(struct Chardev *chr) static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len) { Chardev *chr = CHARDEV(baum); - uint8_t io_buf[1 + 2 * len], *cur = io_buf; + g_autofree uint8_t *io_buf = g_malloc(1 + 2 * len); + uint8_t *cur = io_buf; int room; *cur++ = ESC; while (len--) @@ -380,9 +384,9 @@ static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len) switch (req) { case BAUM_REQ_DisplayData: { - uint8_t cells[baum->x * baum->y], c; - uint8_t text[baum->x * baum->y]; - uint8_t zero[baum->x * baum->y]; + uint8_t cells[X_MAX * Y_MAX], c; + uint8_t text[X_MAX * Y_MAX]; + uint8_t zero[X_MAX * Y_MAX]; int cursor = BRLAPI_CURSOR_OFF; int i; @@ -405,7 +409,7 @@ static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len) } timer_del(baum->cellCount_timer); - memset(zero, 0, sizeof(zero)); + memset(zero, 0, baum->x * baum->y); brlapi_writeArguments_t wa = { .displayNumber = BRLAPI_DISPLAY_DEFAULT, diff --git a/chardev/char-socket.c b/chardev/char-socket.c index dc4e218eeb..879564aa8a 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -557,12 +557,10 @@ static char *qemu_chr_compute_filename(SocketChardev *s) const char *left = "", *right = ""; switch (ss->ss_family) { -#ifndef _WIN32 case AF_UNIX: return g_strdup_printf("unix:%s%s", ((struct sockaddr_un *)(ss))->sun_path, s->is_listen ? ",server=on" : ""); -#endif case AF_INET6: left = "["; right = "]"; @@ -1372,10 +1370,12 @@ static void qmp_chardev_open_socket(Chardev *chr, } qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE); +#ifndef _WIN32 /* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */ if (addr->type == SOCKET_ADDRESS_TYPE_UNIX) { qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS); } +#endif /* * In the chardev-change special-case, we shouldn't register a new yank diff --git a/chardev/char.c b/chardev/char.c index 0169d8dde4..b005df3ccf 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -193,7 +193,7 @@ int qemu_chr_be_can_write(Chardev *s) return be->chr_can_read(be->opaque); } -void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len) +void qemu_chr_be_write_impl(Chardev *s, const uint8_t *buf, int len) { CharBackend *be = s->be; @@ -202,7 +202,7 @@ void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len) } } -void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len) +void qemu_chr_be_write(Chardev *s, const uint8_t *buf, int len) { if (qemu_chr_replay(s)) { if (replay_mode == REPLAY_MODE_PLAY) { diff --git a/chardev/msmouse.c b/chardev/msmouse.c index eb9231dcdb..ab8fe981d6 100644 --- a/chardev/msmouse.c +++ b/chardev/msmouse.c @@ -24,23 +24,45 @@ #include "qemu/osdep.h" #include "qemu/module.h" +#include "qemu/fifo8.h" #include "chardev/char.h" +#include "chardev/char-serial.h" #include "ui/console.h" #include "ui/input.h" #include "qom/object.h" -#define MSMOUSE_LO6(n) ((n) & 0x3f) -#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) +#define MSMOUSE_LO6(n) ((n) & 0x3f) +#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) +#define MSMOUSE_PWR(cm) (cm & (CHR_TIOCM_RTS | CHR_TIOCM_DTR)) + +/* Serial PnP for 6 bit devices/mice sends all ASCII chars - 0x20 */ +#define M(c) (c - 0x20) +/* Serial fifo size. */ +#define MSMOUSE_BUF_SZ 64 + +/* Mouse ID: Send "M3" cause we behave like a 3 button logitech mouse. */ +const uint8_t mouse_id[] = {'M', '3'}; +/* + * PnP start "(", PnP version (1.0), vendor ID, product ID, '\\', + * serial ID (omitted), '\\', MS class name, '\\', driver ID (omitted), '\\', + * product description, checksum, ")" + * Missing parts are inserted later. + */ +const uint8_t pnp_data[] = {M('('), 1, '$', M('Q'), M('M'), M('U'), + M('0'), M('0'), M('0'), M('1'), + M('\\'), M('\\'), + M('M'), M('O'), M('U'), M('S'), M('E'), + M('\\'), M('\\')}; struct MouseChardev { Chardev parent; QemuInputHandlerState *hs; + int tiocm; int axis[INPUT_AXIS__MAX]; bool btns[INPUT_BUTTON__MAX]; bool btnc[INPUT_BUTTON__MAX]; - uint8_t outbuf[32]; - int outlen; + Fifo8 outbuf; }; typedef struct MouseChardev MouseChardev; @@ -51,20 +73,18 @@ DECLARE_INSTANCE_CHECKER(MouseChardev, MOUSE_CHARDEV, static void msmouse_chr_accept_input(Chardev *chr) { MouseChardev *mouse = MOUSE_CHARDEV(chr); - int len; + uint32_t len, avail; len = qemu_chr_be_can_write(chr); - if (len > mouse->outlen) { - len = mouse->outlen; - } - if (!len) { - return; - } + avail = fifo8_num_used(&mouse->outbuf); + while (len > 0 && avail > 0) { + const uint8_t *buf; + uint32_t size; - qemu_chr_be_write(chr, mouse->outbuf, len); - mouse->outlen -= len; - if (mouse->outlen) { - memmove(mouse->outbuf, mouse->outbuf + len, mouse->outlen); + buf = fifo8_pop_buf(&mouse->outbuf, MIN(len, avail), &size); + qemu_chr_be_write(chr, buf, size); + len = qemu_chr_be_can_write(chr); + avail -= size; } } @@ -91,12 +111,11 @@ static void msmouse_queue_event(MouseChardev *mouse) mouse->btnc[INPUT_BUTTON_MIDDLE]) { bytes[3] |= (mouse->btns[INPUT_BUTTON_MIDDLE] ? 0x20 : 0x00); mouse->btnc[INPUT_BUTTON_MIDDLE] = false; - count = 4; + count++; } - if (mouse->outlen <= sizeof(mouse->outbuf) - count) { - memcpy(mouse->outbuf + mouse->outlen, bytes, count); - mouse->outlen += count; + if (fifo8_num_free(&mouse->outbuf) >= count) { + fifo8_push_all(&mouse->outbuf, bytes, count); } else { /* queue full -> drop event */ } @@ -109,6 +128,11 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src, InputMoveEvent *move; InputBtnEvent *btn; + /* Ignore events if serial mouse powered down. */ + if (!MSMOUSE_PWR(mouse->tiocm)) { + return; + } + switch (evt->type) { case INPUT_EVENT_KIND_REL: move = evt->u.rel.data; @@ -132,6 +156,11 @@ static void msmouse_input_sync(DeviceState *dev) MouseChardev *mouse = MOUSE_CHARDEV(dev); Chardev *chr = CHARDEV(dev); + /* Ignore events if serial mouse powered down. */ + if (!MSMOUSE_PWR(mouse->tiocm)) { + return; + } + msmouse_queue_event(mouse); msmouse_chr_accept_input(chr); } @@ -142,13 +171,6 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len) return len; } -static void char_msmouse_finalize(Object *obj) -{ - MouseChardev *mouse = MOUSE_CHARDEV(obj); - - qemu_input_handler_unregister(mouse->hs); -} - static QemuInputHandler msmouse_handler = { .name = "QEMU Microsoft Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, @@ -156,6 +178,81 @@ static QemuInputHandler msmouse_handler = { .sync = msmouse_input_sync, }; +static int msmouse_ioctl(Chardev *chr, int cmd, void *arg) +{ + MouseChardev *mouse = MOUSE_CHARDEV(chr); + int c, i, j; + uint8_t bytes[MSMOUSE_BUF_SZ / 2]; + int *targ = (int *)arg; + const uint8_t hexchr[16] = {M('0'), M('1'), M('2'), M('3'), M('4'), M('5'), + M('6'), M('7'), M('8'), M('9'), M('A'), M('B'), + M('C'), M('D'), M('E'), M('F')}; + + switch (cmd) { + case CHR_IOCTL_SERIAL_SET_TIOCM: + c = mouse->tiocm; + mouse->tiocm = *(int *)arg; + if (MSMOUSE_PWR(mouse->tiocm)) { + if (!MSMOUSE_PWR(c)) { + /* + * Power on after reset: Send ID and PnP data + * No need to check fifo space as it is empty at this point. + */ + fifo8_push_all(&mouse->outbuf, mouse_id, sizeof(mouse_id)); + /* Add PnP data: */ + fifo8_push_all(&mouse->outbuf, pnp_data, sizeof(pnp_data)); + /* + * Add device description from qemu handler name. + * Make sure this all fits into the queue beforehand! + */ + c = M(')'); + for (i = 0; msmouse_handler.name[i]; i++) { + bytes[i] = M(msmouse_handler.name[i]); + c += bytes[i]; + } + /* Calc more of checksum */ + for (j = 0; j < sizeof(pnp_data); j++) { + c += pnp_data[j]; + } + c &= 0xff; + bytes[i++] = hexchr[c >> 4]; + bytes[i++] = hexchr[c & 0x0f]; + bytes[i++] = M(')'); + fifo8_push_all(&mouse->outbuf, bytes, i); + /* Start sending data to serial. */ + msmouse_chr_accept_input(chr); + } + break; + } + /* + * Reset mouse buffers on power down. + * Mouse won't send anything without power. + */ + fifo8_reset(&mouse->outbuf); + memset(mouse->axis, 0, sizeof(mouse->axis)); + memset(mouse->btns, false, sizeof(mouse->btns)); + memset(mouse->btnc, false, sizeof(mouse->btns)); + break; + case CHR_IOCTL_SERIAL_GET_TIOCM: + /* Remember line control status. */ + *targ = mouse->tiocm; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static void char_msmouse_finalize(Object *obj) +{ + MouseChardev *mouse = MOUSE_CHARDEV(obj); + + if (mouse->hs) { + qemu_input_handler_unregister(mouse->hs); + } + fifo8_destroy(&mouse->outbuf); +} + static void msmouse_chr_open(Chardev *chr, ChardevBackend *backend, bool *be_opened, @@ -166,6 +263,8 @@ static void msmouse_chr_open(Chardev *chr, *be_opened = false; mouse->hs = qemu_input_handler_register((DeviceState *)mouse, &msmouse_handler); + mouse->tiocm = 0; + fifo8_create(&mouse->outbuf, MSMOUSE_BUF_SZ); } static void char_msmouse_class_init(ObjectClass *oc, void *data) @@ -175,6 +274,7 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data) cc->open = msmouse_chr_open; cc->chr_write = msmouse_chr_write; cc->chr_accept_input = msmouse_chr_accept_input; + cc->chr_ioctl = msmouse_ioctl; } static const TypeInfo char_msmouse_type_info = { diff --git a/chardev/wctablet.c b/chardev/wctablet.c index e8b292c43c..43bdf6b608 100644 --- a/chardev/wctablet.c +++ b/chardev/wctablet.c @@ -319,7 +319,9 @@ static void wctablet_chr_finalize(Object *obj) { TabletChardev *tablet = WCTABLET_CHARDEV(obj); - qemu_input_handler_unregister(tablet->hs); + if (tablet->hs) { + qemu_input_handler_unregister(tablet->hs); + } } static void wctablet_chr_open(Chardev *chr, diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a..89c39e3123 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -3,3 +3,4 @@ # Boards: # CONFIG_OR1K_SIM=y +CONFIG_OR1K_VIRT=y diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak index 483474ba93..9abc99056f 100644 --- a/configs/targets/loongarch64-softmmu.mak +++ b/configs/targets/loongarch64-softmmu.mak @@ -1,5 +1,5 @@ TARGET_ARCH=loongarch64 TARGET_BASE_ARCH=loongarch TARGET_SUPPORTS_MTTCG=y -TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml +TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml TARGET_NEED_FDT=y diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 263e970870..432f855a30 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=openrisc +TARGET_SUPPORTS_MTTCG=y TARGET_BIG_ENDIAN=y TARGET_NEED_FDT=y diff --git a/configure b/configure index 7acaf49040..68867c50a8 100755 --- a/configure +++ b/configure @@ -57,7 +57,7 @@ GNUmakefile: ; EOF cd build - exec $source_path/configure "$@" + exec "$source_path/configure" "$@" fi # Temporary directory used for files created while @@ -67,8 +67,7 @@ fi # it when configure exits.) TMPDIR1="config-temp" rm -rf "${TMPDIR1}" -mkdir -p "${TMPDIR1}" -if [ $? -ne 0 ]; then +if ! mkdir -p "${TMPDIR1}"; then echo "ERROR: failed to create temporary directory" exit 1 fi @@ -76,7 +75,6 @@ fi TMPB="qemu-conf" TMPC="${TMPDIR1}/${TMPB}.c" TMPO="${TMPDIR1}/${TMPB}.o" -TMPCXX="${TMPDIR1}/${TMPB}.cxx" TMPM="${TMPDIR1}/${TMPB}.m" TMPE="${TMPDIR1}/${TMPB}.exe" @@ -111,7 +109,7 @@ error_exit() { do_compiler() { # Run the compiler, capturing its output to the log. First argument # is compiler binary to execute. - local compiler="$1" + compiler="$1" shift if test -n "$BASH_VERSION"; then eval ' echo >>config.log " @@ -159,10 +157,6 @@ do_cc() { do_compiler_werror "$cc" $CPU_CFLAGS "$@" } -do_cxx() { - do_compiler_werror "$cxx" $CPU_CFLAGS "$@" -} - do_objc() { do_compiler_werror "$objcc" $CPU_CFLAGS "$@" } @@ -172,24 +166,6 @@ add_to() { eval $1=\${$1:+\"\$$1 \"}\$2 } -update_cxxflags() { - # Set QEMU_CXXFLAGS from QEMU_CFLAGS by filtering out those - # options which some versions of GCC's C++ compiler complain about - # because they only make sense for C programs. - QEMU_CXXFLAGS="-D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS" - CONFIGURE_CXXFLAGS=$(echo "$CONFIGURE_CFLAGS" | sed s/-std=gnu11/-std=gnu++11/) - for arg in $QEMU_CFLAGS; do - case $arg in - -Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\ - -Wold-style-declaration|-Wold-style-definition|-Wredundant-decls) - ;; - *) - QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }$arg - ;; - esac - done -} - compile_object() { local_cflags="$1" do_cc $CFLAGS $EXTRA_CFLAGS $CONFIGURE_CFLAGS $QEMU_CFLAGS $local_cflags -c -o $TMPO $TMPC @@ -311,7 +287,6 @@ pie="" coroutine="" plugins="$default_feature" meson="" -meson_args="" ninja="" bindir="bin" skip_meson=no @@ -321,11 +296,6 @@ vfio_user_server="disabled" # are included in the automatically generated help message) # 1. Track which submodules are needed -if test "$default_feature" = no ; then - slirp="disabled" -else - slirp="auto" -fi fdt="auto" # 2. Automatically enable/disable other options @@ -695,20 +665,21 @@ meson_option_build_array() { meson_option_build_array() { printf '[' - (if test "$targetos" == windows; then + (if test "$targetos" = windows; then IFS=\; else IFS=: fi for e in $1; do - e=${e/'\'/'\\'} - e=${e/\"/'\"'} - printf '"""%s""",' "$e" + printf '"""' + # backslash escape any '\' and '"' characters + printf "%s" "$e" | sed -e 's/\([\"]\)/\\\1/g' + printf '""",' done) printf ']\n' } -. $source_path/scripts/meson-buildoptions.sh +. "$source_path/scripts/meson-buildoptions.sh" meson_options= meson_option_add() { @@ -728,7 +699,7 @@ for opt do case "$opt" in --help|-h) show_help=yes ;; - --version|-V) exec cat $source_path/VERSION + --version|-V) exec cat "$source_path/VERSION" ;; --prefix=*) prefix="$optarg" ;; @@ -845,14 +816,6 @@ for opt do ;; --disable-tsan) tsan="no" ;; - --disable-slirp) slirp="disabled" - ;; - --enable-slirp) slirp="enabled" - ;; - --enable-slirp=git) slirp="internal" - ;; - --enable-slirp=*) slirp="$optarg" - ;; --disable-tcg) tcg="disabled" plugins="no" ;; @@ -1017,7 +980,7 @@ default_target_list="" mak_wilds="" if [ "$linux_user" != no ]; then - if [ "$targetos" = linux ] && [ -d $source_path/linux-user/include/host/$cpu ]; then + if [ "$targetos" = linux ] && [ -d "$source_path/linux-user/include/host/$cpu" ]; then linux_user=yes elif [ "$linux_user" = yes ]; then error_exit "linux-user not supported on this architecture" @@ -1027,7 +990,7 @@ if [ "$bsd_user" != no ]; then if [ "$bsd_user" = "" ]; then test $targetos = freebsd && bsd_user=yes fi - if [ "$bsd_user" = yes ] && ! [ -d $source_path/bsd-user/$targetos ]; then + if [ "$bsd_user" = yes ] && ! [ -d "$source_path/bsd-user/$targetos" ]; then error_exit "bsd-user not supported on this host OS" fi fi @@ -1125,7 +1088,7 @@ exit 0 fi # Remove old dependency files to make sure that they get properly regenerated -rm -f */config-devices.mak.d +rm -f ./*/config-devices.mak.d if test -z "$python" then @@ -1143,16 +1106,13 @@ if ! $python -c 'import sys; sys.exit(sys.version_info < (3,6))'; then "Use --python=/path/to/python to specify a supported Python." fi -# Preserve python version since some functionality is dependent on it -python_version=$($python -c 'import sys; print("%d.%d.%d" % (sys.version_info[0], sys.version_info[1], sys.version_info[2]))' 2>/dev/null) - # Suppress writing compiled files python="$python -B" if test -z "$meson"; then - if test "$explicit_python" = no && has meson && version_ge "$(meson --version)" 0.59.3; then + if test "$explicit_python" = no && has meson && version_ge "$(meson --version)" 0.61.5; then meson=meson - elif test $git_submodules_action != 'ignore' ; then + elif test "$git_submodules_action" != 'ignore' ; then meson=git elif test -e "${source_path}/meson/meson.py" ; then meson=internal @@ -1289,6 +1249,7 @@ add_to nowarn_flags -Wno-string-plus-int add_to nowarn_flags -Wno-typedef-redefinition add_to nowarn_flags -Wno-tautological-type-limit-compare add_to nowarn_flags -Wno-psabi +add_to nowarn_flags -Wno-gnu-variable-sized-type-not-at-end gcc_flags="$warn_flags $nowarn_flags" @@ -1401,18 +1362,19 @@ EOF if test "$static" = "yes"; then if test "$pie" != "no" && compile_prog "-Werror -fPIE -DPIE" "-static-pie"; then CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS" - QEMU_LDFLAGS="-static-pie $QEMU_LDFLAGS" pie="yes" elif test "$pie" = "yes"; then error_exit "-static-pie not available due to missing toolchain support" else - QEMU_LDFLAGS="-static $QEMU_LDFLAGS" pie="no" fi elif test "$pie" = "no"; then if compile_prog "-Werror -fno-pie" "-no-pie"; then CONFIGURE_CFLAGS="-fno-pie $CONFIGURE_CFLAGS" CONFIGURE_LDFLAGS="-no-pie $CONFIGURE_LDFLAGS" + # Meson currently only handles pie as a boolean for now so if we have + # explicitly disabled PIE we need to extend our cflags because it wont. + QEMU_CFLAGS="-fno-pie -no-pie $QEMU_CFLAGS" fi elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS" @@ -1425,12 +1387,6 @@ else pie="no" fi -# Detect support for PT_GNU_RELRO + DT_BIND_NOW. -# The combination is known as "full relro", because .got.plt is read-only too. -if compile_prog "" "-Wl,-z,relro -Wl,-z,now" ; then - QEMU_LDFLAGS="-Wl,-z,relro -Wl,-z,now $QEMU_LDFLAGS" -fi - ########################################## # __sync_fetch_and_and requires at least -march=i486. Many toolchains # use i686 as default anyway, but for those that don't, an explicit @@ -1499,15 +1455,6 @@ if test "$tcg" = "enabled"; then git_submodules="$git_submodules tests/fp/berkeley-softfloat-3" fi -feature_not_found() { - feature=$1 - remedy=$2 - - error_exit "User requested feature $feature" \ - "configure was not able to find it." \ - "$remedy" -} - # --- # big/little endian test cat > $TMPC << EOF @@ -1670,7 +1617,7 @@ else ;; ucontext) if test "$ucontext_works" != "yes"; then - feature_not_found "ucontext" + error_exit "'ucontext' backend requested but makecontext not available" fi ;; sigaltstack) @@ -1859,23 +1806,18 @@ EOF fi fi -########################################## -# check for slirp - -case "$slirp" in - auto | enabled | internal) - # Simpler to always update submodule, even if not needed. - git_submodules="${git_submodules} slirp" - ;; -esac - ########################################## # functions to probe cross compilers container="no" if test $use_containers = "yes"; then - if has "docker" || has "podman"; then - container=$($python $source_path/tests/docker/docker.py probe) + case $($python "$source_path"/tests/docker/docker.py probe) in + *docker) container=docker ;; + podman) container=podman ;; + no) container=no ;; + esac + if test "$container" != "no"; then + docker_py="$python $source_path/tests/docker/docker.py --engine $container" fi fi @@ -2059,7 +2001,7 @@ probe_target_compiler() { ;; ppc64|ppc64le) container_image=debian-powerpc-test-cross - container_cross_prefix=powerpc${1#ppc}-linux-gnu- + container_cross_prefix=powerpc${target_arch#ppc}-linux-gnu- container_cross_cc=${container_cross_prefix}gcc-10 ;; riscv64) @@ -2107,7 +2049,6 @@ probe_target_compiler() { : ${container_cross_strip:=${container_cross_prefix}strip} done - local t try try=cross case "$target_arch:$cpu" in aarch64_be:aarch64 | \ @@ -2120,8 +2061,8 @@ probe_target_compiler() { try='native cross' ;; esac eval "target_cflags=\${cross_cc_cflags_$target_arch}" - for t in $try; do - case $t in + for thistry in $try; do + case $thistry in native) target_cc=$cc target_ccas=$ccas @@ -2204,7 +2145,6 @@ probe_target_compiler() { build_static= target_cc= target_ccas= - target_cflags= target_ar= target_as= target_ld= @@ -2213,54 +2153,54 @@ probe_target_compiler() { target_ranlib= target_strip= fi + test -n "$target_cc" } write_target_makefile() { echo "EXTRA_CFLAGS=$target_cflags" - if test -n "$target_cc"; then - echo "CC=$target_cc" - echo "CCAS=$target_ccas" - fi - if test -n "$target_ar"; then - echo "AR=$target_ar" - fi - if test -n "$target_as"; then - echo "AS=$target_as" - fi - if test -n "$target_ld"; then - echo "LD=$target_ld" - fi - if test -n "$target_nm"; then - echo "NM=$target_nm" - fi - if test -n "$target_objcopy"; then - echo "OBJCOPY=$target_objcopy" - fi - if test -n "$target_ranlib"; then - echo "RANLIB=$target_ranlib" - fi - if test -n "$target_strip"; then - echo "STRIP=$target_strip" + if test -z "$target_cc" && test -z "$target_as"; then + test -z "$container_image" && error_exit "Internal error: could not find cross compiler for $1?" + echo "$1: docker-image-$container_image" >> Makefile.prereqs + if test -n "$container_cross_cc"; then + echo "CC=$docker_py cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" + echo "CCAS=$docker_py cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" + fi + echo "AR=$docker_py cc --cc $container_cross_ar -i qemu/$container_image -s $source_path --" + echo "AS=$docker_py cc --cc $container_cross_as -i qemu/$container_image -s $source_path --" + echo "LD=$docker_py cc --cc $container_cross_ld -i qemu/$container_image -s $source_path --" + echo "NM=$docker_py cc --cc $container_cross_nm -i qemu/$container_image -s $source_path --" + echo "OBJCOPY=$docker_py cc --cc $container_cross_objcopy -i qemu/$container_image -s $source_path --" + echo "RANLIB=$docker_py cc --cc $container_cross_ranlib -i qemu/$container_image -s $source_path --" + echo "STRIP=$docker_py cc --cc $container_cross_strip -i qemu/$container_image -s $source_path --" + else + if test -n "$target_cc"; then + echo "CC=$target_cc" + echo "CCAS=$target_ccas" + fi + if test -n "$target_ar"; then + echo "AR=$target_ar" + fi + if test -n "$target_as"; then + echo "AS=$target_as" + fi + if test -n "$target_ld"; then + echo "LD=$target_ld" + fi + if test -n "$target_nm"; then + echo "NM=$target_nm" + fi + if test -n "$target_objcopy"; then + echo "OBJCOPY=$target_objcopy" + fi + if test -n "$target_ranlib"; then + echo "RANLIB=$target_ranlib" + fi + if test -n "$target_strip"; then + echo "STRIP=$target_strip" + fi fi } -write_container_target_makefile() { - echo "EXTRA_CFLAGS=$target_cflags" - if test -n "$container_cross_cc"; then - echo "CC=\$(DOCKER_SCRIPT) cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" - echo "CCAS=\$(DOCKER_SCRIPT) cc --cc $container_cross_cc -i qemu/$container_image -s $source_path --" - fi - echo "AR=\$(DOCKER_SCRIPT) cc --cc $container_cross_ar -i qemu/$container_image -s $source_path --" - echo "AS=\$(DOCKER_SCRIPT) cc --cc $container_cross_as -i qemu/$container_image -s $source_path --" - echo "LD=\$(DOCKER_SCRIPT) cc --cc $container_cross_ld -i qemu/$container_image -s $source_path --" - echo "NM=\$(DOCKER_SCRIPT) cc --cc $container_cross_nm -i qemu/$container_image -s $source_path --" - echo "OBJCOPY=\$(DOCKER_SCRIPT) cc --cc $container_cross_objcopy -i qemu/$container_image -s $source_path --" - echo "RANLIB=\$(DOCKER_SCRIPT) cc --cc $container_cross_ranlib -i qemu/$container_image -s $source_path --" - echo "STRIP=\$(DOCKER_SCRIPT) cc --cc $container_cross_strip -i qemu/$container_image -s $source_path --" -} - - - ########################################## # check for vfio_user_server @@ -2282,13 +2222,6 @@ if test "$fortify_source" = "yes" ; then QEMU_CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $QEMU_CFLAGS" fi -case "$ARCH" in -alpha) - # Ensure there's only a single GP - QEMU_CFLAGS="-msmall-data $QEMU_CFLAGS" -;; -esac - if test "$have_asan" = "yes"; then QEMU_CFLAGS="-fsanitize=address $QEMU_CFLAGS" QEMU_LDFLAGS="-fsanitize=address $QEMU_LDFLAGS" @@ -2316,14 +2249,6 @@ if test "$have_ubsan" = "yes"; then fi ########################################## - -# Exclude --warn-common with TSan to suppress warnings from the TSan libraries. -if test "$solaris" = "no" && test "$tsan" = "no"; then - if $ld --version 2>/dev/null | grep "GNU ld" >/dev/null 2>/dev/null ; then - QEMU_LDFLAGS="-Wl,--warn-common $QEMU_LDFLAGS" - fi -fi - # Guest agent Windows MSI package if test "$QEMU_GA_MANUFACTURER" = ""; then @@ -2333,7 +2258,7 @@ if test "$QEMU_GA_DISTRO" = ""; then QEMU_GA_DISTRO=Linux fi if test "$QEMU_GA_VERSION" = ""; then - QEMU_GA_VERSION=$(cat $source_path/VERSION) + QEMU_GA_VERSION=$(cat "$source_path"/VERSION) fi @@ -2349,7 +2274,6 @@ fi # tests might fail. Prefer to keep the relevant files in their own # directory and symlink the directory instead. LINKS="Makefile" -LINKS="$LINKS tests/tcg/Makefile.target" LINKS="$LINKS pc-bios/optionrom/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile" LINKS="$LINKS pc-bios/vof/Makefile" @@ -2360,38 +2284,26 @@ LINKS="$LINKS python" LINKS="$LINKS contrib/plugins/Makefile " for f in $LINKS ; do if [ -e "$source_path/$f" ]; then - mkdir -p `dirname ./$f` + mkdir -p "$(dirname ./"$f")" symlink "$source_path/$f" "$f" fi done +echo "# Automatically generated by configure - do not modify" > Makefile.prereqs + # Mac OS X ships with a broken assembler roms= -probe_target_compiler i386-softmmu -if test -n "$target_cc" && - test "$targetos" != "darwin" && test "$targetos" != "sunos" && \ - test "$targetos" != "haiku" && test "$softmmu" = yes ; then - # Different host OS linkers have different ideas about the name of the ELF - # emulation. Linux and OpenBSD/amd64 use 'elf_i386'; FreeBSD uses the _fbsd - # variant; OpenBSD/i386 uses the _obsd variant; and Windows uses i386pe. - for emu in elf_i386 elf_i386_fbsd elf_i386_obsd i386pe; do - if "$target_ld" -verbose 2>&1 | grep -q "^[[:space:]]*$emu[[:space:]]*$"; then - ld_i386_emulation="$emu" - break - fi - done - if test -n "$ld_i386_emulation"; then - roms="pc-bios/optionrom" - config_mak=pc-bios/optionrom/config.mak - echo "# Automatically generated by configure - do not modify" > $config_mak - echo "TOPSRC_DIR=$source_path" >> $config_mak - echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_mak - write_target_makefile >> $config_mak - fi +if test "$targetos" != "darwin" && test "$targetos" != "sunos" && \ + test "$targetos" != "haiku" && test "$softmmu" = yes && \ + probe_target_compiler i386-softmmu; then + roms="pc-bios/optionrom" + config_mak=pc-bios/optionrom/config.mak + echo "# Automatically generated by configure - do not modify" > $config_mak + echo "TOPSRC_DIR=$source_path" >> $config_mak + write_target_makefile >> $config_mak fi -probe_target_compiler ppc-softmmu -if test -n "$target_cc" && test "$softmmu" = yes; then +if test "$softmmu" = yes && probe_target_compiler ppc-softmmu; then roms="$roms pc-bios/vof" config_mak=pc-bios/vof/config.mak echo "# Automatically generated by configure - do not modify" > $config_mak @@ -2401,8 +2313,7 @@ fi # Only build s390-ccw bios if the compiler has -march=z900 or -march=z10 # (which is the lowest architecture level that Clang supports) -probe_target_compiler s390x-softmmu -if test -n "$target_cc" && test "$softmmu" = yes; then +if test "$softmmu" = yes && probe_target_compiler s390x-softmmu; then write_c_skeleton do_compiler "$target_cc" $target_cc_cflags -march=z900 -o $TMPO -c $TMPC has_z900=$? @@ -2425,39 +2336,7 @@ fi ####################################### # generate config-host.mak -# Check that the C++ compiler exists and works with the C compiler. -# All the QEMU_CXXFLAGS are based on QEMU_CFLAGS. Keep this at the end to don't miss any other that could be added. -if has $cxx; then - cat > $TMPC < $TMPCXX <> $config_host_mak + else + gdb_bin="" fi fi +if test "$container" != no; then + echo "ENGINE=$container" >> $config_host_mak +fi + if test "$as_shared_lib" = "yes" ; then echo "AS_SHARED_LIB=y" >> $config_host_mak fi @@ -2544,7 +2429,6 @@ echo "MESON=$meson" >> $config_host_mak echo "NINJA=$ninja" >> $config_host_mak echo "CC=$cc" >> $config_host_mak echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak -echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak echo "QEMU_OBJCFLAGS=$QEMU_OBJCFLAGS" >> $config_host_mak echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak echo "GLIB_LIBS=$glib_libs" >> $config_host_mak @@ -2589,7 +2473,7 @@ fi for target in $target_list; do target_dir="$target" target_name=$(echo $target | cut -d '-' -f 1)$EXESUF - mkdir -p $target_dir + mkdir -p "$target_dir" case $target in *-user) symlink "../qemu-$target_name" "$target_dir/qemu-$target_name" ;; *) symlink "../qemu-system-$target_name" "$target_dir/qemu-system-$target_name" ;; @@ -2609,29 +2493,28 @@ if test "$safe_stack" = "yes"; then fi # tests/tcg configuration -(makefile=tests/tcg/Makefile.prereqs -echo "# Automatically generated by configure - do not modify" > $makefile - -config_host_mak=tests/tcg/config-host.mak +(config_host_mak=tests/tcg/config-host.mak +mkdir -p tests/tcg echo "# Automatically generated by configure - do not modify" > $config_host_mak echo "SRC_PATH=$source_path" >> $config_host_mak echo "HOST_CC=$host_cc" >> $config_host_mak +# versioned checked in the main config_host.mak above +if test -n "$gdb_bin"; then + echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak +fi + tcg_tests_targets= for target in $target_list; do arch=${target%%-*} - config_target_mak=tests/tcg/config-$target.mak - - echo "# Automatically generated by configure - do not modify" > $config_target_mak - echo "TARGET_NAME=$arch" >> $config_target_mak case $target in xtensa*-linux-user) # the toolchain is not complete with headers, only build softmmu tests continue ;; *-softmmu) - test -f $source_path/tests/tcg/$arch/Makefile.softmmu-target || continue + test -f "$source_path/tests/tcg/$arch/Makefile.softmmu-target" || continue qemu="qemu-system-$arch" ;; *-linux-user|*-bsd-user) @@ -2639,85 +2522,22 @@ for target in $target_list; do ;; esac - probe_target_compiler $target - if test $got_cross_cc = yes; then - # Test for compiler features for optional tests. We only do this - # for cross compilers because ensuring the docker containers based - # compilers is a requirememt for adding a new test that needs a - # compiler feature. - - echo "BUILD_STATIC=$build_static" >> $config_target_mak - write_target_makefile >> $config_target_mak - case $target in - aarch64-*) - if do_compiler "$target_cc" $target_cflags \ - -march=armv8.1-a+sve -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak - fi - if do_compiler "$target_cc" $target_cflags \ - -march=armv8.1-a+sve2 -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_SVE2=y" >> $config_target_mak - fi - if do_compiler "$target_cc" $target_cflags \ - -march=armv8.3-a -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak - fi - if do_compiler "$target_cc" $target_cflags \ - -mbranch-protection=standard -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak - fi - if do_compiler "$target_cc" $target_cflags \ - -march=armv8.5-a+memtag -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak - fi - ;; - ppc*) - if do_compiler "$target_cc" $target_cflags \ - -mpower8-vector -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak - fi - if do_compiler "$target_cc" $target_cflags \ - -mpower10 -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak - fi - ;; - i386-linux-user) - if do_compiler "$target_cc" $target_cflags \ - -Werror -fno-pie -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak - fi - ;; - esac - elif test -n "$container_image"; then - echo "build-tcg-tests-$target: docker-image-$container_image" >> $makefile - echo "BUILD_STATIC=y" >> $config_target_mak - write_container_target_makefile >> $config_target_mak - case $target in - aarch64-*) - echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak - echo "CROSS_CC_HAS_SVE2=y" >> $config_target_mak - echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak - echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak - echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak - ;; - ppc*) - echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak - echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak - ;; - i386-linux-user) - echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak - ;; - esac - got_cross_cc=yes - fi - if test $got_cross_cc = yes; then - mkdir -p tests/tcg/$target - echo "QEMU=$PWD/$qemu" >> $config_target_mak - echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> $makefile + if probe_target_compiler $target || test -n "$container_image"; then + test -n "$container_image" && build_static=y + mkdir -p "tests/tcg/$target" + config_target_mak=tests/tcg/$target/config-target.mak + ln -sf "$source_path/tests/tcg/Makefile.target" "tests/tcg/$target/Makefile" + echo "# Automatically generated by configure - do not modify" > "$config_target_mak" + echo "TARGET_NAME=$arch" >> "$config_target_mak" + echo "TARGET=$target" >> "$config_target_mak" + write_target_makefile "build-tcg-tests-$target" >> "$config_target_mak" + echo "BUILD_STATIC=$build_static" >> "$config_target_mak" + echo "QEMU=$PWD/$qemu" >> "$config_target_mak" + echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs tcg_tests_targets="$tcg_tests_targets $target" fi done -echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> $makefile) +echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> config-host.mak) if test "$skip_meson" = no; then cross="config-meson.cross.new" @@ -2735,7 +2555,6 @@ if test "$skip_meson" = no; then echo "${a}-softmmu = '$c'" >> $cross done - test -z "$cxx" && echo "link_language = 'c'" >> $cross echo "[built-in options]" >> $cross echo "c_args = [$(meson_quote $CFLAGS $EXTRA_CFLAGS)]" >> $cross echo "cpp_args = [$(meson_quote $CXXFLAGS $EXTRA_CXXFLAGS)]" >> $cross @@ -2792,7 +2611,6 @@ if test "$skip_meson" = no; then test "$fdt" != auto && meson_option_add "-Dfdt=$fdt" test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE" test "$qemu_suffix" != qemu && meson_option_add "-Dqemu_suffix=$qemu_suffix" - test "$slirp" != auto && meson_option_add "-Dslirp=$slirp" test "$smbd" != '' && meson_option_add "-Dsmbd=$smbd" test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg" test "$vfio_user_server" != auto && meson_option_add "-Dvfio_user_server=$vfio_user_server" diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map index 2800d9f986..3727918641 100644 --- a/contrib/gitdm/domain-map +++ b/contrib/gitdm/domain-map @@ -10,6 +10,7 @@ bytedance.com ByteDance cmss.chinamobile.com China Mobile citrix.com Citrix crudebyte.com Crudebyte +chinatelecom.cn China Telecom eldorado.org.br Instituto de Pesquisas Eldorado fujitsu.com Fujitsu google.com Google @@ -19,6 +20,7 @@ ibm.com IBM igalia.com Igalia intel.com Intel linaro.org Linaro +loongson.cn Loongson Technology lwn.net LWN microsoft.com Microsoft mvista.com MontaVista diff --git a/contrib/gitdm/group-map-academics b/contrib/gitdm/group-map-academics index 44745ca85b..082458e1bd 100644 --- a/contrib/gitdm/group-map-academics +++ b/contrib/gitdm/group-map-academics @@ -19,3 +19,9 @@ edu.cn # Boston University bu.edu + +# Institute of Software Chinese Academy of Sciences +iscas.ac.cn + +# Université Grenoble Alpes +univ-grenoble-alpes.fr diff --git a/contrib/gitdm/group-map-individuals b/contrib/gitdm/group-map-individuals index f816aa8770..53883cc526 100644 --- a/contrib/gitdm/group-map-individuals +++ b/contrib/gitdm/group-map-individuals @@ -34,3 +34,6 @@ bmeng.cn@gmail.com liq3ea@gmail.com chetan4windows@gmail.com akihiko.odaki@gmail.com +paul@nowt.org +git@xen0n.name +simon@simonsafar.com diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index b9226e7c40..ac1510aaa1 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -38,7 +38,7 @@ enum EvictionPolicy policy; * put in any of the blocks inside the set. The number of block per set is * called the associativity (assoc). * - * Each block contains the the stored tag and a valid bit. Since this is not + * Each block contains the stored tag and a valid bit. Since this is not * a functional simulator, the data itself is not stored. We only identify * whether a block is in the cache or not by searching for its tag. * diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c index a5275dcc15..1b3bb7ebba 100644 --- a/contrib/plugins/execlog.c +++ b/contrib/plugins/execlog.c @@ -20,6 +20,9 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; /* Store last executed instruction on each vCPU as a GString */ GArray *last_exec; +static GPtrArray *imatches; +static GArray *amatches; + /** * Add memory read or write information to current instruction log */ @@ -85,12 +88,13 @@ static void vcpu_insn_exec(unsigned int cpu_index, void *udata) static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) { struct qemu_plugin_insn *insn; - uint64_t insn_vaddr; - uint32_t insn_opcode; - char *insn_disas; + bool skip = (imatches || amatches); size_t n = qemu_plugin_tb_n_insns(tb); for (size_t i = 0; i < n; i++) { + char *insn_disas; + uint64_t insn_vaddr; + /* * `insn` is shared between translations in QEMU, copy needed data here. * `output` is never freed as it might be used multiple times during @@ -99,20 +103,55 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) * a limitation for CISC architectures. */ insn = qemu_plugin_tb_get_insn(tb, i); - insn_vaddr = qemu_plugin_insn_vaddr(insn); - insn_opcode = *((uint32_t *)qemu_plugin_insn_data(insn)); insn_disas = qemu_plugin_insn_disas(insn); - char *output = g_strdup_printf("0x%"PRIx64", 0x%"PRIx32", \"%s\"", - insn_vaddr, insn_opcode, insn_disas); + insn_vaddr = qemu_plugin_insn_vaddr(insn); - /* Register callback on memory read or write */ - qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem, - QEMU_PLUGIN_CB_NO_REGS, - QEMU_PLUGIN_MEM_RW, NULL); + /* + * If we are filtering we better check out if we have any + * hits. The skip "latches" so we can track memory accesses + * after the instruction we care about. + */ + if (skip && imatches) { + int j; + for (j = 0; j < imatches->len && skip; j++) { + char *m = g_ptr_array_index(imatches, j); + if (g_str_has_prefix(insn_disas, m)) { + skip = false; + } + } + } + + if (skip && amatches) { + int j; + for (j = 0; j < amatches->len && skip; j++) { + uint64_t v = g_array_index(amatches, uint64_t, j); + if (v == insn_vaddr) { + skip = false; + } + } + } + + if (skip) { + g_free(insn_disas); + } else { + uint32_t insn_opcode; + insn_opcode = *((uint32_t *)qemu_plugin_insn_data(insn)); + char *output = g_strdup_printf("0x%"PRIx64", 0x%"PRIx32", \"%s\"", + insn_vaddr, insn_opcode, insn_disas); + + /* Register callback on memory read or write */ + qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem, + QEMU_PLUGIN_CB_NO_REGS, + QEMU_PLUGIN_MEM_RW, NULL); + + /* Register callback on instruction */ + qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec, + QEMU_PLUGIN_CB_NO_REGS, output); + + /* reset skip */ + skip = (imatches || amatches); + } - /* Register callback on instruction */ - qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec, - QEMU_PLUGIN_CB_NO_REGS, output); } } @@ -132,6 +171,25 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) } } +/* Add a match to the array of matches */ +static void parse_insn_match(char *match) +{ + if (!imatches) { + imatches = g_ptr_array_new(); + } + g_ptr_array_add(imatches, match); +} + +static void parse_vaddr_match(char *match) +{ + uint64_t v = g_ascii_strtoull(match, NULL, 16); + + if (!amatches) { + amatches = g_array_new(false, true, sizeof(uint64_t)); + } + g_array_append_val(amatches, v); +} + /** * Install the plugin */ @@ -145,6 +203,19 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, */ last_exec = g_array_new(FALSE, FALSE, sizeof(GString *)); + for (int i = 0; i < argc; i++) { + char *opt = argv[i]; + g_autofree char **tokens = g_strsplit(opt, "=", 2); + if (g_strcmp0(tokens[0], "ifilter") == 0) { + parse_insn_match(tokens[1]); + } else if (g_strcmp0(tokens[0], "afilter") == 0) { + parse_vaddr_match(tokens[1]); + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } + } + /* Register translation block and exit callbacks */ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); diff --git a/contrib/vhost-user-blk/vhost-user-blk.c b/contrib/vhost-user-blk/vhost-user-blk.c index 9cb78ca1d0..d6932a2645 100644 --- a/contrib/vhost-user-blk/vhost-user-blk.c +++ b/contrib/vhost-user-blk/vhost-user-blk.c @@ -106,10 +106,7 @@ static void vub_req_complete(VubReq *req) req->size + 1); vu_queue_notify(vu_dev, req->vq); - if (req->elem) { - free(req->elem); - } - + g_free(req->elem); g_free(req); } @@ -243,7 +240,7 @@ static int vub_virtio_process_req(VubDev *vdev_blk, /* refer to hw/block/virtio_blk.c */ if (elem->out_num < 1 || elem->in_num < 1) { fprintf(stderr, "virtio-blk request missing headers\n"); - free(elem); + g_free(elem); return -1; } @@ -325,7 +322,7 @@ static int vub_virtio_process_req(VubDev *vdev_blk, return 0; err: - free(elem); + g_free(elem); g_free(req); return -1; } diff --git a/cpu.c b/cpu.c index 58af550e3d..26b25ae850 100644 --- a/cpu.c +++ b/cpu.c @@ -406,9 +406,8 @@ const VMStateDescription vmstate_cpu_common = { void cpu_exec_realizefn(CPUState *cpu, Error **errp) { -#ifndef CONFIG_USER_ONLY - CPUClass *cc = CPU_GET_CLASS(cpu); -#endif + /* cache the cpu class for the hotpath */ + cpu->cc = CPU_GET_CLASS(cpu); cpu_list_add(cpu); if (!accel_cpu_realizefn(cpu, errp)) { @@ -426,8 +425,8 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) if (qdev_get_vmsd(DEVICE(cpu)) == NULL) { vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu); } - if (cc->sysemu_ops->legacy_vmsd != NULL) { - vmstate_register(NULL, cpu->cpu_index, cc->sysemu_ops->legacy_vmsd, cpu); + if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) { + vmstate_register(NULL, cpu->cpu_index, cpu->cc->sysemu_ops->legacy_vmsd, cpu); } #endif /* CONFIG_USER_ONLY */ } diff --git a/disas.c b/disas.c index e31438f349..94d3b45042 100644 --- a/disas.c +++ b/disas.c @@ -83,18 +83,18 @@ static int print_insn_objdump(bfd_vma pc, disassemble_info *info, const char *prefix) { int i, n = info->buffer_length; - uint8_t *buf = g_malloc(n); + g_autofree uint8_t *buf = g_malloc(n); - info->read_memory_func(pc, buf, n, info); - - for (i = 0; i < n; ++i) { - if (i % 32 == 0) { - info->fprintf_func(info->stream, "\n%s: ", prefix); + if (info->read_memory_func(pc, buf, n, info) == 0) { + for (i = 0; i < n; ++i) { + if (i % 32 == 0) { + info->fprintf_func(info->stream, "\n%s: ", prefix); + } + info->fprintf_func(info->stream, "%02x", buf[i]); } - info->fprintf_func(info->stream, "%02x", buf[i]); + } else { + info->fprintf_func(info->stream, "unable to read memory"); } - - g_free(buf); return n; } @@ -239,7 +239,7 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code, } } -static int plugin_printf(FILE *stream, const char *fmt, ...) +static int gstring_printf(FILE *stream, const char *fmt, ...) { /* We abuse the FILE parameter to pass a GString. */ GString *s = (GString *)stream; @@ -270,7 +270,7 @@ char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size) GString *ds = g_string_new(NULL); initialize_debug_target(&s, cpu); - s.info.fprintf_func = plugin_printf; + s.info.fprintf_func = gstring_printf; s.info.stream = (FILE *)ds; /* abuse this slot */ s.info.buffer_vma = addr; s.info.buffer_length = size; @@ -358,15 +358,19 @@ void monitor_disas(Monitor *mon, CPUState *cpu, { int count, i; CPUDebug s; + g_autoptr(GString) ds = g_string_new(""); initialize_debug_target(&s, cpu); - s.info.fprintf_func = qemu_fprintf; + s.info.fprintf_func = gstring_printf; + s.info.stream = (FILE *)ds; /* abuse this slot */ + if (is_physical) { s.info.read_memory_func = physical_read_memory; } s.info.buffer_vma = pc; if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) { + monitor_puts(mon, ds->str); return; } @@ -376,13 +380,16 @@ void monitor_disas(Monitor *mon, CPUState *cpu, return; } - for(i = 0; i < nb_insn; i++) { - monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc); + for (i = 0; i < nb_insn; i++) { + g_string_append_printf(ds, "0x" TARGET_FMT_lx ": ", pc); count = s.info.print_insn(pc, &s.info); - monitor_printf(mon, "\n"); - if (count < 0) - break; + g_string_append_c(ds, '\n'); + if (count < 0) { + break; + } pc += count; } + + monitor_puts(mon, ds->str); } #endif diff --git a/disas/capstone.c b/disas/capstone.c index 20bc8f9669..fe3efb0d3c 100644 --- a/disas/capstone.c +++ b/disas/capstone.c @@ -191,37 +191,43 @@ bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size) size_t tsize = MIN(sizeof(cap_buf) - csize, size); const uint8_t *cbuf = cap_buf; - info->read_memory_func(pc + csize, cap_buf + csize, tsize, info); - csize += tsize; - size -= tsize; + if (info->read_memory_func(pc + csize, cap_buf + csize, tsize, info) == 0) { + csize += tsize; + size -= tsize; - while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { - cap_dump_insn(info, insn); - } + while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { + cap_dump_insn(info, insn); + } + + /* If the target memory is not consumed, go back for more... */ + if (size != 0) { + /* + * ... taking care to move any remaining fractional insn + * to the beginning of the buffer. + */ + if (csize != 0) { + memmove(cap_buf, cbuf, csize); + } + continue; + } - /* If the target memory is not consumed, go back for more... */ - if (size != 0) { /* - * ... taking care to move any remaining fractional insn - * to the beginning of the buffer. + * Since the target memory is consumed, we should not have + * a remaining fractional insn. */ if (csize != 0) { - memmove(cap_buf, cbuf, csize); + info->fprintf_func(info->stream, + "Disassembler disagrees with translator " + "over instruction decoding\n" + "Please report this to qemu-devel@nongnu.org\n"); } - continue; - } + break; - /* - * Since the target memory is consumed, we should not have - * a remaining fractional insn. - */ - if (csize != 0) { + } else { info->fprintf_func(info->stream, - "Disassembler disagrees with translator " - "over instruction decoding\n" - "Please report this to qemu-devel@nongnu.org\n"); + "0x%08" PRIx64 ": unable to read memory\n", pc); + break; } - break; } cs_close(&handle); @@ -286,16 +292,23 @@ bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count) /* Make certain that we can make progress. */ assert(tsize != 0); - info->read_memory_func(pc + csize, cap_buf + csize, tsize, info); - csize += tsize; + if (info->read_memory_func(pc + csize, cap_buf + csize, + tsize, info) == 0) + { + csize += tsize; - if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { - cap_dump_insn(info, insn); - if (--count <= 0) { - break; + if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) { + cap_dump_insn(info, insn); + if (--count <= 0) { + break; + } } + memmove(cap_buf, cbuf, csize); + } else { + info->fprintf_func(info->stream, + "0x%08" PRIx64 ": unable to read memory\n", pc); + break; } - memmove(cap_buf, cbuf, csize); } cs_close(&handle); diff --git a/disas/riscv.c b/disas/riscv.c index 7af6afc8fa..f107d94c4c 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1304,8 +1304,6 @@ static const char *csr_name(int csrno) case 0x0043: return "utval"; case 0x0044: return "uip"; case 0x0100: return "sstatus"; - case 0x0102: return "sedeleg"; - case 0x0103: return "sideleg"; case 0x0104: return "sie"; case 0x0105: return "stvec"; case 0x0106: return "scounteren"; @@ -2402,10 +2400,25 @@ static int32_t operand_sbimm12(rv_inst inst) ((inst << 56) >> 63) << 11; } -static uint32_t operand_cimmsh6(rv_inst inst) +static uint32_t operand_cimmshl6(rv_inst inst, rv_isa isa) { - return ((inst << 51) >> 63) << 5 | + int imm = ((inst << 51) >> 63) << 5 | (inst << 57) >> 59; + if (isa == rv128) { + imm = imm ? imm : 64; + } + return imm; +} + +static uint32_t operand_cimmshr6(rv_inst inst, rv_isa isa) +{ + int imm = ((inst << 51) >> 63) << 5 | + (inst << 57) >> 59; + if (isa == rv128) { + imm = imm | (imm & 32) << 1; + imm = imm ? imm : 64; + } + return imm; } static int32_t operand_cimmi(rv_inst inst) @@ -2529,7 +2542,7 @@ static uint32_t operand_rnum(rv_inst inst) /* decode operands */ -static void decode_inst_operands(rv_decode *dec) +static void decode_inst_operands(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; dec->codec = opcode_data[dec->op].codec; @@ -2652,7 +2665,7 @@ static void decode_inst_operands(rv_decode *dec) case rv_codec_cb_sh6: dec->rd = dec->rs1 = operand_crs1rdq(inst) + 8; dec->rs2 = rv_ireg_zero; - dec->imm = operand_cimmsh6(inst); + dec->imm = operand_cimmshr6(inst, isa); break; case rv_codec_ci: dec->rd = dec->rs1 = operand_crs1rd(inst); @@ -2667,7 +2680,7 @@ static void decode_inst_operands(rv_decode *dec) case rv_codec_ci_sh6: dec->rd = dec->rs1 = operand_crs1rd(inst); dec->rs2 = rv_ireg_zero; - dec->imm = operand_cimmsh6(inst); + dec->imm = operand_cimmshl6(inst, isa); break; case rv_codec_ci_16sp: dec->rd = rv_ireg_sp; @@ -3193,7 +3206,7 @@ disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst) dec.pc = pc; dec.inst = inst; decode_inst_opcode(&dec, isa); - decode_inst_operands(&dec); + decode_inst_operands(&dec, isa); decode_inst_decompress(&dec, isa); decode_inst_lift_pseudo(&dec); format_inst(buf, buflen, 16, &dec); diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index 6b8496c430..1c1e7b9e11 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -41,12 +41,12 @@ Those hosts are officially supported, with various accelerators: - Accelerators * - Arm - kvm (64 bit only), tcg, xen - * - MIPS + * - MIPS (little endian only) - kvm, tcg * - PPC - kvm, tcg * - RISC-V - - tcg + - kvm, tcg * - s390x - kvm, tcg * - SPARC @@ -71,7 +71,10 @@ The project aims to support the most recent major version at all times. Support for the previous major version will be dropped 2 years after the new major version is released or when the vendor itself drops support, whichever comes first. In this context, third-party efforts to extend the lifetime of a distro -are not considered, even when they are endorsed by the vendor (eg. Debian LTS). +are not considered, even when they are endorsed by the vendor (eg. Debian LTS); +the same is true of repositories that contain packages backported from later +releases (e.g. Debian backports). Within each major release, only the most +recent minor release is considered. For the purposes of identifying supported software versions available on Linux, the project will look at CentOS, Debian, Fedora, openSUSE, RHEL, SLES and diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 7ee26626d5..93affe3669 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -81,11 +81,6 @@ the process listing. This is replaced by the new ``password-secret`` option which lets the password be securely provided on the command line using a ``secret`` object instance. -``-watchdog`` (since 6.2) -''''''''''''''''''''''''' - -Use ``-device`` instead. - ``-smp`` ("parameter=0" SMP configurations) (since 6.2) ''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -213,6 +208,19 @@ MIPS ``Trap-and-Emul`` KVM support (since 6.0) The MIPS ``Trap-and-Emul`` KVM host and guest support has been removed from Linux upstream kernel, declare it deprecated. +Host Architectures +------------------ + +BE MIPS (since 7.2) +''''''''''''''''''' + +As Debian 10 ("Buster") moved into LTS the big endian 32 bit version of +MIPS moved out of support making it hard to maintain our +cross-compilation CI tests of the architecture. As we no longer have +CI coverage support may bitrot away before the deprecation process +completes. The little endian variants of MIPS (both 32 and 64 bit) are +still a supported host architecture. + QEMU API (QAPI) events ---------------------- @@ -233,15 +241,6 @@ deprecated; use the new name ``dtb-randomness`` instead. The new name better reflects the way this property affects all random data within the device tree blob, not just the ``kaslr-seed`` node. -PPC 405 ``taihu`` machine (since 7.0) -''''''''''''''''''''''''''''''''''''' - -The PPC 405 CPU is a system-on-a-chip, so all 405 machines are very similar, -except for some external periphery. However, the periphery of the ``taihu`` -machine is hardly emulated at all (e.g. neither the LCD nor the USB part had -been implemented), so there is not much value added by this board. Use the -``ref405ep`` machine instead. - ``pc-i440fx-1.4`` up to ``pc-i440fx-1.7`` (since 7.0) ''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -297,7 +296,7 @@ by using ``-machine graphics=off``. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In QEMU versions 6.1, 6.2 and 7.0, the ``nvme-ns`` generates an EUI-64 -identifer that is not globally unique. If an EUI-64 identifer is required, the +identifier that is not globally unique. If an EUI-64 identifier is required, the user must set it explicitly using the ``nvme-ns`` device parameter ``eui64``. ``-device nvme,use-intel-id=on|off`` (since 7.1) @@ -379,3 +378,22 @@ be deleted from this tree. New deployments should use the Rust version, and existing systems should consider moving to it. The command line and feature set is very close and moving should be simple. + + +QEMU guest agent +---------------- + +``--blacklist`` command line option (since 7.2) +''''''''''''''''''''''''''''''''''''''''''''''' + +``--blacklist`` has been replaced by ``--block-rpcs`` (which is a better +wording for what this option does). The short form ``-b`` still stays +the same and thus is the preferred way for scripts that should run with +both, older and future versions of QEMU. + +``blacklist`` config file option (since 7.2) +'''''''''''''''''''''''''''''''''''''''''''' + +The ``blacklist`` config file option has been renamed to ``block-rpcs`` +(to be in sync with the renaming of the corresponding command line +option). diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index c7b9dadd5d..63df9848fd 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -396,6 +396,18 @@ Use ``-display sdl`` instead. Use ``-display curses`` instead. +Creating sound card devices using ``-soundhw`` (removed in 7.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Sound card devices should be created using ``-device`` or ``-audio``. +The exception is ``pcspk`` which can be activated using ``-machine +pcspk-audiodev=``. + +``-watchdog`` (since 7.2) +''''''''''''''''''''''''' + +Use ``-device`` instead. + QEMU Machine Protocol (QMP) commands ------------------------------------ @@ -661,6 +673,12 @@ Aspeed ``swift-bmc`` machine (removed in 7.0) This machine was removed because it was unused. Alternative AST2500 based OpenPOWER machines are ``witherspoon-bmc`` and ``romulus-bmc``. +ppc ``taihu`` machine (removed in 7.2) +''''''''''''''''''''''''''''''''''''''''''''' + +This machine was removed because it was partially emulated and 405 +machines are very similar. Use the ``ref405ep`` machine instead. + linux-user mode CPUs -------------------- @@ -681,13 +699,6 @@ tripped up the CI testing and was suspected to be quite broken. For that reason the maintainers strongly suspected no one actually used it. -Creating sound card devices using ``-soundhw`` (removed in 7.1) -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Sound card devices should be created using ``-device`` or ``-audio``. -The exception is ``pcspk`` which can be activated using ``-machine -pcspk-audiodev=``. - TCG introspection features -------------------------- diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index 431caba7aa..1894721743 100644 --- a/docs/devel/build-system.rst +++ b/docs/devel/build-system.rst @@ -99,11 +99,6 @@ developers in checking for system features: Write a minimal C program main() function to the temporary file indicated by $TMPC -``feature_not_found $NAME $REMEDY`` - Print a message to stderr that the feature $NAME was not available - on the system, suggesting the user try $REMEDY to address the - problem. - ``error_exit $MESSAGE $MORE...`` Print $MESSAGE to stderr, followed by $MORE... and then exit from the configure script with non-zero status diff --git a/docs/devel/fuzzing.rst b/docs/devel/fuzzing.rst index 784ecb99e6..715330c856 100644 --- a/docs/devel/fuzzing.rst +++ b/docs/devel/fuzzing.rst @@ -287,8 +287,8 @@ select the fuzz target. Then, the qtest client is initialized. If the target requires qos, qgraph is set up and the QOM/LIBQOS modules are initialized. Then the QGraph is walked and the QEMU cmd_line is determined and saved. -After this, the ``vl.c:qemu_main`` is called to set up the guest. There are -target-specific hooks that can be called before and after qemu_main, for +After this, the ``vl.c:main`` is called to set up the guest. There are +target-specific hooks that can be called before and after main, for additional setup(e.g. PCI setup, or VM snapshotting). ``LLVMFuzzerTestOneInput``: Uses qtest/qos functions to act based on the fuzz diff --git a/docs/devel/qom.rst b/docs/devel/qom.rst index e5fe3597cd..3e34b07c98 100644 --- a/docs/devel/qom.rst +++ b/docs/devel/qom.rst @@ -292,8 +292,7 @@ in the header file: .. code-block:: c :caption: Declaring a simple type - OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device, - MY_DEVICE, DEVICE) + OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, MY_DEVICE) This is equivalent to the following: @@ -372,8 +371,8 @@ This accepts an array of interface type names. { TYPE_USER_CREATABLE }, { NULL }) -If the type is not intended to be instantiated, then then -the OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead: +If the type is not intended to be instantiated, then the +OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead: .. code-block:: c :caption: Defining a simple abstract type diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst index a7cc44aa20..9740a70406 100644 --- a/docs/devel/tcg-plugins.rst +++ b/docs/devel/tcg-plugins.rst @@ -110,11 +110,6 @@ details are opaque to plugins. The plugin is able to query select details of instructions and system configuration only through the exported *qemu_plugin* functions. -API -~~~ - -.. kernel-doc:: include/qemu/qemu-plugin.h - Internals --------- @@ -150,12 +145,141 @@ Example Plugins There are a number of plugins included with QEMU and you are encouraged to contribute your own plugins plugins upstream. There is a -``contrib/plugins`` directory where they can go. +``contrib/plugins`` directory where they can go. There are also some +basic plugins that are used to test and exercise the API during the +``make check-tcg`` target in ``tests\plugins``. -- tests/plugins +- tests/plugins/empty.c -These are some basic plugins that are used to test and exercise the -API during the ``make check-tcg`` target. +Purely a test plugin for measuring the overhead of the plugins system +itself. Does no instrumentation. + +- tests/plugins/bb.c + +A very basic plugin which will measure execution in course terms as +each basic block is executed. By default the results are shown once +execution finishes:: + + $ qemu-aarch64 -plugin tests/plugin/libbb.so \ + -d plugin ./tests/tcg/aarch64-linux-user/sha1 + SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6 + bb's: 2277338, insns: 158483046 + +Behaviour can be tweaked with the following arguments: + + * inline=true|false + + Use faster inline addition of a single counter. Not per-cpu and not + thread safe. + + * idle=true|false + + Dump the current execution stats whenever the guest vCPU idles + +- tests/plugins/insn.c + +This is a basic instruction level instrumentation which can count the +number of instructions executed on each core/thread:: + + $ qemu-aarch64 -plugin tests/plugin/libinsn.so \ + -d plugin ./tests/tcg/aarch64-linux-user/threadcount + Created 10 threads + Done + cpu 0 insns: 46765 + cpu 1 insns: 3694 + cpu 2 insns: 3694 + cpu 3 insns: 2994 + cpu 4 insns: 1497 + cpu 5 insns: 1497 + cpu 6 insns: 1497 + cpu 7 insns: 1497 + total insns: 63135 + +Behaviour can be tweaked with the following arguments: + + * inline=true|false + + Use faster inline addition of a single counter. Not per-cpu and not + thread safe. + + * sizes=true|false + + Give a summary of the instruction sizes for the execution + + * match= + + Only instrument instructions matching the string prefix. Will show + some basic stats including how many instructions have executed since + the last execution. For example:: + + $ qemu-aarch64 -plugin tests/plugin/libinsn.so,match=bl \ + -d plugin ./tests/tcg/aarch64-linux-user/sha512-vector + ... + 0x40069c, 'bl #0x4002b0', 10 hits, 1093 match hits, Δ+1257 since last match, 98 avg insns/match + 0x4006ac, 'bl #0x403690', 10 hits, 1094 match hits, Δ+47 since last match, 98 avg insns/match + 0x4037fc, 'bl #0x4002b0', 18 hits, 1095 match hits, Δ+22 since last match, 98 avg insns/match + 0x400720, 'bl #0x403690', 10 hits, 1096 match hits, Δ+58 since last match, 98 avg insns/match + 0x4037fc, 'bl #0x4002b0', 19 hits, 1097 match hits, Δ+22 since last match, 98 avg insns/match + 0x400730, 'bl #0x403690', 10 hits, 1098 match hits, Δ+33 since last match, 98 avg insns/match + 0x4037ac, 'bl #0x4002b0', 12 hits, 1099 match hits, Δ+20 since last match, 98 avg insns/match + ... + +For more detailed execution tracing see the ``execlog`` plugin for +other options. + +- tests/plugins/mem.c + +Basic instruction level memory instrumentation:: + + $ qemu-aarch64 -plugin tests/plugin/libmem.so,inline=true \ + -d plugin ./tests/tcg/aarch64-linux-user/sha1 + SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6 + inline mem accesses: 79525013 + +Behaviour can be tweaked with the following arguments: + + * inline=true|false + + Use faster inline addition of a single counter. Not per-cpu and not + thread safe. + + * callback=true|false + + Use callbacks on each memory instrumentation. + + * hwaddr=true|false + + Count IO accesses (only for system emulation) + +- tests/plugins/syscall.c + +A basic syscall tracing plugin. This only works for user-mode. By +default it will give a summary of syscall stats at the end of the +run:: + + $ qemu-aarch64 -plugin tests/plugin/libsyscall \ + -d plugin ./tests/tcg/aarch64-linux-user/threadcount + Created 10 threads + Done + syscall no. calls errors + 226 12 0 + 99 11 11 + 115 11 0 + 222 11 0 + 93 10 0 + 220 10 0 + 233 10 0 + 215 8 0 + 214 4 0 + 134 2 0 + 64 2 0 + 96 1 0 + 94 1 0 + 80 1 0 + 261 1 0 + 78 1 0 + 160 1 0 + 135 1 0 - contrib/plugins/hotblocks.c @@ -172,7 +296,7 @@ slightly faster (but not thread safe) counters. Example:: - ./aarch64-linux-user/qemu-aarch64 \ + $ qemu-aarch64 \ -plugin contrib/plugins/libhotblocks.so -d plugin \ ./tests/tcg/aarch64-linux-user/sha1 SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6 @@ -186,7 +310,7 @@ Example:: Similar to hotblocks but this time tracks memory accesses:: - ./aarch64-linux-user/qemu-aarch64 \ + $ qemu-aarch64 \ -plugin contrib/plugins/libhotpages.so -d plugin \ ./tests/tcg/aarch64-linux-user/sha1 SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6 @@ -220,7 +344,7 @@ counted. You can give a value to the ``count`` argument for a class of instructions to break it down fully, so for example to see all the system registers accesses:: - ./aarch64-softmmu/qemu-system-aarch64 $(QEMU_ARGS) \ + $ qemu-system-aarch64 $(QEMU_ARGS) \ -append "root=/dev/sda2 systemd.unit=benchmark.service" \ -smp 4 -plugin ./contrib/plugins/libhowvec.so,count=sreg -d plugin @@ -288,10 +412,10 @@ for the plugin is a path for the socket the two instances will communicate over:: - ./sparc-softmmu/qemu-system-sparc -monitor none -parallel none \ + $ qemu-system-sparc -monitor none -parallel none \ -net none -M SS-20 -m 256 -kernel day11/zImage.elf \ -plugin ./contrib/plugins/liblockstep.so,sockpath=lockstep-sparc.sock \ - -d plugin,nochain + -d plugin,nochain which will eventually report:: @@ -346,9 +470,9 @@ The execlog tool traces executed instructions with memory access. It can be used for debugging and security analysis purposes. Please be aware that this will generate a lot of output. -The plugin takes no argument:: +The plugin needs default argument:: - qemu-system-arm $(QEMU_ARGS) \ + $ qemu-system-arm $(QEMU_ARGS) \ -plugin ./contrib/plugins/libexeclog.so -d plugin which will output an execution trace following this structure:: @@ -364,13 +488,20 @@ which will output an execution trace following this structure:: 0, 0xd34, 0xf9c8f000, "bl #0x10c8" 0, 0x10c8, 0xfff96c43, "ldr r3, [r0, #0x44]", load, 0x200000e4, RAM +the output can be filtered to only track certain instructions or +addresses using the ``ifilter`` or ``afilter`` options. You can stack the +arguments if required:: + + $ qemu-system-arm $(QEMU_ARGS) \ + -plugin ./contrib/plugins/libexeclog.so,ifilter=st1w,afilter=0x40001808 -d plugin + - contrib/plugins/cache.c Cache modelling plugin that measures the performance of a given L1 cache configuration, and optionally a unified L2 per-core cache when a given working set is run:: - qemu-x86_64 -plugin ./contrib/plugins/libcache.so \ + $ qemu-x86_64 -plugin ./contrib/plugins/libcache.so \ -d plugin -D cache.log ./tests/tcg/x86_64-linux-user/float_convs will report the following:: @@ -441,3 +572,13 @@ The plugin has a number of arguments, all of them are optional: associativity of the L2 cache, respectively. Setting any of the L2 configuration arguments implies ``l2=on``. (default: N = 2097152 (2MB), B = 64, A = 16) + +API +--- + +The following API is generated from the inline documentation in +``include/qemu/qemu-plugin.h``. Please ensure any updates to the API +include the full kernel-doc annotations. + +.. kernel-doc:: include/qemu/qemu-plugin.h + diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 3f6ebd5073..fbb98faabe 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -81,6 +81,36 @@ QTest cases can be executed with make check-qtest +Writing portable test cases +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Both unit tests and qtests can run on POSIX hosts as well as Windows hosts. +Care must be taken when writing portable test cases that can be built and run +successfully on various hosts. The following list shows some best practices: + +* Use portable APIs from glib whenever necessary, e.g.: g_setenv(), + g_mkdtemp(), g_mkdir(). +* Avoid using hardcoded /tmp for temporary file directory. + Use g_get_tmp_dir() instead. +* Bear in mind that Windows has different special string representation for + stdin/stdout/stderr and null devices. For example if your test case uses + "/dev/fd/2" and "/dev/null" on Linux, remember to use "2" and "nul" on + Windows instead. Also IO redirection does not work on Windows, so avoid + using "2>nul" whenever necessary. +* If your test cases uses the blkdebug feature, use relative path to pass + the config and image file paths in the command line as Windows absolute + path contains the delimiter ":" which will confuse the blkdebug parser. +* Use double quotes in your extra QEMU commmand line in your test cases + instead of single quotes, as Windows does not drop single quotes when + passing the command line to QEMU. +* Windows opens a file in text mode by default, while a POSIX compliant + implementation treats text files and binary files the same. So if your + test cases opens a file to write some data and later wants to compare the + written data with the original one, be sure to pass the letter 'b' as + part of the mode string to fopen(), or O_BINARY flag for the open() call. +* If a certain test case can only run on POSIX or Linux hosts, use a proper + #ifdef in the codes. If the whole test suite cannot run on Windows, disable + the build in the meson.build file. + QAPI schema tests ~~~~~~~~~~~~~~~~~ @@ -297,7 +327,7 @@ build and test QEMU in predefined and widely accessible Linux environments. This makes it possible to expand the test coverage across distros, toolchain flavors and library versions. The support was originally written for Docker although we also support Podman as -an alternative container runtime. Although the many of the target +an alternative container runtime. Although many of the target names and scripts are prefixed with "docker" the system will automatically run on whichever is configured. @@ -375,7 +405,7 @@ locally by using the ``NOCACHE`` build option: .. code:: - make docker-image-debian10 NOCACHE=1 + make docker-image-debian-arm64-cross NOCACHE=1 Images ~~~~~~ diff --git a/docs/devel/writing-monitor-commands.rst b/docs/devel/writing-monitor-commands.rst index 4aa2bb904d..2fefedcd98 100644 --- a/docs/devel/writing-monitor-commands.rst +++ b/docs/devel/writing-monitor-commands.rst @@ -716,7 +716,7 @@ message. Here's the implementation of the "info roms" HMP command:: if (hmp_handle_error(mon, err)) { return; } - monitor_printf(mon, "%s", info->human_readable_text); + monitor_puts(mon, info->human_readable_text); } Also, you have to add the function's prototype to the hmp.h file. diff --git a/docs/interop/live-block-operations.rst b/docs/interop/live-block-operations.rst index 39e62c9915..135784ab33 100644 --- a/docs/interop/live-block-operations.rst +++ b/docs/interop/live-block-operations.rst @@ -53,7 +53,7 @@ files in a disk image backing chain: (1) Directional: 'base' and 'top'. Given the simple disk image chain above, image [A] can be referred to as 'base', and image [B] as - 'top'. (This terminology can be seen in in QAPI schema file, + 'top'. (This terminology can be seen in the QAPI schema file, block-core.json.) (2) Relational: 'backing file' and 'overlay'. Again, taking the same @@ -825,7 +825,7 @@ entire disk image chain, to a target, using ``blockdev-mirror`` would be: job ready to be completed (5) Gracefully complete the 'mirror' block device job, and notice the - the event ``BLOCK_JOB_COMPLETED`` + event ``BLOCK_JOB_COMPLETED`` (6) Shutdown the guest by issuing the QMP ``quit`` command so that caches are flushed diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst index 3063357bb5..a9183802d1 100644 --- a/docs/interop/qemu-ga.rst +++ b/docs/interop/qemu-ga.rst @@ -79,10 +79,10 @@ Options Daemonize after startup (detach from terminal). -.. option:: -b, --blacklist=LIST +.. option:: -b, --block-rpcs=LIST - Comma-separated list of RPCs to disable (no spaces, ``?`` to list - available RPCs). + Comma-separated list of RPCs to disable (no spaces, use ``help`` to + list available RPCs). .. option:: -D, --dump-conf @@ -125,7 +125,7 @@ pidfile string fsfreeze-hook string statedir string verbose boolean -blacklist string list +block-rpcs string list ============= =========== See also diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst index a8a9d22d25..2339b60ad7 100644 --- a/docs/specs/acpi_erst.rst +++ b/docs/specs/acpi_erst.rst @@ -108,7 +108,7 @@ Slot 0 contains a backend storage header that identifies the contents as ERST and also facilitates efficient access to the records. Depending upon the size of the backend storage, additional slots will be designated to be a part of the slot 0 header. For example, at 8KiB, -the slot 0 header can accomodate 1021 records. Thus a storage size +the slot 0 header can accommodate 1021 records. Thus a storage size of 8MiB (8KiB * 1024) requires an additional slot for use by the header. In this scenario, slot 0 and slot 1 form the backend storage header, and records can be stored starting at slot 2. @@ -196,5 +196,5 @@ References [2] "Unified Extensible Firmware Interface Specification", version 2.1, October 2008. -[3] "Windows Hardware Error Architecture", specfically +[3] "Windows Hardware Error Architecture", specifically "Error Record Persistence Mechanism". diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst index 3be190343a..535912a92b 100644 --- a/docs/specs/tpm.rst +++ b/docs/specs/tpm.rst @@ -250,24 +250,25 @@ hardware TPM ``/dev/tpm0``: The following commands should result in similar output inside the VM with a Linux kernel that either has the TPM TIS driver built-in or -available as a module: +available as a module (assuming a TPM 2 is passed through): .. code-block:: console # dmesg | grep -i tpm - [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) - - # dmesg | grep TCPA - [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ - BXPCTCPA 0000001 BXPC 00000001) + [ 0.012560] ACPI: TPM2 0x000000000BFFD1900 00004C (v04 BOCHS \ + BXPC 0000001 BXPC 00000001) # ls -l /dev/tpm* - crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 + crw-rw----. 1 tss root 10, 224 Sep 6 12:36 /dev/tpm0 + crw-rw----. 1 tss rss 253, 65536 Sep 6 12:36 /dev/tpmrm0 - # find /sys/devices/ | grep pcrs$ | xargs cat - PCR-00: 35 4E 3B CE 23 9F 38 59 ... + Starting with Linux 5.12 there are PCR entries for TPM 2 in sysfs: + # find /sys/devices/ -type f | grep pcr-sha + ... + /sys/devices/LNXSYSTEM:00/LNXSYBUS:00/MSFT0101:00/tpm/tpm0/pcr-sha256/1 + ... + /sys/devices/LNXSYSTEM:00/LNXSYBUS:00/MSFT0101:00/tpm/tpm0/pcr-sha256/9 ... - PCR-23: 00 00 00 00 00 00 00 00 ... The QEMU TPM emulator device ---------------------------- @@ -304,6 +305,7 @@ a socket interface. They do not need to be run as root. mkdir /tmp/mytpm1 swtpm socket --tpmstate dir=/tmp/mytpm1 \ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ + --tpm2 \ --log level=20 Command line to start QEMU with the TPM emulator device communicating @@ -365,19 +367,20 @@ available as a module: .. code-block:: console # dmesg | grep -i tpm - [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) - - # dmesg | grep TCPA - [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ - BXPCTCPA 0000001 BXPC 00000001) + [ 0.012560] ACPI: TPM2 0x000000000BFFD1900 00004C (v04 BOCHS \ + BXPC 0000001 BXPC 00000001) # ls -l /dev/tpm* - crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 + crw-rw----. 1 tss root 10, 224 Sep 6 12:36 /dev/tpm0 + crw-rw----. 1 tss rss 253, 65536 Sep 6 12:36 /dev/tpmrm0 - # find /sys/devices/ | grep pcrs$ | xargs cat - PCR-00: 35 4E 3B CE 23 9F 38 59 ... + Starting with Linux 5.12 there are PCR entries for TPM 2 in sysfs: + # find /sys/devices/ -type f | grep pcr-sha + ... + /sys/devices/LNXSYSTEM:00/LNXSYBUS:00/MSFT0101:00/tpm/tpm0/pcr-sha256/1 + ... + /sys/devices/LNXSYSTEM:00/LNXSYBUS:00/MSFT0101:00/tpm/tpm0/pcr-sha256/9 ... - PCR-23: 00 00 00 00 00 00 00 00 ... Migration with the TPM emulator =============================== @@ -398,7 +401,8 @@ In a 1st terminal start an instance of a swtpm using the following command: mkdir /tmp/mytpm1 swtpm socket --tpmstate dir=/tmp/mytpm1 \ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ - --log level=20 --tpm2 + --tpm2 \ + --log level=20 In a 2nd terminal start the VM: diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst index 3fd76fa0b4..c2c01ec7d2 100644 --- a/docs/system/arm/cpu-features.rst +++ b/docs/system/arm/cpu-features.rst @@ -284,7 +284,7 @@ SVE CPU Property Parsing Semantics CPU Property Dependencies and Constraints"). 4) If one or more vector lengths have been explicitly enabled and at - at least one of the dependency lengths of the maximum enabled length + least one of the dependency lengths of the maximum enabled length has been explicitly disabled, then an error is generated (see constraint (2) of "SVE CPU Property Dependencies and Constraints"). diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 8e494c8bea..cfb4b0768b 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -24,12 +24,14 @@ the following architecture extensions: - FEAT_Debugv8p4 (Debug changes for v8.4) - FEAT_DotProd (Advanced SIMD dot product instructions) - FEAT_DoubleFault (Double Fault Extension) +- FEAT_ETS (Enhanced Translation Synchronization) - FEAT_FCMA (Floating-point complex number instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions) - FEAT_FP16 (Half-precision floating-point data processing) - FEAT_FRINTTS (Floating-point to integer instructions) - FEAT_FlagM (Flag manipulation instructions v2) - FEAT_FlagM2 (Enhancements to flag manipulation instructions) +- FEAT_GTG (Guest translation granule size) - FEAT_HCX (Support for the HCRX_EL2 register) - FEAT_HPDS (Hierarchical permission disables) - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) @@ -52,6 +54,7 @@ the following architecture extensions: - FEAT_PMULL (PMULL, PMULL2 instructions) - FEAT_PMUv3p1 (PMU Extensions v3.1) - FEAT_PMUv3p4 (PMU Extensions v3.4) +- FEAT_PMUv3p5 (PMU Extensions v3.5) - FEAT_RAS (Reliability, availability, and serviceability) - FEAT_RASv1p1 (RAS Extension v1.1) - FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions) diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst index ef2792076a..c38df32bde 100644 --- a/docs/system/arm/nuvoton.rst +++ b/docs/system/arm/nuvoton.rst @@ -82,9 +82,9 @@ Boot options The Nuvoton machines can boot from an OpenBMC firmware image, or directly into a kernel using the ``-kernel`` option. OpenBMC images for ``quanta-gsj`` and -possibly others can be downloaded from the OpenPOWER jenkins : +possibly others can be downloaded from the OpenBMC jenkins : - https://openpower.xyz/ + https://jenkins.openbmc.org/ The firmware image should be attached as an MTD drive. Example : diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 3b6ba69a9a..20442ea2c1 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -52,6 +52,7 @@ Supported guest CPU types: - ``cortex-a7`` (32-bit) - ``cortex-a15`` (32-bit; the default) +- ``cortex-a35`` (64-bit) - ``cortex-a53`` (64-bit) - ``cortex-a57`` (64-bit) - ``cortex-a72`` (64-bit) diff --git a/docs/system/devices/canokey.rst b/docs/system/devices/canokey.rst index c2c58ae3e7..cfa6186e48 100644 --- a/docs/system/devices/canokey.rst +++ b/docs/system/devices/canokey.rst @@ -28,9 +28,9 @@ With the same software configuration as a hardware key, the guest OS can use all the functionalities of a secure key as if there was actually an hardware key plugged in. -CanoKey QEMU provides much convenience for debuging: +CanoKey QEMU provides much convenience for debugging: -* libcanokey-qemu supports debuging output thus developers can +* libcanokey-qemu supports debugging output thus developers can inspect what happens inside a secure key * CanoKey QEMU supports trace event thus event * QEMU USB stack supports pcap thus USB packet between the guest @@ -102,8 +102,8 @@ and find CanoKey QEMU there: You may setup the key as guided in [6]_. The console for the key is at [7]_. -Debuging -======== +Debugging +========= CanoKey QEMU consists of two parts, ``libcanokey-qemu.so`` and ``canokey.c``, the latter of which resides in QEMU. The former provides core functionality diff --git a/docs/system/devices/cxl.rst b/docs/system/devices/cxl.rst index a57e4c4e5c..f25783a4ec 100644 --- a/docs/system/devices/cxl.rst +++ b/docs/system/devices/cxl.rst @@ -15,7 +15,7 @@ with CXL Host Bridges, which have CXL Root Ports which may be directly attached to CXL or PCI End Points. Alternatively there may be CXL Switches with CXL and PCI Endpoints attached below them. In many cases additional control and capabilities are exposed via PCI Express interfaces. -This sharing of interfaces and hence emulation code is is reflected +This sharing of interfaces and hence emulation code is reflected in how the devices are emulated in QEMU. In most cases the various CXL elements are built upon an equivalent PCIe devices. @@ -83,7 +83,7 @@ CXL Fixed Memory Windows (CFMW) A CFMW consists of a particular range of Host Physical Address space which is routed to particular CXL Host Bridges. At time of generic software initialization it will have a particularly interleaving -configuration and associated Quality of Serice Throtling Group (QTG). +configuration and associated Quality of Service Throttling Group (QTG). This information is available to system software, when making decisions about how to configure interleave across available CXL memory devices. It is provide as CFMW Structures (CFMWS) in @@ -98,7 +98,7 @@ specification defined register interface called CXL Host Bridge Component Registers (CHBCR). The location of this CHBCR MMIO space is described to system software via a CXL Host Bridge Structure (CHBS) in the CEDT ACPI table. The actual interfaces -are identical to those used for other parts of the CXL heirarchy +are identical to those used for other parts of the CXL hierarchy as CXL Component Registers in PCI BARs. Interfaces provided include: @@ -143,7 +143,7 @@ CXL Memory Devices - Type 3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ CXL type 3 devices use a PCI class code and are intended to be supported by a generic operating system driver. They have HDM decoders -though in these EP devices, the decoder is reponsible not for +though in these EP devices, the decoder is responsible not for routing but for translation of the incoming host physical address (HPA) into a Device Physical Address (DPA). @@ -209,7 +209,7 @@ Notes: ranges of the system physical address map. Each CFMW has particular interleave setup across the CXL Host Bridges (HB) CFMW0 provides uninterleaved access to HB0, CFW2 provides - uninterleaved acess to HB1. CFW1 provides interleaved memory access + uninterleaved access to HB1. CFW1 provides interleaved memory access across HB0 and HB1. (2) **Two CXL Host Bridges**. Each of these has 2 CXL Root Ports and @@ -282,7 +282,7 @@ Example topology involving a switch:: --------------------------------------------------- | Switch 0 USP as PCI 0d:00.0 | | USP has HDM decoder which direct traffic to | - | appropiate downstream port | + | appropriate downstream port | | Switch BUS appears as 0e | |x__________________________________________________| | | | | @@ -366,7 +366,7 @@ An example of 4 devices below a switch suitable for 1, 2 or 4 way interleave:: Kernel Configuration Options ---------------------------- -In Linux 5.18 the followings options are necessary to make use of +In Linux 5.18 the following options are necessary to make use of OS management of CXL memory devices as described here. * CONFIG_CXL_BUS diff --git a/docs/system/devices/usb.rst b/docs/system/devices/usb.rst index f39a88f080..37cb9b33ae 100644 --- a/docs/system/devices/usb.rst +++ b/docs/system/devices/usb.rst @@ -178,8 +178,20 @@ option or the ``device_add`` monitor command. Available devices are: host character device id. ``usb-braille,chardev=id`` - Braille device. This will use BrlAPI to display the braille output on - a real or fake device referenced by id. + Braille device. This emulates a Baum Braille device USB port. id has to + specify a character device defined with ``-chardev …,id=id``. One will + normally use BrlAPI to display the braille output on a BRLTTY-supported + device with + + .. parsed-literal:: + + |qemu_system| [...] -chardev braille,id=brl -device usb-braille,chardev=brl + + or alternatively, use the following equivalent shortcut: + + .. parsed-literal:: + + |qemu_system| [...] -usbdevice braille ``usb-net[,netdev=id]`` Network adapter that supports CDC ethernet and RNDIS protocols. id diff --git a/docs/system/loongarch/loongson3.rst b/docs/system/loongarch/loongson3.rst index fa3acd01c0..1bdab44e27 100644 --- a/docs/system/loongarch/loongson3.rst +++ b/docs/system/loongarch/loongson3.rst @@ -15,27 +15,115 @@ The ``virt`` machine supports: - Gpex host bridge - Ls7a RTC device - Ls7a IOAPIC device -- Ls7a ACPI device +- ACPI GED device - Fw_cfg device - PCI/PCIe devices - Memory device -- CPU device. Type: Loongson-3A5000. +- CPU device. Type: la464-loongarch-cpu. CPU and machine Type -------------------- The ``qemu-system-loongarch64`` provides emulation for virt machine. You can specify the machine type ``virt`` and -cpu type ``Loongson-3A5000``. +cpu type ``la464-loongarch-cpu``. Boot options ------------ -Now the ``virt`` machine can run test program in ELF format and the -method of compiling is in target/loongarch/README. +We can boot the LoongArch virt machine by specifying the uefi bios, +initrd, and linux kernel. And those source codes and binary files +can be accessed by following steps. + +(1) booting command: .. code-block:: bash - $ qemu-system-loongarch64 -machine virt -m 4G -cpu Loongson-3A5000 \ - -smp 1 -kernel hello -monitor none -display none \ - -chardev file,path=hello.out,id=output -serial chardev:output + $ qemu-system-loongarch64 -machine virt -m 4G -cpu la464-loongarch-cpu \ + -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd initrd.img \ + -append "root=/dev/ram rdinit=/sbin/init consol e=ttyS0,115200" \ + --nographic + +Note: The running speed may be a little slow, as the performance of our +qemu and uefi bios is not perfect, and it is being fixed. + +(2) cross compiler tools: + +.. code-block:: bash + + wget https://github.com/loongson/build-tools/releases/download/ \ + 2022.05.29/loongarch64-clfs-5.0-cross-tools-gcc-full.tar.xz + + tar -vxf loongarch64-clfs-5.0-cross-tools-gcc-full.tar.xz + +(3) qemu compile configure option: + +.. code-block:: bash + + ./configure --disable-rdma --disable-pvrdma --prefix=usr \ + --target-list="loongarch64-softmmu" \ + --disable-libiscsi --disable-libnfs --disable-libpmem \ + --disable-glusterfs --enable-libusb --enable-usb-redir \ + --disable-opengl --disable-xen --enable-spice \ + --enable-debug --disable-capstone --disable-kvm \ + --enable-profiler + make + +(4) uefi bios source code and compile method: + +.. code-block:: bash + + git clone https://github.com/loongson/edk2-LoongarchVirt.git + + cd edk2-LoongarchVirt + + git submodule update --init + + export PATH=$YOUR_COMPILER_PATH/bin:$PATH + + export WORKSPACE=`pwd` + + export PACKAGES_PATH=$WORKSPACE/edk2-LoongarchVirt + + export GCC5_LOONGARCH64_PREFIX=loongarch64-unknown-linux-gnu- + + edk2-LoongarchVirt/edksetup.sh + + make -C edk2-LoongarchVirt/BaseTools + + build --buildtarget=DEBUG --tagname=GCC5 --arch=LOONGARCH64 --platform=OvmfPkg/LoongArchQemu/Loongson.dsc + + build --buildtarget=RELEASE --tagname=GCC5 --arch=LOONGARCH64 --platform=OvmfPkg/LoongArchQemu/Loongson.dsc + +The efi binary file path: + + Build/LoongArchQemu/DEBUG_GCC5/FV/QEMU_EFI.fd + + Build/LoongArchQemu/RELEASE_GCC5/FV/QEMU_EFI.fd + +(5) linux kernel source code and compile method: + +.. code-block:: bash + + git clone https://github.com/loongson/linux.git + + export PATH=$YOUR_COMPILER_PATH/bin:$PATH + + export LD_LIBRARY_PATH=$YOUR_COMPILER_PATH/lib:$LD_LIBRARY_PATH + + export LD_LIBRARY_PATH=$YOUR_COMPILER_PATH/loongarch64-unknown-linux-gnu/lib/:$LD_LIBRARY_PATH + + make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig + + make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- + + make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- install + + make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- modules_install + +Note: The branch of linux source code is loongarch-next. + +(6) initrd file: + + You can use busybox tool and the linux modules to make a initrd file. Or you can access the + binary files: https://github.com/yangxiaojuan-loongson/qemu-binary diff --git a/docs/system/openrisc/cpu-features.rst b/docs/system/openrisc/cpu-features.rst new file mode 100644 index 0000000000..aeb65e22ff --- /dev/null +++ b/docs/system/openrisc/cpu-features.rst @@ -0,0 +1,15 @@ +CPU Features +============ + +The QEMU emulation of the OpenRISC architecture provides following built in +features. + +- Shadow GPRs +- MMU TLB with 128 entries, 1 way +- Power Management (PM) +- Programmable Interrupt Controller (PIC) +- Tick Timer + +These features are on by default and the presence can be confirmed by checking +the contents of the Unit Presence Register (``UPR``) and CPU Configuration +Register (``CPUCFGR``). diff --git a/docs/system/openrisc/emulation.rst b/docs/system/openrisc/emulation.rst new file mode 100644 index 0000000000..0af898ab20 --- /dev/null +++ b/docs/system/openrisc/emulation.rst @@ -0,0 +1,17 @@ +OpenRISC 1000 CPU architecture support +====================================== + +QEMU's TCG emulation includes support for the OpenRISC or1200 implementation of +the OpenRISC 1000 cpu architecture. + +The or1200 cpu also has support for the following instruction subsets: + +- ORBIS32 (OpenRISC Basic Instruction Set) +- ORFPX32 (OpenRISC Floating-Point eXtension) + +In addition to the instruction subsets the QEMU TCG emulation also has support +for most Class II (optional) instructions. + +For information on all OpenRISC instructions please refer to the latest +architecture manual available on the OpenRISC website in the +`OpenRISC Architecture `_ section. diff --git a/docs/system/openrisc/or1k-sim.rst b/docs/system/openrisc/or1k-sim.rst new file mode 100644 index 0000000000..ef10439737 --- /dev/null +++ b/docs/system/openrisc/or1k-sim.rst @@ -0,0 +1,43 @@ +Or1ksim board +============= + +The QEMU Or1ksim machine emulates the standard OpenRISC board simulator which is +also the standard SoC configuration. + +Supported devices +----------------- + + * 16550A UART + * ETHOC Ethernet controller + * SMP (OpenRISC multicore using ompic) + +Boot options +------------ + +The Or1ksim machine can be started using the ``-kernel`` and ``-initrd`` options +to load a Linux kernel and optional disk image. + +.. code-block:: bash + + $ qemu-system-or1k -cpu or1220 -M or1k-sim -nographic \ + -kernel vmlinux \ + -initrd initramfs.cpio.gz \ + -m 128 + +Linux guest kernel configuration +"""""""""""""""""""""""""""""""" + +The 'or1ksim_defconfig' for Linux openrisc kernels includes the right +drivers for the or1ksim machine. If you would like to run an SMP system +choose the 'simple_smp_defconfig' config. + +Hardware configuration information +"""""""""""""""""""""""""""""""""" + +The ``or1k-sim`` board automatically generates a device tree blob ("dtb") +which it passes to the guest. This provides information about the +addresses, interrupt lines and other configuration of the various devices +in the system. + +The location of the DTB will be passed in register ``r3`` to the guest operating +system. diff --git a/docs/system/openrisc/virt.rst b/docs/system/openrisc/virt.rst new file mode 100644 index 0000000000..2fe61ac942 --- /dev/null +++ b/docs/system/openrisc/virt.rst @@ -0,0 +1,50 @@ +'virt' generic virtual platform +=============================== + +The ``virt`` board is a platform which does not correspond to any +real hardware; it is designed for use in virtual machines. +It is the recommended board type if you simply want to run +a guest such as Linux and do not care about reproducing the +idiosyncrasies and limitations of a particular bit of real-world +hardware. + +Supported devices +----------------- + + * PCI/PCIe devices + * 8 virtio-mmio transport devices + * 16550A UART + * Goldfish RTC + * SiFive Test device for poweroff and reboot + * SMP (OpenRISC multicore using ompic) + +Boot options +------------ + +The virt machine can be started using the ``-kernel`` and ``-initrd`` options +to load a Linux kernel and optional disk image. For example: + +.. code-block:: bash + + $ qemu-system-or1k -cpu or1220 -M or1k-sim -nographic \ + -device virtio-net-device,netdev=user -netdev user,id=user,net=10.9.0.1/24,host=10.9.0.100 \ + -device virtio-blk-device,drive=d0 -drive file=virt.qcow2,id=d0,if=none,format=qcow2 \ + -kernel vmlinux \ + -initrd initramfs.cpio.gz \ + -m 128 + +Linux guest kernel configuration +"""""""""""""""""""""""""""""""" + +The 'virt_defconfig' for Linux openrisc kernels includes the right drivers for +the ``virt`` machine. + +Hardware configuration information +"""""""""""""""""""""""""""""""""" + +The ``virt`` board automatically generates a device tree blob ("dtb") which it +passes to the guest. This provides information about the addresses, interrupt +lines and other configuration of the various devices in the system. + +The location of the DTB will be passed in register ``r3`` to the guest operating +system. diff --git a/docs/system/ppc/embedded.rst b/docs/system/ppc/embedded.rst index cfffbda24d..af3b3d9fa4 100644 --- a/docs/system/ppc/embedded.rst +++ b/docs/system/ppc/embedded.rst @@ -6,5 +6,4 @@ Embedded family boards - ``ppce500`` generic paravirt e500 platform - ``ref405ep`` ref405ep - ``sam460ex`` aCube Sam460ex -- ``taihu`` taihu - ``virtex-ml507`` Xilinx Virtex ML507 reference design diff --git a/docs/system/ppc/pseries.rst b/docs/system/ppc/pseries.rst index 3e1bbe6726..a876d897b6 100644 --- a/docs/system/ppc/pseries.rst +++ b/docs/system/ppc/pseries.rst @@ -62,7 +62,7 @@ Booting via ``-kernel`` supports the following: +-------------------+-------------------+------------------+ | vmlinux LE | ✓ | ✓ | +-------------------+-------------------+------------------+ -| zImage.pseries BE | x | ✓¹ | +| zImage.pseries BE | ✓¹ | ✓¹ | +-------------------+-------------------+------------------+ | zImage.pseries LE | ✓ | ✓ | +-------------------+-------------------+------------------+ diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst index f8ecec95f3..4b16e41d7f 100644 --- a/docs/system/riscv/virt.rst +++ b/docs/system/riscv/virt.rst @@ -168,14 +168,19 @@ Enabling TPM A TPM device can be connected to the virt board by following the steps below. -First launch the TPM emulator +First launch the TPM emulator: - swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm \ +.. code-block:: bash + + $ swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm \ --ctrl type=unixio,path=swtpm-sock -Then launch QEMU with: +Then launch QEMU with some additional arguments to link a TPM device to the backend: - ... +.. code-block:: bash + + $ qemu-system-riscv64 \ + ... other args .... \ -chardev socket,id=chrtpm,path=swtpm-sock \ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -device tpm-tis-device,tpmdev=tpm0 diff --git a/docs/system/s390x/bootdevices.rst b/docs/system/s390x/bootdevices.rst index 9e591cb9dc..b5950133e8 100644 --- a/docs/system/s390x/bootdevices.rst +++ b/docs/system/s390x/bootdevices.rst @@ -65,7 +65,7 @@ you can specify it via the ``-global s390-ipl.netboot_fw=filename`` command line option. The ``bootindex`` property is especially important for booting via the network. -If you don't specify the the ``bootindex`` property here, the network bootloader +If you don't specify the ``bootindex`` property here, the network bootloader firmware code won't get loaded into the guest memory so that the network boot will fail. For a successful network boot, try something like this:: diff --git a/docs/system/target-openrisc.rst b/docs/system/target-openrisc.rst new file mode 100644 index 0000000000..22cb2217a6 --- /dev/null +++ b/docs/system/target-openrisc.rst @@ -0,0 +1,71 @@ +.. _OpenRISC-System-emulator: + +OpenRISC System emulator +~~~~~~~~~~~~~~~~~~~~~~~~ + +QEMU can emulate 32-bit OpenRISC CPUs using the ``qemu-system-or1k`` executable. + +OpenRISC CPUs are generally built into "system-on-chip" (SoC) designs that run +on FPGAs. These SoCs are based on the same core architecture as the or1ksim +(the original OpenRISC instruction level simulator) which QEMU supports. For +this reason QEMU does not need to support many different boards to support the +OpenRISC hardware ecosystem. + +The OpenRISC CPU supported by QEMU is the ``or1200``, it supports an MMU and can +run linux. + +Choosing a board model +====================== + +For QEMU's OpenRISC system emulation, you must specify which board model you +want to use with the ``-M`` or ``--machine`` option; the default machine is +``or1k-sim``. + +If you intend to boot Linux, it is possible to have a single kernel image that +will boot on any of the QEMU machines. To do this one would compile all required +drivers into the kernel. This is possible because QEMU will create a device tree +structure that describes the QEMU machine and pass a pointer to the structure to +the kernel. The kernel can then use this to configure itself for the machine. + +However, typically users will have specific firmware images for a specific machine. + +If you already have a system image or a kernel that works on hardware and you +want to boot with QEMU, check whether QEMU lists that machine in its ``-machine +help`` output. If it is listed, then you can probably use that board model. If +it is not listed, then unfortunately your image will almost certainly not boot +on QEMU. (You might be able to extract the filesystem and use that with a +different kernel which boots on a system that QEMU does emulate.) + +If you don't care about reproducing the idiosyncrasies of a particular +bit of hardware, such as small amount of RAM, no PCI or other hard disk, etc., +and just want to run Linux, the best option is to use the ``virt`` board. This +is a platform which doesn't correspond to any real hardware and is designed for +use in virtual machines. You'll need to compile Linux with a suitable +configuration for running on the ``virt`` board. ``virt`` supports PCI, virtio +and large amounts of RAM. + +Board-specific documentation +============================ + +.. + This table of contents should be kept sorted alphabetically + by the title text of each file, which isn't the same ordering + as an alphabetical sort by filename. + +.. toctree:: + :maxdepth: 1 + + openrisc/or1k-sim + openrisc/virt + +Emulated CPU architecture support +================================= + +.. toctree:: + openrisc/emulation + +OpenRISC CPU features +===================== + +.. toctree:: + openrisc/cpu-features diff --git a/docs/system/targets.rst b/docs/system/targets.rst index 9dcd95dd84..224fadae71 100644 --- a/docs/system/targets.rst +++ b/docs/system/targets.rst @@ -21,6 +21,7 @@ Contents: target-m68k target-mips target-ppc + target-openrisc target-riscv target-rx target-s390x diff --git a/docs/system/tls.rst b/docs/system/tls.rst index 1a04674362..e284c82801 100644 --- a/docs/system/tls.rst +++ b/docs/system/tls.rst @@ -182,7 +182,7 @@ certificates. --template client-hostNNN.info \ --outfile client-hostNNN-cert.pem -The subject alt name extension data is not required for clients, so the +The subject alt name extension data is not required for clients, so the ``dns_name`` and ``ip_address`` fields are not included. The ``tls_www_client`` keyword is the key purpose extension to indicate this certificate is intended for usage in a web client. Although QEMU network diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index 85a6e05b35..15aeddc6d8 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -57,7 +57,7 @@ cases. See below for a description of the supported disk formats. *OUTPUT_FMT* is the destination format. *OPTIONS* is a comma separated list of format specific options in a -name=value format. Use ``-o ?`` for an overview of the options supported +name=value format. Use ``-o help`` for an overview of the options supported by the used format or see the format descriptions below for details. *SNAPSHOT_PARAM* is param used for internal snapshot, format is diff --git a/docs/tools/qemu-pr-helper.rst b/docs/tools/qemu-pr-helper.rst index eaebe40da0..c32867cfc6 100644 --- a/docs/tools/qemu-pr-helper.rst +++ b/docs/tools/qemu-pr-helper.rst @@ -21,8 +21,8 @@ programs because incorrect usage can disrupt regular operation of the storage fabric. QEMU's SCSI passthrough devices ``scsi-block`` and ``scsi-generic`` support passing guest persistent reservation requests to a privileged external helper program. :program:`qemu-pr-helper` -is that external helper; it creates a socket which QEMU can -connect to to communicate with it. +is that external helper; it creates a listener socket which will +accept incoming connections for communication with QEMU. If you want to run VMs in a setup like this, this helper should be started as a system service, and you should read the QEMU manual diff --git a/dump/dump.c b/dump/dump.c index 4d9658ffa2..236559b03a 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -59,6 +59,11 @@ static inline bool dump_is_64bit(DumpState *s) return s->dump_info.d_class == ELFCLASS64; } +static inline bool dump_has_filter(DumpState *s) +{ + return s->filter_area_length > 0; +} + uint16_t cpu_to_dump16(DumpState *s, uint16_t val) { if (s->dump_info.d_endian == ELFDATA2LSB) { @@ -126,7 +131,7 @@ static int fd_write_vmcore(const void *buf, size_t size, void *opaque) return 0; } -static void write_elf64_header(DumpState *s, Error **errp) +static void prepare_elf64_header(DumpState *s, Elf64_Ehdr *elf_header) { /* * phnum in the elf header is 16 bit, if we have more segments we @@ -134,34 +139,27 @@ static void write_elf64_header(DumpState *s, Error **errp) * special section. */ uint16_t phnum = MIN(s->phdr_num, PN_XNUM); - Elf64_Ehdr elf_header; - int ret; - memset(&elf_header, 0, sizeof(Elf64_Ehdr)); - memcpy(&elf_header, ELFMAG, SELFMAG); - elf_header.e_ident[EI_CLASS] = ELFCLASS64; - elf_header.e_ident[EI_DATA] = s->dump_info.d_endian; - elf_header.e_ident[EI_VERSION] = EV_CURRENT; - elf_header.e_type = cpu_to_dump16(s, ET_CORE); - elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine); - elf_header.e_version = cpu_to_dump32(s, EV_CURRENT); - elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header)); - elf_header.e_phoff = cpu_to_dump64(s, s->phdr_offset); - elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr)); - elf_header.e_phnum = cpu_to_dump16(s, phnum); + memset(elf_header, 0, sizeof(Elf64_Ehdr)); + memcpy(elf_header, ELFMAG, SELFMAG); + elf_header->e_ident[EI_CLASS] = ELFCLASS64; + elf_header->e_ident[EI_DATA] = s->dump_info.d_endian; + elf_header->e_ident[EI_VERSION] = EV_CURRENT; + elf_header->e_type = cpu_to_dump16(s, ET_CORE); + elf_header->e_machine = cpu_to_dump16(s, s->dump_info.d_machine); + elf_header->e_version = cpu_to_dump32(s, EV_CURRENT); + elf_header->e_ehsize = cpu_to_dump16(s, sizeof(elf_header)); + elf_header->e_phoff = cpu_to_dump64(s, s->phdr_offset); + elf_header->e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr)); + elf_header->e_phnum = cpu_to_dump16(s, phnum); if (s->shdr_num) { - elf_header.e_shoff = cpu_to_dump64(s, s->shdr_offset); - elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr)); - elf_header.e_shnum = cpu_to_dump16(s, s->shdr_num); - } - - ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); - if (ret < 0) { - error_setg_errno(errp, -ret, "dump: failed to write elf header"); + elf_header->e_shoff = cpu_to_dump64(s, s->shdr_offset); + elf_header->e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr)); + elf_header->e_shnum = cpu_to_dump16(s, s->shdr_num); } } -static void write_elf32_header(DumpState *s, Error **errp) +static void prepare_elf32_header(DumpState *s, Elf32_Ehdr *elf_header) { /* * phnum in the elf header is 16 bit, if we have more segments we @@ -169,28 +167,45 @@ static void write_elf32_header(DumpState *s, Error **errp) * special section. */ uint16_t phnum = MIN(s->phdr_num, PN_XNUM); - Elf32_Ehdr elf_header; + + memset(elf_header, 0, sizeof(Elf32_Ehdr)); + memcpy(elf_header, ELFMAG, SELFMAG); + elf_header->e_ident[EI_CLASS] = ELFCLASS32; + elf_header->e_ident[EI_DATA] = s->dump_info.d_endian; + elf_header->e_ident[EI_VERSION] = EV_CURRENT; + elf_header->e_type = cpu_to_dump16(s, ET_CORE); + elf_header->e_machine = cpu_to_dump16(s, s->dump_info.d_machine); + elf_header->e_version = cpu_to_dump32(s, EV_CURRENT); + elf_header->e_ehsize = cpu_to_dump16(s, sizeof(elf_header)); + elf_header->e_phoff = cpu_to_dump32(s, s->phdr_offset); + elf_header->e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr)); + elf_header->e_phnum = cpu_to_dump16(s, phnum); + if (s->shdr_num) { + elf_header->e_shoff = cpu_to_dump32(s, s->shdr_offset); + elf_header->e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr)); + elf_header->e_shnum = cpu_to_dump16(s, s->shdr_num); + } +} + +static void write_elf_header(DumpState *s, Error **errp) +{ + Elf32_Ehdr elf32_header; + Elf64_Ehdr elf64_header; + size_t header_size; + void *header_ptr; int ret; - memset(&elf_header, 0, sizeof(Elf32_Ehdr)); - memcpy(&elf_header, ELFMAG, SELFMAG); - elf_header.e_ident[EI_CLASS] = ELFCLASS32; - elf_header.e_ident[EI_DATA] = s->dump_info.d_endian; - elf_header.e_ident[EI_VERSION] = EV_CURRENT; - elf_header.e_type = cpu_to_dump16(s, ET_CORE); - elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine); - elf_header.e_version = cpu_to_dump32(s, EV_CURRENT); - elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header)); - elf_header.e_phoff = cpu_to_dump32(s, s->phdr_offset); - elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr)); - elf_header.e_phnum = cpu_to_dump16(s, phnum); - if (s->shdr_num) { - elf_header.e_shoff = cpu_to_dump32(s, s->shdr_offset); - elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr)); - elf_header.e_shnum = cpu_to_dump16(s, s->shdr_num); + if (dump_is_64bit(s)) { + prepare_elf64_header(s, &elf64_header); + header_size = sizeof(elf64_header); + header_ptr = &elf64_header; + } else { + prepare_elf32_header(s, &elf32_header); + header_size = sizeof(elf32_header); + header_ptr = &elf32_header; } - ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); + ret = fd_write_vmcore(header_ptr, header_size, s); if (ret < 0) { error_setg_errno(errp, -ret, "dump: failed to write elf header"); } @@ -245,7 +260,7 @@ static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, } } -static void write_elf64_phdr_note(DumpState *s, Elf64_Phdr *phdr) +static void prepare_elf64_phdr_note(DumpState *s, Elf64_Phdr *phdr) { memset(phdr, 0, sizeof(*phdr)); phdr->p_type = cpu_to_dump32(s, PT_NOTE); @@ -301,7 +316,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, write_guest_note(f, s, errp); } -static void write_elf32_phdr_note(DumpState *s, Elf32_Phdr *phdr) +static void prepare_elf32_phdr_note(DumpState *s, Elf32_Phdr *phdr) { memset(phdr, 0, sizeof(*phdr)); phdr->p_type = cpu_to_dump32(s, PT_NOTE); @@ -349,11 +364,11 @@ static void write_elf_phdr_note(DumpState *s, Error **errp) int ret; if (dump_is_64bit(s)) { - write_elf64_phdr_note(s, &phdr64); + prepare_elf64_phdr_note(s, &phdr64); size = sizeof(phdr64); phdr = &phdr64; } else { - write_elf32_phdr_note(s, &phdr32); + prepare_elf32_phdr_note(s, &phdr32); size = sizeof(phdr32); phdr = &phdr32; } @@ -443,29 +458,30 @@ static void get_offset_range(hwaddr phys_addr, *p_offset = -1; *p_filesz = 0; - if (s->has_filter) { - if (phys_addr < s->begin || phys_addr >= s->begin + s->length) { + if (dump_has_filter(s)) { + if (phys_addr < s->filter_area_begin || + phys_addr >= s->filter_area_begin + s->filter_area_length) { return; } } QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { - if (s->has_filter) { - if (block->target_start >= s->begin + s->length || - block->target_end <= s->begin) { + if (dump_has_filter(s)) { + if (block->target_start >= s->filter_area_begin + s->filter_area_length || + block->target_end <= s->filter_area_begin) { /* This block is out of the range */ continue; } - if (s->begin <= block->target_start) { + if (s->filter_area_begin <= block->target_start) { start = block->target_start; } else { - start = s->begin; + start = s->filter_area_begin; } size_in_block = block->target_end - start; - if (s->begin + s->length < block->target_end) { - size_in_block -= block->target_end - (s->begin + s->length); + if (s->filter_area_begin + s->filter_area_length < block->target_end) { + size_in_block -= block->target_end - (s->filter_area_begin + s->filter_area_length); } } else { start = block->target_start; @@ -490,7 +506,7 @@ static void get_offset_range(hwaddr phys_addr, } } -static void write_elf_loads(DumpState *s, Error **errp) +static void write_elf_phdr_loads(DumpState *s, Error **errp) { ERRP_GUARD(); hwaddr offset, filesz; @@ -558,11 +574,7 @@ static void dump_begin(DumpState *s, Error **errp) */ /* write elf header to vmcore */ - if (dump_is_64bit(s)) { - write_elf64_header(s, errp); - } else { - write_elf32_header(s, errp); - } + write_elf_header(s, errp); if (*errp) { return; } @@ -573,8 +585,8 @@ static void dump_begin(DumpState *s, Error **errp) return; } - /* write all PT_LOAD to vmcore */ - write_elf_loads(s, errp); + /* write all PT_LOADs to vmcore */ + write_elf_phdr_loads(s, errp); if (*errp) { return; } @@ -591,31 +603,43 @@ static void dump_begin(DumpState *s, Error **errp) write_elf_notes(s, errp); } -static int get_next_block(DumpState *s, GuestPhysBlock *block) +static int64_t dump_filtered_memblock_size(GuestPhysBlock *block, + int64_t filter_area_start, + int64_t filter_area_length) { - while (1) { - block = QTAILQ_NEXT(block, next); - if (!block) { - /* no more block */ - return 1; - } + int64_t size, left, right; - s->start = 0; - s->next_block = block; - if (s->has_filter) { - if (block->target_start >= s->begin + s->length || - block->target_end <= s->begin) { - /* This block is out of the range */ - continue; - } - - if (s->begin > block->target_start) { - s->start = s->begin - block->target_start; - } - } - - return 0; + /* No filter, return full size */ + if (!filter_area_length) { + return block->target_end - block->target_start; } + + /* calculate the overlapped region. */ + left = MAX(filter_area_start, block->target_start); + right = MIN(filter_area_start + filter_area_length, block->target_end); + size = right - left; + size = size > 0 ? size : 0; + + return size; +} + +static int64_t dump_filtered_memblock_start(GuestPhysBlock *block, + int64_t filter_area_start, + int64_t filter_area_length) +{ + if (filter_area_length) { + /* return -1 if the block is not within filter area */ + if (block->target_start >= filter_area_start + filter_area_length || + block->target_end <= filter_area_start) { + return -1; + } + + if (filter_area_start > block->target_start) { + return filter_area_start - block->target_start; + } + } + + return 0; } /* write all memory to vmcore */ @@ -623,24 +647,22 @@ static void dump_iterate(DumpState *s, Error **errp) { ERRP_GUARD(); GuestPhysBlock *block; - int64_t size; + int64_t memblock_size, memblock_start; - do { - block = s->next_block; - - size = block->target_end - block->target_start; - if (s->has_filter) { - size -= s->start; - if (s->begin + s->length < block->target_end) { - size -= block->target_end - (s->begin + s->length); - } + QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { + memblock_start = dump_filtered_memblock_start(block, s->filter_area_begin, s->filter_area_length); + if (memblock_start == -1) { + continue; } - write_memory(s, block, s->start, size, errp); + + memblock_size = dump_filtered_memblock_size(block, s->filter_area_begin, s->filter_area_length); + + /* Write the memory to file */ + write_memory(s, block, memblock_start, memblock_size, errp); if (*errp) { return; } - - } while (!get_next_block(s, block)); + } } static void create_vmcore(DumpState *s, Error **errp) @@ -1094,55 +1116,81 @@ static uint64_t dump_pfn_to_paddr(DumpState *s, uint64_t pfn) } /* - * exam every page and return the page frame number and the address of the page. - * bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys - * blocks, so block->target_start and block->target_end should be interal - * multiples of the target page size. + * Return the page frame number and the page content in *bufptr. bufptr can be + * NULL. If not NULL, *bufptr must contains a target page size of pre-allocated + * memory. This is not necessarily the memory returned. */ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr, uint8_t **bufptr, DumpState *s) { GuestPhysBlock *block = *blockptr; - hwaddr addr, target_page_mask = ~((hwaddr)s->dump_info.page_size - 1); - uint8_t *buf; + uint32_t page_size = s->dump_info.page_size; + uint8_t *buf = NULL, *hbuf; + hwaddr addr; /* block == NULL means the start of the iteration */ if (!block) { block = QTAILQ_FIRST(&s->guest_phys_blocks.head); *blockptr = block; - assert((block->target_start & ~target_page_mask) == 0); - assert((block->target_end & ~target_page_mask) == 0); - *pfnptr = dump_paddr_to_pfn(s, block->target_start); - if (bufptr) { - *bufptr = block->host_addr; - } - return true; - } - - *pfnptr = *pfnptr + 1; - addr = dump_pfn_to_paddr(s, *pfnptr); - - if ((addr >= block->target_start) && - (addr + s->dump_info.page_size <= block->target_end)) { - buf = block->host_addr + (addr - block->target_start); + addr = block->target_start; + *pfnptr = dump_paddr_to_pfn(s, addr); } else { - /* the next page is in the next block */ - block = QTAILQ_NEXT(block, next); - *blockptr = block; - if (!block) { - return false; + *pfnptr += 1; + addr = dump_pfn_to_paddr(s, *pfnptr); + } + assert(block != NULL); + + while (1) { + if (addr >= block->target_start && addr < block->target_end) { + size_t n = MIN(block->target_end - addr, page_size - addr % page_size); + hbuf = block->host_addr + (addr - block->target_start); + if (!buf) { + if (n == page_size) { + /* this is a whole target page, go for it */ + assert(addr % page_size == 0); + buf = hbuf; + break; + } else if (bufptr) { + assert(*bufptr); + buf = *bufptr; + memset(buf, 0, page_size); + } else { + return true; + } + } + + memcpy(buf + addr % page_size, hbuf, n); + addr += n; + if (addr % page_size == 0) { + /* we filled up the page */ + break; + } + } else { + /* the next page is in the next block */ + *blockptr = block = QTAILQ_NEXT(block, next); + if (!block) { + break; + } + + addr = block->target_start; + /* are we still in the same page? */ + if (dump_paddr_to_pfn(s, addr) != *pfnptr) { + if (buf) { + /* no, but we already filled something earlier, return it */ + break; + } else { + /* else continue from there */ + *pfnptr = dump_paddr_to_pfn(s, addr); + } + } } - assert((block->target_start & ~target_page_mask) == 0); - assert((block->target_end & ~target_page_mask) == 0); - *pfnptr = dump_paddr_to_pfn(s, block->target_start); - buf = block->host_addr; } if (bufptr) { *bufptr = buf; } - return true; + return buf != NULL; } static void write_dump_bitmap(DumpState *s, Error **errp) @@ -1280,6 +1328,7 @@ static void write_dump_pages(DumpState *s, Error **errp) uint8_t *buf; GuestPhysBlock *block_iter = NULL; uint64_t pfn_iter; + g_autofree uint8_t *page = NULL; /* get offset of page_desc and page_data in dump file */ offset_desc = s->offset_page; @@ -1315,12 +1364,13 @@ static void write_dump_pages(DumpState *s, Error **errp) } offset_data += s->dump_info.page_size; + page = g_malloc(s->dump_info.page_size); /* * dump memory to vmcore page by page. zero page will all be resided in the * first page of page section */ - while (get_next_page(&block_iter, &pfn_iter, &buf, s)) { + for (buf = page; get_next_page(&block_iter, &pfn_iter, &buf, s); buf = page) { /* check zero page */ if (buffer_is_zero(buf, s->dump_info.page_size)) { ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor), @@ -1490,30 +1540,22 @@ static void create_kdump_vmcore(DumpState *s, Error **errp) } } -static ram_addr_t get_start_block(DumpState *s) +static int validate_start_block(DumpState *s) { GuestPhysBlock *block; - if (!s->has_filter) { - s->next_block = QTAILQ_FIRST(&s->guest_phys_blocks.head); + if (!dump_has_filter(s)) { return 0; } QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { - if (block->target_start >= s->begin + s->length || - block->target_end <= s->begin) { - /* This block is out of the range */ + /* This block is out of the range */ + if (block->target_start >= s->filter_area_begin + s->filter_area_length || + block->target_end <= s->filter_area_begin) { continue; } - - s->next_block = block; - if (s->begin > block->target_start) { - s->start = s->begin - block->target_start; - } else { - s->start = 0; - } - return s->start; - } + return 0; + } return -1; } @@ -1540,25 +1582,19 @@ bool qemu_system_dump_in_progress(void) return (qatomic_read(&state->status) == DUMP_STATUS_ACTIVE); } -/* calculate total size of memory to be dumped (taking filter into - * acoount.) */ +/* + * calculate total size of memory to be dumped (taking filter into + * account.) + */ static int64_t dump_calculate_size(DumpState *s) { GuestPhysBlock *block; - int64_t size = 0, total = 0, left = 0, right = 0; + int64_t total = 0; QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { - if (s->has_filter) { - /* calculate the overlapped region. */ - left = MAX(s->begin, block->target_start); - right = MIN(s->begin + s->length, block->target_end); - size = right - left; - size = size > 0 ? size : 0; - } else { - /* count the whole region in */ - size = (block->target_end - block->target_start); - } - total += size; + total += dump_filtered_memblock_size(block, + s->filter_area_begin, + s->filter_area_length); } return total; @@ -1641,9 +1677,12 @@ static void dump_init(DumpState *s, int fd, bool has_format, } s->fd = fd; - s->has_filter = has_filter; - s->begin = begin; - s->length = length; + if (has_filter && !length) { + error_setg(errp, QERR_INVALID_PARAMETER, "length"); + goto cleanup; + } + s->filter_area_begin = begin; + s->filter_area_length = length; memory_mapping_list_init(&s->list); @@ -1660,8 +1699,8 @@ static void dump_init(DumpState *s, int fd, bool has_format, goto cleanup; } - s->start = get_start_block(s); - if (s->start == -1) { + /* Is the filter filtering everything? */ + if (validate_start_block(s) == -1) { error_setg(errp, QERR_INVALID_PARAMETER, "begin"); goto cleanup; } @@ -1776,8 +1815,8 @@ static void dump_init(DumpState *s, int fd, bool has_format, return; } - if (s->has_filter) { - memory_mapping_filter(&s->list, s->begin, s->length); + if (dump_has_filter(s)) { + memory_mapping_filter(&s->list, s->filter_area_begin, s->filter_area_length); } /* diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index bbeadaa189..a9f268fcab 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -214,18 +214,35 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, p->frac_lo &= ~round_mask; } } else if (unlikely(exp >= exp_max)) { - flags |= float_flag_overflow | float_flag_inexact; - if (overflow_norm) { + flags |= float_flag_overflow; + if (s->rebias_overflow) { + exp -= fmt->exp_re_bias; + } else if (overflow_norm) { + flags |= float_flag_inexact; exp = exp_max - 1; frac_allones(p); p->frac_lo &= ~round_mask; } else { + flags |= float_flag_inexact; p->cls = float_class_inf; exp = exp_max; frac_clear(p); } } frac_shr(p, frac_shift); + } else if (unlikely(s->rebias_underflow)) { + flags |= float_flag_underflow; + exp += fmt->exp_re_bias; + if (p->frac_lo & round_mask) { + flags |= float_flag_inexact; + if (frac_addi(p, p, inc)) { + frac_shr(p, 1); + p->frac_hi |= DECOMPOSED_IMPLICIT_BIT; + exp++; + } + p->frac_lo &= ~round_mask; + } + frac_shr(p, frac_shift); } else if (s->flush_to_zero) { flags |= float_flag_output_denormal; p->cls = float_class_zero; diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 4a871ef2a1..c7454c3eb1 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -521,6 +521,7 @@ typedef struct { typedef struct { int exp_size; int exp_bias; + int exp_re_bias; int exp_max; int frac_size; int frac_shift; @@ -532,6 +533,7 @@ typedef struct { #define FLOAT_PARAMS_(E) \ .exp_size = E, \ .exp_bias = ((1 << E) - 1) >> 1, \ + .exp_re_bias = (1 << (E - 1)) + (1 << (E - 2)), \ .exp_max = (1 << E) - 1 #define FLOAT_PARAMS(E, F) \ diff --git a/gdb-xml/loongarch-base64.xml b/gdb-xml/loongarch-base64.xml index 4962bdbd28..2d8a1f6b73 100644 --- a/gdb-xml/loongarch-base64.xml +++ b/gdb-xml/loongarch-base64.xml @@ -1,5 +1,5 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb-xml/loongarch-fpu64.xml b/gdb-xml/loongarch-fpu64.xml deleted file mode 100644 index e52cf89fbc..0000000000 --- a/gdb-xml/loongarch-fpu64.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gdb-xml/riscv-32bit-cpu.xml b/gdb-xml/riscv-32bit-cpu.xml index 0d07aaec85..466f2c0648 100644 --- a/gdb-xml/riscv-32bit-cpu.xml +++ b/gdb-xml/riscv-32bit-cpu.xml @@ -5,13 +5,9 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. --> - - - + diff --git a/gdb-xml/riscv-32bit-fpu.xml b/gdb-xml/riscv-32bit-fpu.xml index 1eaae9119e..24aa087031 100644 --- a/gdb-xml/riscv-32bit-fpu.xml +++ b/gdb-xml/riscv-32bit-fpu.xml @@ -5,13 +5,9 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. --> - - - + @@ -43,8 +39,4 @@ - - - - diff --git a/gdb-xml/riscv-64bit-cpu.xml b/gdb-xml/riscv-64bit-cpu.xml index b8aa424ae4..c4d83de09b 100644 --- a/gdb-xml/riscv-64bit-cpu.xml +++ b/gdb-xml/riscv-64bit-cpu.xml @@ -5,13 +5,9 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. --> - - - + diff --git a/gdb-xml/riscv-64bit-fpu.xml b/gdb-xml/riscv-64bit-fpu.xml index 794854cc01..d0f17f9984 100644 --- a/gdb-xml/riscv-64bit-fpu.xml +++ b/gdb-xml/riscv-64bit-fpu.xml @@ -5,10 +5,6 @@ are permitted in any medium without royalty provided the copyright notice and this notice are preserved. --> - - @@ -17,7 +13,7 @@ - + @@ -49,8 +45,4 @@ - - - - diff --git a/gdbstub.c b/gdbstub/gdbstub.c similarity index 95% rename from gdbstub.c rename to gdbstub/gdbstub.c index 2f44f7b525..42f8717ca5 100644 --- a/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -29,7 +29,7 @@ #include "qemu/ctype.h" #include "qemu/cutils.h" #include "qemu/module.h" -#include "trace/trace-root.h" +#include "trace.h" #include "exec/gdbstub.h" #ifdef CONFIG_USER_ONLY #include "qemu.h" @@ -45,12 +45,14 @@ #include "qemu/sockets.h" #include "sysemu/hw_accel.h" -#include "sysemu/kvm.h" #include "sysemu/runstate.h" #include "semihosting/semihost.h" #include "exec/exec-all.h" +#include "exec/hwaddr.h" #include "sysemu/replay.h" +#include "internals.h" + #ifdef CONFIG_USER_ONLY #define GDB_ATTACHED "0" #else @@ -383,27 +385,13 @@ static void init_gdbserver_state(void) gdbserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4); /* - * In replay mode all events will come from the log and can't be - * suppressed otherwise we would break determinism. However as those - * events are tied to the number of executed instructions we won't see - * them occurring every time we single step. - */ - if (replay_mode != REPLAY_MODE_NONE) { - gdbserver_state.supported_sstep_flags = SSTEP_ENABLE; - } else if (kvm_enabled()) { - gdbserver_state.supported_sstep_flags = kvm_get_supported_sstep_flags(); - } else { - gdbserver_state.supported_sstep_flags = - SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; - } - - /* - * By default use no IRQs and no timers while single stepping so as to - * make single stepping like an ICE HW step. + * What single-step modes are supported is accelerator dependent. + * By default try to use no IRQs and no timers while single + * stepping so as to make single stepping like a typical ICE HW step. */ + gdbserver_state.supported_sstep_flags = accel_supported_gdbstub_sstep_flags(); gdbserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; gdbserver_state.sstep_flags &= gdbserver_state.supported_sstep_flags; - } #ifndef CONFIG_USER_ONLY @@ -1026,130 +1014,16 @@ void gdb_register_coprocessor(CPUState *cpu, } } -#ifndef CONFIG_USER_ONLY -/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */ -static inline int xlat_gdb_type(CPUState *cpu, int gdbtype) -{ - static const int xlat[] = { - [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, - [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ, - [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS, - }; - - CPUClass *cc = CPU_GET_CLASS(cpu); - int cputype = xlat[gdbtype]; - - if (cc->gdb_stop_before_watchpoint) { - cputype |= BP_STOP_BEFORE_ACCESS; - } - return cputype; -} -#endif - -static int gdb_breakpoint_insert(int type, target_ulong addr, target_ulong len) -{ - CPUState *cpu; - int err = 0; - - if (kvm_enabled()) { - return kvm_insert_breakpoint(gdbserver_state.c_cpu, addr, len, type); - } - - switch (type) { - case GDB_BREAKPOINT_SW: - case GDB_BREAKPOINT_HW: - CPU_FOREACH(cpu) { - err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL); - if (err) { - break; - } - } - return err; -#ifndef CONFIG_USER_ONLY - case GDB_WATCHPOINT_WRITE: - case GDB_WATCHPOINT_READ: - case GDB_WATCHPOINT_ACCESS: - CPU_FOREACH(cpu) { - err = cpu_watchpoint_insert(cpu, addr, len, - xlat_gdb_type(cpu, type), NULL); - if (err) { - break; - } - } - return err; -#endif - default: - return -ENOSYS; - } -} - -static int gdb_breakpoint_remove(int type, target_ulong addr, target_ulong len) -{ - CPUState *cpu; - int err = 0; - - if (kvm_enabled()) { - return kvm_remove_breakpoint(gdbserver_state.c_cpu, addr, len, type); - } - - switch (type) { - case GDB_BREAKPOINT_SW: - case GDB_BREAKPOINT_HW: - CPU_FOREACH(cpu) { - err = cpu_breakpoint_remove(cpu, addr, BP_GDB); - if (err) { - break; - } - } - return err; -#ifndef CONFIG_USER_ONLY - case GDB_WATCHPOINT_WRITE: - case GDB_WATCHPOINT_READ: - case GDB_WATCHPOINT_ACCESS: - CPU_FOREACH(cpu) { - err = cpu_watchpoint_remove(cpu, addr, len, - xlat_gdb_type(cpu, type)); - if (err) - break; - } - return err; -#endif - default: - return -ENOSYS; - } -} - -static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu) -{ - cpu_breakpoint_remove_all(cpu, BP_GDB); -#ifndef CONFIG_USER_ONLY - cpu_watchpoint_remove_all(cpu, BP_GDB); -#endif -} - static void gdb_process_breakpoint_remove_all(GDBProcess *p) { CPUState *cpu = get_first_cpu_in_process(p); while (cpu) { - gdb_cpu_breakpoint_remove_all(cpu); + gdb_breakpoint_remove_all(cpu); cpu = gdb_next_cpu_in_process(cpu); } } -static void gdb_breakpoint_remove_all(void) -{ - CPUState *cpu; - - if (kvm_enabled()) { - kvm_remove_all_breakpoints(gdbserver_state.c_cpu); - return; - } - - CPU_FOREACH(cpu) { - gdb_cpu_breakpoint_remove_all(cpu); - } -} static void gdb_set_cpu_pc(target_ulong pc) { @@ -1681,7 +1555,8 @@ static void handle_insert_bp(GArray *params, void *user_ctx) return; } - res = gdb_breakpoint_insert(get_param(params, 0)->val_ul, + res = gdb_breakpoint_insert(gdbserver_state.c_cpu, + get_param(params, 0)->val_ul, get_param(params, 1)->val_ull, get_param(params, 2)->val_ull); if (res >= 0) { @@ -1704,7 +1579,8 @@ static void handle_remove_bp(GArray *params, void *user_ctx) return; } - res = gdb_breakpoint_remove(get_param(params, 0)->val_ul, + res = gdb_breakpoint_remove(gdbserver_state.c_cpu, + get_param(params, 0)->val_ul, get_param(params, 1)->val_ull, get_param(params, 2)->val_ull); if (res >= 0) { @@ -2640,7 +2516,7 @@ static void handle_target_halt(GArray *params, void *user_ctx) * because gdb is doing an initial connect and the state * should be cleaned up. */ - gdb_breakpoint_remove_all(); + gdb_breakpoint_remove_all(gdbserver_state.c_cpu); } static int gdb_handle_packet(const char *line_buf) @@ -3655,8 +3531,8 @@ int gdbserver_start(const char *device) return -1; } - if (kvm_enabled() && !kvm_supports_guest_debug()) { - error_report("gdbstub: KVM doesn't support guest debugging"); + if (!gdb_supports_guest_debug()) { + error_report("gdbstub: current accelerator doesn't support guest debugging"); return -1; } diff --git a/gdbstub/internals.h b/gdbstub/internals.h new file mode 100644 index 0000000000..eabb0341d1 --- /dev/null +++ b/gdbstub/internals.h @@ -0,0 +1,17 @@ +/* + * gdbstub internals + * + * Copyright (c) 2022 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef _INTERNALS_H_ +#define _INTERNALS_H_ + +bool gdb_supports_guest_debug(void); +int gdb_breakpoint_insert(CPUState *cs, int type, hwaddr addr, hwaddr len); +int gdb_breakpoint_remove(CPUState *cs, int type, hwaddr addr, hwaddr len); +void gdb_breakpoint_remove_all(CPUState *cs); + +#endif /* _INTERNALS_H_ */ diff --git a/gdbstub/meson.build b/gdbstub/meson.build new file mode 100644 index 0000000000..fc895a2c39 --- /dev/null +++ b/gdbstub/meson.build @@ -0,0 +1,9 @@ +# +# The main gdbstub still relies on per-build definitions of various +# types. The bits pushed to softmmu/user.c try to use guest agnostic +# types such as hwaddr. +# + +specific_ss.add(files('gdbstub.c')) +softmmu_ss.add(files('softmmu.c')) +user_ss.add(files('user.c')) diff --git a/gdbstub/softmmu.c b/gdbstub/softmmu.c new file mode 100644 index 0000000000..f208c6cf15 --- /dev/null +++ b/gdbstub/softmmu.c @@ -0,0 +1,51 @@ +/* + * gdb server stub - softmmu specific bits + * + * Debug integration depends on support from the individual + * accelerators so most of this involves calling the ops helpers. + * + * Copyright (c) 2022 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/gdbstub.h" +#include "exec/hwaddr.h" +#include "sysemu/cpus.h" +#include "internals.h" + +bool gdb_supports_guest_debug(void) +{ + const AccelOpsClass *ops = cpus_get_accel(); + if (ops->supports_guest_debug) { + return ops->supports_guest_debug(); + } + return false; +} + +int gdb_breakpoint_insert(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + const AccelOpsClass *ops = cpus_get_accel(); + if (ops->insert_breakpoint) { + return ops->insert_breakpoint(cs, type, addr, len); + } + return -ENOSYS; +} + +int gdb_breakpoint_remove(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + const AccelOpsClass *ops = cpus_get_accel(); + if (ops->remove_breakpoint) { + return ops->remove_breakpoint(cs, type, addr, len); + } + return -ENOSYS; +} + +void gdb_breakpoint_remove_all(CPUState *cs) +{ + const AccelOpsClass *ops = cpus_get_accel(); + if (ops->remove_all_breakpoints) { + ops->remove_all_breakpoints(cs); + } +} diff --git a/gdbstub/trace-events b/gdbstub/trace-events new file mode 100644 index 0000000000..03f0c303bf --- /dev/null +++ b/gdbstub/trace-events @@ -0,0 +1,29 @@ +# See docs/devel/tracing.rst for syntax documentation. + +# gdbstub.c +gdbstub_op_start(const char *device) "Starting gdbstub using device %s" +gdbstub_op_exiting(uint8_t code) "notifying exit with code=0x%02x" +gdbstub_op_continue(void) "Continuing all CPUs" +gdbstub_op_continue_cpu(int cpu_index) "Continuing CPU %d" +gdbstub_op_stepping(int cpu_index) "Stepping CPU %d" +gdbstub_op_extra_info(const char *info) "Thread extra info: %s" +gdbstub_hit_watchpoint(const char *type, int cpu_gdb_index, uint64_t vaddr) "Watchpoint hit, type=\"%s\" cpu=%d, vaddr=0x%" PRIx64 "" +gdbstub_hit_internal_error(void) "RUN_STATE_INTERNAL_ERROR" +gdbstub_hit_break(void) "RUN_STATE_DEBUG" +gdbstub_hit_paused(void) "RUN_STATE_PAUSED" +gdbstub_hit_shutdown(void) "RUN_STATE_SHUTDOWN" +gdbstub_hit_io_error(void) "RUN_STATE_IO_ERROR" +gdbstub_hit_watchdog(void) "RUN_STATE_WATCHDOG" +gdbstub_hit_unknown(int state) "Unknown run state=0x%x" +gdbstub_io_reply(const char *message) "Sent: %s" +gdbstub_io_binaryreply(size_t ofs, const char *line) "0x%04zx: %s" +gdbstub_io_command(const char *command) "Received: %s" +gdbstub_io_got_ack(void) "Got ACK" +gdbstub_io_got_unexpected(uint8_t ch) "Got 0x%02x when expecting ACK/NACK" +gdbstub_err_got_nack(void) "Got NACK, retransmitting" +gdbstub_err_garbage(uint8_t ch) "received garbage between packets: 0x%02x" +gdbstub_err_overrun(void) "command buffer overrun, dropping command" +gdbstub_err_invalid_repeat(uint8_t ch) "got invalid RLE count: 0x%02x" +gdbstub_err_invalid_rle(void) "got invalid RLE sequence" +gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x%02x" +gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x" diff --git a/gdbstub/trace.h b/gdbstub/trace.h new file mode 100644 index 0000000000..dee87b1238 --- /dev/null +++ b/gdbstub/trace.h @@ -0,0 +1 @@ +#include "trace/trace-gdbstub.h" diff --git a/gdbstub/user.c b/gdbstub/user.c new file mode 100644 index 0000000000..033e5fdd71 --- /dev/null +++ b/gdbstub/user.c @@ -0,0 +1,68 @@ +/* + * gdbstub user-mode helper routines. + * + * We know for user-mode we are using TCG so we can call stuff directly. + * + * Copyright (c) 2022 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/hwaddr.h" +#include "exec/gdbstub.h" +#include "hw/core/cpu.h" +#include "internals.h" + +bool gdb_supports_guest_debug(void) +{ + /* user-mode == TCG == supported */ + return true; +} + +int gdb_breakpoint_insert(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + CPUState *cpu; + int err = 0; + + switch (type) { + case GDB_BREAKPOINT_SW: + case GDB_BREAKPOINT_HW: + CPU_FOREACH(cpu) { + err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL); + if (err) { + break; + } + } + return err; + default: + /* user-mode doesn't support watchpoints */ + return -ENOSYS; + } +} + +int gdb_breakpoint_remove(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + CPUState *cpu; + int err = 0; + + switch (type) { + case GDB_BREAKPOINT_SW: + case GDB_BREAKPOINT_HW: + CPU_FOREACH(cpu) { + err = cpu_breakpoint_remove(cpu, addr, BP_GDB); + if (err) { + break; + } + } + return err; + default: + /* user-mode doesn't support watchpoints */ + return -ENOSYS; + } +} + +void gdb_breakpoint_remove_all(CPUState *cs) +{ + cpu_breakpoint_remove_all(cs, BP_GDB); +} diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 188d9ece3b..754b1e8408 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -100,9 +100,11 @@ ERST { .name = "registers", - .args_type = "cpustate_all:-a", - .params = "[-a]", - .help = "show the cpu registers (-a: all - show register info for all cpus)", + .args_type = "cpustate_all:-a,vcpu:i?", + .params = "[-a|vcpu]", + .help = "show the cpu registers (-a: show register info for all cpus;" + " vcpu: specific vCPU to query; show the current CPU's registers if" + " no argument is specified)", .cmd = hmp_info_registers, }, @@ -921,3 +923,73 @@ SRST ``stats`` Show runtime-collected statistics ERST + + { + .name = "virtio", + .args_type = "", + .params = "", + .help = "List all available virtio devices", + .cmd = hmp_virtio_query, + .flags = "p", + }, + +SRST + ``info virtio`` + List all available virtio devices +ERST + + { + .name = "virtio-status", + .args_type = "path:s", + .params = "path", + .help = "Display status of a given virtio device", + .cmd = hmp_virtio_status, + .flags = "p", + }, + +SRST + ``info virtio-status`` *path* + Display status of a given virtio device +ERST + + { + .name = "virtio-queue-status", + .args_type = "path:s,queue:i", + .params = "path queue", + .help = "Display status of a given virtio queue", + .cmd = hmp_virtio_queue_status, + .flags = "p", + }, + +SRST + ``info virtio-queue-status`` *path* *queue* + Display status of a given virtio queue +ERST + + { + .name = "virtio-vhost-queue-status", + .args_type = "path:s,queue:i", + .params = "path queue", + .help = "Display status of a given vhost queue", + .cmd = hmp_vhost_queue_status, + .flags = "p", + }, + +SRST + ``info virtio-vhost-queue-status`` *path* *queue* + Display status of a given vhost queue +ERST + + { + .name = "virtio-queue-element", + .args_type = "path:s,queue:i,index:i?", + .params = "path queue [index]", + .help = "Display element of a given virtio queue", + .cmd = hmp_virtio_queue_element, + .flags = "p", + }, + +SRST + ``info virtio-queue-element`` *path* *queue* [*index*] + Display element of a given virtio queue +ERST diff --git a/hmp-commands.hx b/hmp-commands.hx index 182e639d14..8ab8000acd 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1742,23 +1742,6 @@ SRST *icount* for the reference may be observed with ``info replay`` command. ERST - { - .name = "info", - .args_type = "item:s?", - .params = "[subcommand]", - .help = "show various information about the system state", - .cmd = hmp_info_help, - .sub_table = hmp_info_cmds, - .flags = "p", - }, - -SRST -``calc_dirty_rate`` *second* - Start a round of dirty rate measurement with the period specified in *second*. - The result of the dirty rate measurement may be observed with ``info - dirty_rate`` command. -ERST - { .name = "calc_dirty_rate", .args_type = "dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?", @@ -1770,10 +1753,10 @@ ERST }, SRST -``set_vcpu_dirty_limit`` - Set dirty page rate limit on virtual CPU, the information about all the - virtual CPU dirty limit status can be observed with ``info vcpu_dirty_limit`` - command. +``calc_dirty_rate`` *second* + Start a round of dirty rate measurement with the period specified in *second*. + The result of the dirty rate measurement may be observed with ``info + dirty_rate`` command. ERST { @@ -1786,8 +1769,8 @@ ERST }, SRST -``cancel_vcpu_dirty_limit`` - Cancel dirty page rate limit on virtual CPU, the information about all the +``set_vcpu_dirty_limit`` + Set dirty page rate limit on virtual CPU, the information about all the virtual CPU dirty limit status can be observed with ``info vcpu_dirty_limit`` command. ERST @@ -1800,3 +1783,20 @@ ERST "\n\t\t\t\t\t limit on a specified virtual cpu", .cmd = hmp_cancel_vcpu_dirty_limit, }, + +SRST +``cancel_vcpu_dirty_limit`` + Cancel dirty page rate limit on virtual CPU, the information about all the + virtual CPU dirty limit status can be observed with ``info vcpu_dirty_limit`` + command. +ERST + + { + .name = "info", + .args_type = "item:s?", + .params = "[subcommand]", + .help = "show various information about the system state", + .cmd = hmp_info_help, + .sub_table = hmp_info_cmds, + .flags = "p", + }, diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 994f952600..a523ac34a9 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -424,21 +424,24 @@ typedef struct V9fsGetlock extern int open_fd_hw; extern int total_open_fd; -static inline void v9fs_path_write_lock(V9fsState *s) +static inline void coroutine_fn +v9fs_path_write_lock(V9fsState *s) { if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_wrlock(&s->rename_lock); } } -static inline void v9fs_path_read_lock(V9fsState *s) +static inline void coroutine_fn +v9fs_path_read_lock(V9fsState *s) { if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_rdlock(&s->rename_lock); } } -static inline void v9fs_path_unlock(V9fsState *s) +static inline void coroutine_fn +v9fs_path_unlock(V9fsState *s) { if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_unlock(&s->rename_lock); diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index e28457a7d1..a3d31631fe 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -267,6 +267,13 @@ static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev, } } +static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) +{ + AcpiGedState *s = ACPI_GED(adev); + + acpi_memory_ospm_status(&s->memhp_state, list); +} + static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) { AcpiGedState *s = ACPI_GED(adev); @@ -409,6 +416,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) hc->unplug_request = acpi_ged_unplug_request_cb; hc->unplug = acpi_ged_unplug_cb; + adevc->ospm_status = acpi_ged_ospm_status; adevc->send_event = acpi_ged_send_event; } diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index 5f85b16327..31e46df0bd 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -35,6 +35,7 @@ #include "hw/nvram/fw_cfg.h" #include "hw/mem/nvdimm.h" #include "qemu/nvdimm-utils.h" +#include "trace.h" /* * define Byte Addressable Persistent Memory (PM) Region according to @@ -550,8 +551,8 @@ static void nvdimm_dsm_func_read_fit(NVDIMMState *state, NvdimmDsmIn *in, fit = fit_buf->fit; - nvdimm_debug("Read FIT: offset 0x%x FIT size 0x%x Dirty %s.\n", - read_fit->offset, fit->len, fit_buf->dirty ? "Yes" : "No"); + trace_acpi_nvdimm_read_fit(read_fit->offset, fit->len, + fit_buf->dirty ? "Yes" : "No"); if (read_fit->offset > fit->len) { func_ret_status = NVDIMM_DSM_RET_STATUS_INVALID; @@ -658,7 +659,7 @@ static void nvdimm_dsm_label_size(NVDIMMDevice *nvdimm, hwaddr dsm_mem_addr) label_size = nvdimm->label_size; mxfer = nvdimm_get_max_xfer_label_size(); - nvdimm_debug("label_size 0x%x, max_xfer 0x%x.\n", label_size, mxfer); + trace_acpi_nvdimm_label_info(label_size, mxfer); label_size_out.func_ret_status = cpu_to_le32(NVDIMM_DSM_RET_STATUS_SUCCESS); label_size_out.label_size = cpu_to_le32(label_size); @@ -674,20 +675,18 @@ static uint32_t nvdimm_rw_label_data_check(NVDIMMDevice *nvdimm, uint32_t ret = NVDIMM_DSM_RET_STATUS_INVALID; if (offset + length < offset) { - nvdimm_debug("offset 0x%x + length 0x%x is overflow.\n", offset, - length); + trace_acpi_nvdimm_label_overflow(offset, length); return ret; } if (nvdimm->label_size < offset + length) { - nvdimm_debug("position 0x%x is beyond label data (len = %" PRIx64 ").\n", - offset + length, nvdimm->label_size); + trace_acpi_nvdimm_label_oversize(offset + length, nvdimm->label_size); return ret; } if (length > nvdimm_get_max_xfer_label_size()) { - nvdimm_debug("length (0x%x) is larger than max_xfer (0x%x).\n", - length, nvdimm_get_max_xfer_label_size()); + trace_acpi_nvdimm_label_xfer_exceed(length, + nvdimm_get_max_xfer_label_size()); return ret; } @@ -710,8 +709,8 @@ static void nvdimm_dsm_get_label_data(NVDIMMDevice *nvdimm, NvdimmDsmIn *in, get_label_data->offset = le32_to_cpu(get_label_data->offset); get_label_data->length = le32_to_cpu(get_label_data->length); - nvdimm_debug("Read Label Data: offset 0x%x length 0x%x.\n", - get_label_data->offset, get_label_data->length); + trace_acpi_nvdimm_read_label(get_label_data->offset, + get_label_data->length); status = nvdimm_rw_label_data_check(nvdimm, get_label_data->offset, get_label_data->length); @@ -749,8 +748,8 @@ static void nvdimm_dsm_set_label_data(NVDIMMDevice *nvdimm, NvdimmDsmIn *in, set_label_data->offset = le32_to_cpu(set_label_data->offset); set_label_data->length = le32_to_cpu(set_label_data->length); - nvdimm_debug("Write Label Data: offset 0x%x length 0x%x.\n", - set_label_data->offset, set_label_data->length); + trace_acpi_nvdimm_write_label(set_label_data->offset, + set_label_data->length); status = nvdimm_rw_label_data_check(nvdimm, set_label_data->offset, set_label_data->length); @@ -821,7 +820,7 @@ static void nvdimm_dsm_device(NvdimmDsmIn *in, hwaddr dsm_mem_addr) static uint64_t nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size) { - nvdimm_debug("BUG: we never read _DSM IO Port.\n"); + trace_acpi_nvdimm_read_io_port(); return 0; } @@ -832,7 +831,7 @@ nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) NvdimmDsmIn *in; hwaddr dsm_mem_addr = val; - nvdimm_debug("dsm memory address 0x%" HWADDR_PRIx ".\n", dsm_mem_addr); + trace_acpi_nvdimm_dsm_mem_addr(dsm_mem_addr); /* * The DSM memory is mapped to guest address space so an evil guest @@ -846,12 +845,10 @@ nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) in->function = le32_to_cpu(in->function); in->handle = le32_to_cpu(in->handle); - nvdimm_debug("Revision 0x%x Handler 0x%x Function 0x%x.\n", in->revision, - in->handle, in->function); + trace_acpi_nvdimm_dsm_info(in->revision, in->handle, in->function); if (in->revision != 0x1 /* Currently we only support DSM Spec Rev1. */) { - nvdimm_debug("Revision 0x%x is not supported, expect 0x%x.\n", - in->revision, 0x1); + trace_acpi_nvdimm_invalid_revision(in->revision); nvdimm_dsm_no_payload(NVDIMM_DSM_RET_STATUS_UNSUPPORT, dsm_mem_addr); goto exit; } diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events index 2250126a22..eb60b04f9b 100644 --- a/hw/acpi/trace-events +++ b/hw/acpi/trace-events @@ -70,3 +70,16 @@ acpi_erst_reset_out(unsigned record_count) "record_count %u" acpi_erst_post_load(void *header, unsigned slot_size) "header: 0x%p slot_size %u" acpi_erst_class_init_in(void) acpi_erst_class_init_out(void) + +# nvdimm.c +acpi_nvdimm_read_fit(uint32_t offset, uint32_t len, const char *dirty) "Read FIT: offset 0x%" PRIx32 " FIT size 0x%" PRIx32 " Dirty %s" +acpi_nvdimm_label_info(uint32_t label_size, uint32_t mxfer) "label_size 0x%" PRIx32 ", max_xfer 0x%" PRIx32 +acpi_nvdimm_label_overflow(uint32_t offset, uint32_t length) "offset 0x%" PRIx32 " + length 0x%" PRIx32 " is overflow" +acpi_nvdimm_label_oversize(uint32_t pos, uint64_t size) "position 0x%" PRIx32 " is beyond label data (len = %" PRIu64 ")" +acpi_nvdimm_label_xfer_exceed(uint32_t length, uint32_t max_xfer) "length (0x%" PRIx32 ") is larger than max_xfer (0x%" PRIx32 ")" +acpi_nvdimm_read_label(uint32_t offset, uint32_t length) "Read Label Data: offset 0x%" PRIx32 " length 0x%" PRIx32 +acpi_nvdimm_write_label(uint32_t offset, uint32_t length) "Write Label Data: offset 0x%" PRIx32 " length 0x%" PRIx32 +acpi_nvdimm_read_io_port(void) "Alert: we never read _DSM IO Port" +acpi_nvdimm_dsm_mem_addr(uint64_t dsm_mem_addr) "dsm memory address 0x%" PRIx64 +acpi_nvdimm_dsm_info(uint32_t revision, uint32_t handle, uint32_t function) "Revision 0x%" PRIx32 " Handle 0x%" PRIx32 " Function 0x%" PRIx32 +acpi_nvdimm_invalid_revision(uint32_t revision) "Revision 0x%" PRIx32 " is not supported, expect 0x1" diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 990861ee5e..50a9507c0b 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -568,21 +568,15 @@ static void armv7m_reset(void *opaque) cpu_reset(CPU(cpu)); } -void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size) +void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, + hwaddr mem_base, int mem_size) { ssize_t image_size; uint64_t entry; - int big_endian; AddressSpace *as; int asidx; CPUState *cs = CPU(cpu); -#if TARGET_BIG_ENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif - if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) { asidx = ARMASIdx_S; } else { @@ -593,9 +587,9 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size) if (kernel_filename) { image_size = load_elf_as(kernel_filename, NULL, NULL, NULL, &entry, NULL, NULL, - NULL, big_endian, EM_ARM, 1, 0, as); + NULL, 0, EM_ARM, 1, 0, as); if (image_size < 0) { - image_size = load_image_targphys_as(kernel_filename, 0, + image_size = load_image_targphys_as(kernel_filename, mem_base, mem_size, as); } if (image_size < 0) { diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 4193a3d23d..bc3ecdb619 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -38,8 +38,6 @@ struct AspeedMachineState { /* Public */ AspeedSoCState soc; - MemoryRegion ram_container; - MemoryRegion max_ram; bool mmio_exec; char *fmc_model; char *spi_model; @@ -1432,6 +1430,7 @@ static void aspeed_minibmc_machine_init(MachineState *machine) armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, + 0, AST1030_INTERNAL_FLASH_SIZE); } diff --git a/hw/arm/boot.c b/hw/arm/boot.c index ada2717f76..ee3858b673 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -763,6 +763,10 @@ static void do_cpu_reset(void *opaque) if (cpu_isar_feature(aa64_sve, cpu)) { env->cp15.cptr_el[3] |= R_CPTR_EL3_EZ_MASK; } + if (cpu_isar_feature(aa64_sme, cpu)) { + env->cp15.cptr_el[3] |= R_CPTR_EL3_ESM_MASK; + env->cp15.scr_el3 |= SCR_ENTP2; + } /* AArch64 kernels never boot in secure mode */ assert(!info->secure_boot); /* This hook is only supported for AArch32 currently: diff --git a/hw/arm/fby35.c b/hw/arm/fby35.c index 79605f3064..90c04bbc33 100644 --- a/hw/arm/fby35.c +++ b/hw/arm/fby35.c @@ -72,11 +72,13 @@ static void fby35_bmc_init(Fby35State *s) { DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); - memory_region_init(&s->bmc_memory, OBJECT(s), "bmc-memory", UINT64_MAX); - memory_region_init_ram(&s->bmc_dram, OBJECT(s), "bmc-dram", + object_initialize_child(OBJECT(s), "bmc", &s->bmc, "ast2600-a3"); + + memory_region_init(&s->bmc_memory, OBJECT(&s->bmc), "bmc-memory", + UINT64_MAX); + memory_region_init_ram(&s->bmc_dram, OBJECT(&s->bmc), "bmc-dram", FBY35_BMC_RAM_SIZE, &error_abort); - object_initialize_child(OBJECT(s), "bmc", &s->bmc, "ast2600-a3"); object_property_set_int(OBJECT(&s->bmc), "ram-size", FBY35_BMC_RAM_SIZE, &error_abort); object_property_set_link(OBJECT(&s->bmc), "memory", OBJECT(&s->bmc_memory), @@ -120,9 +122,11 @@ static void fby35_bic_init(Fby35State *s) s->bic_sysclk = clock_new(OBJECT(s), "SYSCLK"); clock_set_hz(s->bic_sysclk, 200000000ULL); - memory_region_init(&s->bic_memory, OBJECT(s), "bic-memory", UINT64_MAX); - object_initialize_child(OBJECT(s), "bic", &s->bic, "ast1030-a1"); + + memory_region_init(&s->bic_memory, OBJECT(&s->bic), "bic-memory", + UINT64_MAX); + qdev_connect_clock_in(DEVICE(&s->bic), "sysclk", s->bic_sysclk); object_property_set_link(OBJECT(&s->bic), "memory", OBJECT(&s->bic_memory), &error_abort); diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c index e9494334ce..50df362088 100644 --- a/hw/arm/microbit.c +++ b/hw/arm/microbit.c @@ -57,7 +57,7 @@ static void microbit_init(MachineState *machine) mr, -1); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - s->nrf51.flash_size); + 0, s->nrf51.flash_size); } static void microbit_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 4017392bf5..394192b9b2 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -1197,7 +1197,7 @@ static void mps2tz_common_init(MachineState *machine) } armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - boot_ram_size(mms)); + 0, boot_ram_size(mms)); } static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address, diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index bb76fa6889..a86a994dba 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -450,7 +450,7 @@ static void mps2_common_init(MachineState *machine) mmc->fpga_type == FPGA_AN511 ? 47 : 13)); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - 0x400000); + 0, 0x400000); } static void mps2_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index d9f881690e..a6df473ec9 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -98,7 +98,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) sysbus_connect_irq(SYS_BUS_DEVICE(&soc->spi[0]), 1, cs_line); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - soc->envm_size); + 0, soc->envm_size); } static void emcraft_sf2_machine_init(MachineClass *mc) diff --git a/hw/arm/musca.c b/hw/arm/musca.c index 7a83f7dda7..6eeee57c9d 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -597,7 +597,8 @@ static void musca_init(MachineState *machine) "cfg_sec_resp", 0)); } - armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x2000000); + armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, + 0, 0x2000000); } static void musca_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c index 3365da11bf..83753d53a3 100644 --- a/hw/arm/netduino2.c +++ b/hw/arm/netduino2.c @@ -49,7 +49,7 @@ static void netduino2_init(MachineState *machine) sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - FLASH_SIZE); + 0, FLASH_SIZE); } static void netduino2_machine_init(MachineClass *mc) diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c index 76cea8e489..515c081605 100644 --- a/hw/arm/netduinoplus2.c +++ b/hw/arm/netduinoplus2.c @@ -50,7 +50,7 @@ static void netduinoplus2_init(MachineState *machine) armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - FLASH_SIZE); + 0, FLASH_SIZE); } static void netduinoplus2_machine_init(MachineClass *mc) diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index 02b1aa8c97..8571eedd73 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -274,7 +274,7 @@ static void omap_eac_format_update(struct omap_eac_s *s) fmt.freq = s->codec.rate; /* TODO: signedness possibly depends on the CODEC hardware - or * does I2S specify it? */ - /* All register writes are 16 bits so we we store 16-bit samples + /* All register writes are 16 bits so we store 16-bit samples * in the buffers regardless of AGCFR[B8_16] value. */ fmt.fmt = AUDIO_FORMAT_U16; diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 12c673c917..a9e96c37f8 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1302,7 +1302,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) create_unimplemented_device("hibernation", 0x400fc000, 0x1000); create_unimplemented_device("flash-control", 0x400fd000, 0x1000); - armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, flash_size); + armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, 0, flash_size); } /* FIXME: Figure out how to generate these from stellaris_boards. */ diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c index 04036da3ee..67675e952f 100644 --- a/hw/arm/stm32vldiscovery.c +++ b/hw/arm/stm32vldiscovery.c @@ -53,7 +53,7 @@ static void stm32vldiscovery_init(MachineState *machine) armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - FLASH_SIZE); + 0, FLASH_SIZE); } static void stm32vldiscovery_machine_init(MachineClass *mc) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 449fab0080..13c6e3e468 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -592,8 +592,7 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) acpi_table_begin(&table, table_data); /* CntControlBase Physical Address */ - /* FIXME: invalid value, should be 0xFFFFFFFFFFFFFFFF if not impl. ? */ - build_append_int_noprefix(table_data, 0, 8); + build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8); build_append_int_noprefix(table_data, 0, 4); /* Reserved */ /* * FIXME: clarify comment: @@ -618,7 +617,7 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) /* Non-Secure EL2 timer Flags */ build_append_int_noprefix(table_data, irqflags, 4); /* CntReadBase Physical address */ - build_append_int_noprefix(table_data, 0, 8); + build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8); /* Platform Timer Count */ build_append_int_noprefix(table_data, 0, 4); /* Platform Timer Offset */ @@ -732,7 +731,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) uint32_t pmu_interrupt = arm_feature(&armcpu->env, ARM_FEATURE_PMU) ? PPI(VIRTUAL_PMU_IRQ) : 0; - if (vms->gic_version == 2) { + if (vms->gic_version == VIRT_GIC_VERSION_2) { physical_base_address = memmap[VIRT_GIC_CPU].base; gicv = memmap[VIRT_GIC_VCPU].base; gich = memmap[VIRT_GIC_HYP].base; @@ -762,7 +761,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_append_int_noprefix(table_data, armcpu->mp_affinity, 8); } - if (vms->gic_version == 3) { + if (vms->gic_version != VIRT_GIC_VERSION_2) { build_append_gicr(table_data, memmap[VIRT_GIC_REDIST].base, memmap[VIRT_GIC_REDIST].size); if (virt_gicv3_redist_region_count(vms) == 2) { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9633f822f3..cda9defe8f 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -199,6 +199,7 @@ static const int a15irqmap[] = { static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a7"), ARM_CPU_TYPE_NAME("cortex-a15"), + ARM_CPU_TYPE_NAME("cortex-a35"), ARM_CPU_TYPE_NAME("cortex-a53"), ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), @@ -252,6 +253,7 @@ static void create_fdt(VirtMachineState *vms) qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,dummy-virt"); qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2); + qemu_fdt_setprop_string(fdt, "/", "model", "linux,dummy-virt"); /* /chosen must exist for load_dtb to fill in necessary properties later */ qemu_fdt_add_subnode(fdt, "/chosen"); @@ -486,6 +488,7 @@ static void fdt_add_its_gic_node(VirtMachineState *vms) qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "arm,gic-v3-its"); qemu_fdt_setprop(ms->fdt, nodename, "msi-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#msi-cells", 1); qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, vms->memmap[VIRT_GIC_ITS].base, 2, vms->memmap[VIRT_GIC_ITS].size); @@ -1358,8 +1361,6 @@ static void create_smmu(const VirtMachineState *vms, qemu_fdt_setprop(ms->fdt, node, "interrupt-names", irq_names, sizeof(irq_names)); - qemu_fdt_setprop_cell(ms->fdt, node, "clocks", vms->clock_phandle); - qemu_fdt_setprop_string(ms->fdt, node, "clock-names", "apb_pclk"); qemu_fdt_setprop(ms->fdt, node, "dma-coherent", NULL, 0); qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1); @@ -1487,8 +1488,8 @@ static void create_pcie(VirtMachineState *vms) qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); if (vms->msi_phandle) { - qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-parent", - vms->msi_phandle); + qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map", + 0, vms->msi_phandle, 0, 0x10000); } qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", @@ -3094,10 +3095,17 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_machine_7_1_options(MachineClass *mc) +static void virt_machine_7_2_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(7, 1) +DEFINE_VIRT_MACHINE_AS_LATEST(7, 2) + +static void virt_machine_7_1_options(MachineClass *mc) +{ + virt_machine_7_2_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len); +} +DEFINE_VIRT_MACHINE(7, 1) static void virt_machine_7_0_options(MachineClass *mc) { diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 383e177a00..335cfc417d 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -143,6 +143,14 @@ static const int adma_ch_intr[XLNX_ZYNQMP_NUM_ADMA_CH] = { 77, 78, 79, 80, 81, 82, 83, 84 }; +static const uint64_t usb_addr[XLNX_ZYNQMP_NUM_USB] = { + 0xFE200000, 0xFE300000 +}; + +static const int usb_intr[XLNX_ZYNQMP_NUM_USB] = { + 65, 70 +}; + typedef struct XlnxZynqMPGICRegion { int region_index; uint32_t address; @@ -428,6 +436,10 @@ static void xlnx_zynqmp_init(Object *obj) object_initialize_child(obj, "qspi-dma", &s->qspi_dma, TYPE_XLNX_CSU_DMA); object_initialize_child(obj, "qspi-irq-orgate", &s->qspi_irq_orgate, TYPE_OR_IRQ); + + for (i = 0; i < XLNX_ZYNQMP_NUM_USB; i++) { + object_initialize_child(obj, "usb[*]", &s->usb[i], TYPE_USB_DWC3); + } } static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) @@ -814,6 +826,30 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) object_property_add_alias(OBJECT(s), bus_name, OBJECT(&s->qspi), target_bus); } + + for (i = 0; i < XLNX_ZYNQMP_NUM_USB; i++) { + if (!object_property_set_link(OBJECT(&s->usb[i].sysbus_xhci), "dma", + OBJECT(system_memory), errp)) { + return; + } + + qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "intrs", 4); + qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "slots", 2); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 0, + gic_spi[usb_intr[i]]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 1, + gic_spi[usb_intr[i] + 1]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 2, + gic_spi[usb_intr[i] + 2]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 3, + gic_spi[usb_intr[i] + 3]); + } } static Property xlnx_zynqmp_props[] = { diff --git a/hw/block/block.c b/hw/block/block.c index 04279166ee..f9c4fe6767 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -205,6 +205,8 @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, blk_set_enable_write_cache(blk, wce); blk_set_on_error(blk, rerror, werror); + block_acct_setup(blk_get_stats(blk), conf->account_invalid, + conf->account_failed); return true; } diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 49276e46f2..26f965cabc 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -219,6 +219,11 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) memory_region_transaction_commit(); + /* + * These fields are visible to the IOThread so we rely on implicit barriers + * in aio_context_acquire() on the write side and aio_notify_accept() on + * the read side. + */ s->starting = false; vblk->dataplane_started = true; trace_virtio_blk_data_plane_start(s); diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c index 112094358e..dae13ab14d 100644 --- a/hw/block/hd-geometry.c +++ b/hw/block/hd-geometry.c @@ -150,7 +150,12 @@ void hd_geometry_guess(BlockBackend *blk, translation = BIOS_ATA_TRANSLATION_NONE; } if (ptrans) { - *ptrans = translation; + if (*ptrans == BIOS_ATA_TRANSLATION_AUTO) { + *ptrans = translation; + } else { + /* Defer to the translation specified by the user. */ + translation = *ptrans; + } } trace_hd_geometry_guess(blk, *pcyls, *pheads, *psecs, translation); } diff --git a/hw/block/meson.build b/hw/block/meson.build index 2389326112..1908abd45c 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -16,7 +16,7 @@ softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c')) softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c')) softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c')) -specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c')) -specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c')) +specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c')) +specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c')) subdir('dataplane') diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 9117222456..84902dde17 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -23,6 +23,7 @@ #include "hw/qdev-core.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" +#include "hw/virtio/virtio-blk-common.h" #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user-blk.h" #include "hw/virtio/virtio.h" @@ -63,7 +64,7 @@ static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config) /* Our num_queues overrides the device backend */ virtio_stw_p(vdev, &s->blkcfg.num_queues, s->num_queues); - memcpy(config, &s->blkcfg, sizeof(struct virtio_blk_config)); + memcpy(config, &s->blkcfg, vdev->config_len); } static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config) @@ -92,12 +93,12 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) { int ret; struct virtio_blk_config blkcfg; + VirtIODevice *vdev = dev->vdev; VHostUserBlk *s = VHOST_USER_BLK(dev->vdev); Error *local_err = NULL; ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg, - sizeof(struct virtio_blk_config), - &local_err); + vdev->config_len, &local_err); if (ret < 0) { error_report_err(local_err); return ret; @@ -106,7 +107,7 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) /* valid for resize only */ if (blkcfg.capacity != s->blkcfg.capacity) { s->blkcfg.capacity = blkcfg.capacity; - memcpy(dev->vdev->config, &s->blkcfg, sizeof(struct virtio_blk_config)); + memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len); virtio_notify_config(dev->vdev); } @@ -229,7 +230,7 @@ static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) return; } - if (s->dev.started == should_start) { + if (vhost_dev_is_started(&s->dev) == should_start) { return; } @@ -259,12 +260,7 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev, virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); virtio_add_feature(&features, VIRTIO_BLK_F_FLUSH); virtio_add_feature(&features, VIRTIO_BLK_F_RO); - virtio_add_feature(&features, VIRTIO_BLK_F_DISCARD); - virtio_add_feature(&features, VIRTIO_BLK_F_WRITE_ZEROES); - if (s->config_wce) { - virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE); - } if (s->num_queues > 1) { virtio_add_feature(&features, VIRTIO_BLK_F_MQ); } @@ -286,7 +282,7 @@ static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) return; } - if (s->dev.started) { + if (vhost_dev_is_started(&s->dev)) { return; } @@ -415,6 +411,12 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) * the vhost migration code. If disconnect was caught there is an * option for the general vhost code to get the dev state without * knowing its type (in this case vhost-user). + * + * FIXME: this is sketchy to be reaching into vhost_dev + * now because we are forcing something that implies we + * have executed vhost_dev_stop() but that won't happen + * until vhost_user_blk_stop() gets called from the bh. + * Really this state check should be tracked locally. */ s->dev.started = false; } @@ -447,7 +449,7 @@ static int vhost_user_blk_realize_connect(VHostUserBlk *s, Error **errp) assert(s->connected); ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, - sizeof(struct virtio_blk_config), errp); + s->parent_obj.config_len, errp); if (ret < 0) { qemu_chr_fe_disconnect(&s->chardev); vhost_dev_cleanup(&s->dev); @@ -462,6 +464,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) ERRP_GUARD(); VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(vdev); + size_t config_size; int retries; int i, ret; @@ -492,8 +495,9 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) return; } - virtio_init(vdev, VIRTIO_ID_BLOCK, - sizeof(struct virtio_blk_config)); + config_size = virtio_get_config_size(&virtio_blk_cfg_size_params, + vdev->host_features); + virtio_init(vdev, VIRTIO_ID_BLOCK, config_size); s->virtqs = g_new(VirtQueue *, s->num_queues); for (i = 0; i < s->num_queues; i++) { @@ -591,7 +595,12 @@ static Property vhost_user_blk_properties[] = { DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues, VHOST_USER_BLK_AUTO_NUM_QUEUES), DEFINE_PROP_UINT32("queue-size", VHostUserBlk, queue_size, 128), - DEFINE_PROP_BIT("config-wce", VHostUserBlk, config_wce, 0, true), + DEFINE_PROP_BIT64("config-wce", VHostUserBlk, parent_obj.host_features, + VIRTIO_BLK_F_CONFIG_WCE, true), + DEFINE_PROP_BIT64("discard", VHostUserBlk, parent_obj.host_features, + VIRTIO_BLK_F_DISCARD, true), + DEFINE_PROP_BIT64("write-zeroes", VHostUserBlk, parent_obj.host_features, + VIRTIO_BLK_F_WRITE_ZEROES, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/virtio-blk-common.c b/hw/block/virtio-blk-common.c new file mode 100644 index 0000000000..ac52d7c176 --- /dev/null +++ b/hw/block/virtio-blk-common.c @@ -0,0 +1,39 @@ +/* + * Virtio Block Device common helpers + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "standard-headers/linux/virtio_blk.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-blk-common.h" + +/* Config size before the discard support (hide associated config fields) */ +#define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \ + max_discard_sectors) + +/* + * Starting from the discard feature, we can use this array to properly + * set the config size depending on the features enabled. + */ +static const VirtIOFeature feature_sizes[] = { + {.flags = 1ULL << VIRTIO_BLK_F_DISCARD, + .end = endof(struct virtio_blk_config, discard_sector_alignment)}, + {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES, + .end = endof(struct virtio_blk_config, write_zeroes_may_unmap)}, + {} +}; + +const VirtIOConfigSizeParams virtio_blk_cfg_size_params = { + .min_size = VIRTIO_BLK_CFG_SIZE, + .max_size = sizeof(struct virtio_blk_config), + .feature_sizes = feature_sizes +}; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index e9ba752f6b..8131ec2dbc 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -32,31 +32,9 @@ #include "hw/virtio/virtio-bus.h" #include "migration/qemu-file-types.h" #include "hw/virtio/virtio-access.h" +#include "hw/virtio/virtio-blk-common.h" #include "qemu/coroutine.h" -/* Config size before the discard support (hide associated config fields) */ -#define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \ - max_discard_sectors) -/* - * Starting from the discard feature, we can use this array to properly - * set the config size depending on the features enabled. - */ -static const VirtIOFeature feature_sizes[] = { - {.flags = 1ULL << VIRTIO_BLK_F_DISCARD, - .end = endof(struct virtio_blk_config, discard_sector_alignment)}, - {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES, - .end = endof(struct virtio_blk_config, write_zeroes_may_unmap)}, - {} -}; - -static void virtio_blk_set_config_size(VirtIOBlock *s, uint64_t host_features) -{ - s->config_size = MAX(VIRTIO_BLK_CFG_SIZE, - virtio_feature_get_config_size(feature_sizes, host_features)); - - assert(s->config_size <= sizeof(struct virtio_blk_config)); -} - static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, VirtIOBlockReq *req) { @@ -1204,8 +1182,8 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) return; } - virtio_blk_set_config_size(s, s->host_features); - + s->config_size = virtio_get_config_size(&virtio_blk_cfg_size_params, + s->host_features); virtio_init(vdev, VIRTIO_ID_BLOCK, s->config_size); s->blk = conf->conf.blk; diff --git a/hw/char/serial.c b/hw/char/serial.c index 7061aacbce..41b5e61977 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -961,6 +961,9 @@ void serial_set_frequency(SerialState *s, uint32_t frequency) const MemoryRegionOps serial_io_ops = { .read = serial_ioport_read, .write = serial_ioport_write, + .valid = { + .unaligned = 1, + }, .impl = { .min_access_size = 1, .max_access_size = 1, diff --git a/hw/core/clock.c b/hw/core/clock.c index 916875e07a..d82e44cd1a 100644 --- a/hw/core/clock.c +++ b/hw/core/clock.c @@ -68,7 +68,7 @@ static uint64_t clock_get_child_period(Clock *clk) { /* * Return the period to be used for child clocks, which is the parent - * clock period adjusted for for multiplier and divider effects. + * clock period adjusted for multiplier and divider effects. */ return muldiv64(clk->period, clk->multiplier, clk->divider); } diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 9e3241b430..f9fdd46b9d 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -137,8 +137,7 @@ static void cpu_common_reset(DeviceState *dev) cpu->cflags_next_tb = -1; if (tcg_enabled()) { - cpu_tb_jmp_cache_clear(cpu); - + tcg_flush_jmp_cache(cpu); tcg_flush_softmmu_tlb(cpu); } } diff --git a/hw/core/cpu-sysemu.c b/hw/core/cpu-sysemu.c index 00253f8929..5eaf2e79e6 100644 --- a/hw/core/cpu-sysemu.c +++ b/hw/core/cpu-sysemu.c @@ -69,11 +69,10 @@ hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr) int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs) { - CPUClass *cc = CPU_GET_CLASS(cpu); int ret = 0; - if (cc->sysemu_ops->asidx_from_attrs) { - ret = cc->sysemu_ops->asidx_from_attrs(cpu, attrs); + if (cpu->cc->sysemu_ops->asidx_from_attrs) { + ret = cpu->cc->sysemu_ops->asidx_from_attrs(cpu, attrs); assert(ret < cpu->num_ases && ret >= 0); } return ret; diff --git a/hw/core/machine.c b/hw/core/machine.c index a673302cce..aa520e74a8 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -40,6 +40,9 @@ #include "hw/virtio/virtio-pci.h" #include "qom/object_interfaces.h" +GlobalProperty hw_compat_7_1[] = {}; +const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1); + GlobalProperty hw_compat_7_0[] = { { "arm-gicv3-common", "force-8-bit-prio", "on" }, { "nvme-ns", "eui64-default", "on"}, diff --git a/hw/core/sysbus-fdt.c b/hw/core/sysbus-fdt.c index 19d22cbe73..edb0c49b19 100644 --- a/hw/core/sysbus-fdt.c +++ b/hw/core/sysbus-fdt.c @@ -539,7 +539,7 @@ void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr, assert(fdt); - node = g_strdup_printf("/platform@%"PRIx64, addr); + node = g_strdup_printf("/platform-bus@%"PRIx64, addr); /* Create a /platform node that we can put all devices into */ qemu_fdt_add_subnode(fdt, node); diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c index 687759b301..83ce7a8270 100644 --- a/hw/cxl/cxl-device-utils.c +++ b/hw/cxl/cxl-device-utils.c @@ -141,9 +141,15 @@ static uint64_t mdev_reg_read(void *opaque, hwaddr offset, unsigned size) return retval; } +static void ro_reg_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + /* Many register sets are read only */ +} + static const MemoryRegionOps mdev_ops = { .read = mdev_reg_read, - .write = NULL, /* memory device register is read only */ + .write = ro_reg_write, .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 1, @@ -173,7 +179,7 @@ static const MemoryRegionOps mailbox_ops = { static const MemoryRegionOps dev_ops = { .read = dev_reg_read, - .write = NULL, /* status register is read only */ + .write = ro_reg_write, .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 1, @@ -188,7 +194,7 @@ static const MemoryRegionOps dev_ops = { static const MemoryRegionOps caps_ops = { .read = caps_reg_read, - .write = NULL, /* caps registers are read only */ + .write = ro_reg_write, .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 1, diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c index 483d8eb13f..1adf61231a 100644 --- a/hw/cxl/cxl-host.c +++ b/hw/cxl/cxl-host.c @@ -26,7 +26,7 @@ static void cxl_fixed_memory_window_config(CXLState *cxl_state, CXLFixedMemoryWindowOptions *object, Error **errp) { - CXLFixedWindow *fw = g_malloc0(sizeof(*fw)); + g_autofree CXLFixedWindow *fw = g_malloc0(sizeof(*fw)); strList *target; int i; @@ -64,7 +64,8 @@ static void cxl_fixed_memory_window_config(CXLState *cxl_state, fw->enc_int_gran = 0; } - cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows, fw); + cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows, + g_steal_pointer(&fw)); return; } @@ -103,7 +104,6 @@ static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr, uint32_t ctrl; uint32_t ig_enc; uint32_t iw_enc; - uint32_t target_reg; uint32_t target_idx; ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL]; @@ -115,14 +115,13 @@ static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr, iw_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IW); target_idx = (addr / cxl_decode_ig(ig_enc)) % (1 << iw_enc); - if (target_idx > 4) { - target_reg = cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_LO]; - target_reg >>= target_idx * 8; + if (target_idx < 4) { + *target = extract32(cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_LO], + target_idx * 8, 8); } else { - target_reg = cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_LO]; - target_reg >>= (target_idx - 4) * 8; + *target = extract32(cache_mem[R_CXL_HDM_DECODER0_TARGET_LIST_HI], + (target_idx - 4) * 8, 8); } - *target = target_reg & 0xff; return true; } diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index bb66c765a5..bc1bb18844 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -406,7 +406,7 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { cmd_identify_memory_device, 0, 0 }, [CCLS][GET_PARTITION_INFO] = { "CCLS_GET_PARTITION_INFO", cmd_ccls_get_partition_info, 0, 0 }, - [CCLS][GET_LSA] = { "CCLS_GET_LSA", cmd_ccls_get_lsa, 0, 0 }, + [CCLS][GET_LSA] = { "CCLS_GET_LSA", cmd_ccls_get_lsa, 8, 0 }, [CCLS][SET_LSA] = { "CCLS_SET_LSA", cmd_ccls_set_lsa, ~0, IMMEDIATE_CONFIG_CHANGE | IMMEDIATE_DATA_CHANGE }, }; @@ -425,7 +425,7 @@ void cxl_process_mailbox(CXLDeviceState *cxl_dstate) cxl_cmd = &cxl_cmd_set[set][cmd]; h = cxl_cmd->handler; if (h) { - if (len == cxl_cmd->in) { + if (len == cxl_cmd->in || cxl_cmd->in == ~0) { cxl_cmd->payload = cxl_dstate->mbox_reg_state + A_CXL_DEV_CMD_PAYLOAD; ret = (*h)(cxl_cmd, cxl_dstate, &len); diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c index 4dc10ea795..692bec91de 100644 --- a/hw/display/ati_2d.c +++ b/hw/display/ati_2d.c @@ -84,7 +84,7 @@ void ati_2d_blt(ATIVGAState *s) DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d %c %c\n", s->regs.src_offset, s->regs.dst_offset, s->regs.default_offset, s->regs.src_pitch, s->regs.dst_pitch, s->regs.default_pitch, - s->regs.src_x, s->regs.src_y, s->regs.dst_x, s->regs.dst_y, + s->regs.src_x, s->regs.src_y, dst_x, dst_y, s->regs.dst_width, s->regs.dst_height, (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? '>' : '<'), (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? 'v' : '^')); @@ -180,11 +180,11 @@ void ati_2d_blt(ATIVGAState *s) dst_stride /= sizeof(uint32_t); DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n", dst_bits, dst_stride, bpp, - s->regs.dst_x, s->regs.dst_y, + dst_x, dst_y, s->regs.dst_width, s->regs.dst_height, filler); pixman_fill((uint32_t *)dst_bits, dst_stride, bpp, - s->regs.dst_x, s->regs.dst_y, + dst_x, dst_y, s->regs.dst_width, s->regs.dst_height, filler); if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr && diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c index 088fc3d51c..a05277674f 100644 --- a/hw/display/bcm2835_fb.c +++ b/hw/display/bcm2835_fb.c @@ -279,8 +279,7 @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value) newconf.xoffset = ldl_le_phys(&s->dma_as, value + 24); newconf.yoffset = ldl_le_phys(&s->dma_as, value + 28); - newconf.base = s->vcram_base | (value & 0xc0000000); - newconf.base += BCM2835_FB_OFFSET; + newconf.base = s->vcram_base + BCM2835_FB_OFFSET; /* Copy fields which we don't want to change from the existing config */ newconf.pixo = s->config.pixo; diff --git a/hw/display/vga.c b/hw/display/vga.c index 5dca2d1528..50ecb1ad02 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1514,9 +1514,10 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) force_shadow = true; } + /* bits 5-6: 0 = 16-color mode, 1 = 4-color mode, 2 = 256-color mode. */ shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3; double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7); - if (shift_control != 1) { + if (s->cr[VGA_CRTC_MODE] & 1) { multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan) - 1; } else { diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 3340ef9e5f..19c0e20103 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "qemu/sockets.h" #include "hw/qdev-properties.h" #include "hw/virtio/virtio-gpu.h" #include "chardev/char-fe.h" @@ -375,7 +376,7 @@ vhost_user_gpu_do_set_socket(VhostUserGPU *g, Error **errp) Chardev *chr; int sv[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (qemu_socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { error_setg_errno(errp, errno, "socketpair() failed"); return false; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 20cc703dcc..5e15c79b94 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -515,9 +515,10 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { scanout = &g->parent_obj.scanout[i]; if (scanout->resource_id == res->resource_id && - rf.r.x >= scanout->x && rf.r.y >= scanout->y && - rf.r.x + rf.r.width <= scanout->x + scanout->width && - rf.r.y + rf.r.height <= scanout->y + scanout->height && + rf.r.x < scanout->x + scanout->width && + rf.r.x + rf.r.width >= scanout->x && + rf.r.y < scanout->y + scanout->height && + rf.r.y + rf.r.height >= scanout->y && console_has_gl(scanout->con)) { dpy_gl_update(scanout->con, 0, 0, scanout->width, scanout->height); diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index a071c81883..b0828d65aa 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -532,8 +532,8 @@ 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(); + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid command: %u", __func__, cmd); + return; } s->core_registers[DP_INTERRUPT_SIGNAL_STATE] |= 0x04; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index cad6f5ac41..4f54b61904 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -374,6 +374,25 @@ build_facs(GArray *table_data) g_array_append_vals(table_data, reserved, 40); /* Reserved */ } +Aml *aml_pci_device_dsm(void) +{ + Aml *method; + + method = aml_method("_DSM", 4, AML_SERIALIZED); + { + Aml *params = aml_local(0); + Aml *pkg = aml_package(2); + aml_append(pkg, aml_name("BSEL")); + aml_append(pkg, aml_name("ASUN")); + aml_append(method, aml_store(pkg, params)); + aml_append(method, + aml_return(aml_call5("PDSM", aml_arg(0), aml_arg(1), + aml_arg(2), aml_arg(3), params)) + ); + } + return method; +} + static void build_append_pcihp_notify_entry(Aml *method, int slot) { Aml *if_ctx; @@ -408,13 +427,41 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, int func = PCI_FUNC(devfn); /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ int adr = slot << 16 | func; - bool hotplug_enabled_dev; - bool bridge_in_acpi; - bool cold_plugged_bridge; + bool hotpluggbale_slot = false; + bool bridge_in_acpi = false; + bool cold_plugged_bridge = false; + bool is_vga = false; + + if (pdev) { + pc = PCI_DEVICE_GET_CLASS(pdev); + dc = DEVICE_GET_CLASS(pdev); + + if (pc->class_id == PCI_CLASS_BRIDGE_ISA) { + continue; + } + + is_vga = pc->class_id == PCI_CLASS_DISPLAY_VGA; - if (!pdev) { /* - * add hotplug slots for non present devices. + * Cold plugged bridges aren't themselves hot-pluggable. + * Hotplugged bridges *are* hot-pluggable. + */ + cold_plugged_bridge = pc->is_bridge && !DEVICE(pdev)->hotplugged; + bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; + + hotpluggbale_slot = bsel && dc->hotpluggable && + !cold_plugged_bridge; + + /* + * allow describing coldplugged bridges in ACPI even if they are not + * on function 0, as they are not unpluggable, for all other devices + * generate description only for function 0 per slot + */ + if (func && !bridge_in_acpi) { + continue; + } + } else { + /* * hotplug is supported only for non-multifunction device * so generate device description only for function 0 */ @@ -422,51 +469,11 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, if (pci_bus_is_express(bus) && slot > 0) { break; } - dev = aml_device("S%.02X", devfn); - aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); - aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - aml_append(method, - aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) - ); - aml_append(dev, method); - method = aml_method("_DSM", 4, AML_SERIALIZED); - aml_append(method, - aml_return(aml_call6("PDSM", aml_arg(0), aml_arg(1), - aml_arg(2), aml_arg(3), - aml_name("BSEL"), aml_name("_SUN"))) - ); - aml_append(dev, method); - aml_append(parent_scope, dev); - - build_append_pcihp_notify_entry(notify_method, slot); + /* mark it as empty hotpluggable slot */ + hotpluggbale_slot = true; + } else { + continue; } - continue; - } - - pc = PCI_DEVICE_GET_CLASS(pdev); - dc = DEVICE_GET_CLASS(pdev); - - /* - * Cold plugged bridges aren't themselves hot-pluggable. - * Hotplugged bridges *are* hot-pluggable. - */ - cold_plugged_bridge = pc->is_bridge && !DEVICE(pdev)->hotplugged; - bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; - - hotplug_enabled_dev = bsel && dc->hotpluggable && !cold_plugged_bridge; - - if (pc->class_id == PCI_CLASS_BRIDGE_ISA) { - continue; - } - - /* - * allow describing coldplugged bridges in ACPI even if they are not - * on function 0, as they are not unpluggable, for all other devices - * generate description only for function 0 per slot - */ - if (func && !bridge_in_acpi) { - continue; } /* start to compose PCI device descriptor */ @@ -479,15 +486,10 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, * enumeration order in linux kernel, so use another variable for it */ aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); - method = aml_method("_DSM", 4, AML_SERIALIZED); - aml_append(method, aml_return( - aml_call6("PDSM", aml_arg(0), aml_arg(1), aml_arg(2), - aml_arg(3), aml_name("BSEL"), aml_name("ASUN")) - )); - aml_append(dev, method); + aml_append(dev, aml_pci_device_dsm()); } - if (pc->class_id == PCI_CLASS_DISPLAY_VGA) { + if (is_vga) { /* add VGA specific AML methods */ int s3d; @@ -508,19 +510,10 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, method = aml_method("_S3D", 0, AML_NOTSERIALIZED); aml_append(method, aml_return(aml_int(s3d))); aml_append(dev, method); - } else if (hotplug_enabled_dev) { - aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); - /* add _EJ0 to make slot hotpluggable */ - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - aml_append(method, - aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) - ); - aml_append(dev, method); + } - if (bsel) { - build_append_pcihp_notify_entry(notify_method, slot); - } - } else if (bridge_in_acpi) { + bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; + if (bridge_in_acpi) { /* * device is coldplugged bridge, * add child device descriptions into its scope @@ -529,6 +522,19 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en); } + + if (hotpluggbale_slot) { + aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); + /* add _EJ0 to make slot hotpluggable */ + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); + aml_append(method, + aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) + ); + aml_append(dev, method); + + build_append_pcihp_notify_entry(notify_method, slot); + } + /* device descriptor has been composed, add it into parent context */ aml_append(parent_scope, dev); } @@ -572,84 +578,100 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, qobject_unref(bsel); } -Aml *aml_pci_device_dsm(void) +static Aml *aml_pci_pdsm(void) { - Aml *method, *UUID, *ifctx, *ifctx1, *ifctx2, *ifctx3, *elsectx; - Aml *acpi_index = aml_local(0); + Aml *method, *UUID, *ifctx, *ifctx1; + Aml *ret = aml_local(0); + Aml *caps = aml_local(1); + Aml *acpi_index = aml_local(2); Aml *zero = aml_int(0); - Aml *bnum = aml_arg(4); + Aml *one = aml_int(1); Aml *func = aml_arg(2); Aml *rev = aml_arg(1); - Aml *sunum = aml_arg(5); + Aml *params = aml_arg(4); + Aml *bnum = aml_derefof(aml_index(params, aml_int(0))); + Aml *sunum = aml_derefof(aml_index(params, aml_int(1))); - method = aml_method("PDSM", 6, AML_SERIALIZED); + method = aml_method("PDSM", 5, AML_SERIALIZED); + /* get supported functions */ + ifctx = aml_if(aml_equal(func, zero)); + { + uint8_t byte_list[1] = { 0 }; /* nothing supported yet */ + aml_append(ifctx, aml_store(aml_buffer(1, byte_list), ret)); + aml_append(ifctx, aml_store(zero, caps)); + + /* + * PCI Firmware Specification 3.1 + * 4.6. _DSM Definitions for PCI + */ + UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); + ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(0), UUID))); + { + /* call is for unsupported UUID, bail out */ + aml_append(ifctx1, aml_return(ret)); + } + aml_append(ifctx, ifctx1); + + ifctx1 = aml_if(aml_lless(rev, aml_int(2))); + { + /* call is for unsupported REV, bail out */ + aml_append(ifctx1, aml_return(ret)); + } + aml_append(ifctx, ifctx1); + + aml_append(ifctx, + aml_store(aml_call2("AIDX", bnum, sunum), acpi_index)); + /* + * advertise function 7 if device has acpi-index + * acpi_index values: + * 0: not present (default value) + * FFFFFFFF: not supported (old QEMU without PIDX reg) + * other: device's acpi-index + */ + ifctx1 = aml_if(aml_lnot( + aml_or(aml_equal(acpi_index, zero), + aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL) + )); + { + /* have supported functions */ + aml_append(ifctx1, aml_or(caps, one, caps)); + /* support for function 7 */ + aml_append(ifctx1, + aml_or(caps, aml_shiftleft(one, aml_int(7)), caps)); + } + aml_append(ifctx, ifctx1); + + aml_append(ifctx, aml_store(caps, aml_index(ret, zero))); + aml_append(ifctx, aml_return(ret)); + } + aml_append(method, ifctx); + + /* handle specific functions requests */ /* * PCI Firmware Specification 3.1 - * 4.6. _DSM Definitions for PCI + * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under + * Operating Systems */ - UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); - ifctx = aml_if(aml_equal(aml_arg(0), UUID)); + ifctx = aml_if(aml_equal(func, aml_int(7))); { - aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index)); - ifctx1 = aml_if(aml_equal(func, zero)); - { - uint8_t byte_list[1]; + Aml *pkg = aml_package(2); - ifctx2 = aml_if(aml_equal(rev, aml_int(2))); - { - /* - * advertise function 7 if device has acpi-index - * acpi_index values: - * 0: not present (default value) - * FFFFFFFF: not supported (old QEMU without PIDX reg) - * other: device's acpi-index - */ - ifctx3 = aml_if(aml_lnot( - aml_or(aml_equal(acpi_index, zero), - aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL) - )); - { - byte_list[0] = - 1 /* have supported functions */ | - 1 << 7 /* support for function 7 */ - ; - aml_append(ifctx3, aml_return(aml_buffer(1, byte_list))); - } - aml_append(ifctx2, ifctx3); - } - aml_append(ifctx1, ifctx2); + aml_append(pkg, zero); + /* + * optional, if not impl. should return null string + */ + aml_append(pkg, aml_string("%s", "")); + aml_append(ifctx, aml_store(pkg, ret)); - byte_list[0] = 0; /* nothing supported */ - aml_append(ifctx1, aml_return(aml_buffer(1, byte_list))); - } - aml_append(ifctx, ifctx1); - elsectx = aml_else(); - /* - * PCI Firmware Specification 3.1 - * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under - * Operating Systems - */ - ifctx1 = aml_if(aml_equal(func, aml_int(7))); - { - Aml *pkg = aml_package(2); - Aml *ret = aml_local(1); - - aml_append(pkg, zero); - /* - * optional, if not impl. should return null string - */ - aml_append(pkg, aml_string("%s", "")); - aml_append(ifctx1, aml_store(pkg, ret)); - /* - * update acpi-index to actual value - */ - aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero))); - aml_append(ifctx1, aml_return(ret)); - } - aml_append(elsectx, ifctx1); - aml_append(ifctx, elsectx); + aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index)); + /* + * update acpi-index to actual value + */ + aml_append(ifctx, aml_store(acpi_index, aml_index(ret, zero))); + aml_append(ifctx, aml_return(ret)); } + aml_append(method, ifctx); return method; } @@ -1339,7 +1361,7 @@ static void build_x86_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr) aml_append(method, aml_return(aml_local(0))); aml_append(scope, method); - aml_append(scope, aml_pci_device_dsm()); + aml_append(scope, aml_pci_pdsm()); aml_append(table, scope); } @@ -1467,9 +1489,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(sb_scope, dev); aml_append(dsdt, sb_scope); - if (misc->has_hpet) { - build_hpet_aml(dsdt); - } build_piix4_isa_bridge(dsdt); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); @@ -1515,9 +1534,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); - if (misc->has_hpet) { - build_hpet_aml(dsdt); - } build_q35_isa_bridge(dsdt); if (pm->pcihp_bridge_en) { build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base); @@ -1528,6 +1544,10 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } } + if (misc->has_hpet) { + build_hpet_aml(dsdt); + } + if (vmbus_bridge) { sb_scope = aml_scope("_SB"); aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge)); @@ -2024,7 +2044,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) build_srat_memory(table_data, mem_base, mem_len, i - 1, MEM_AFFINITY_ENABLED); } - mem_base = 1ULL << 32; + mem_base = x86ms->above_4g_mem_start; mem_len = next_base - x86ms->below_4g_mem_size; next_base = mem_base + mem_len; } diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 2162394e08..6524c2ee32 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1187,7 +1187,7 @@ static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info) return ret; } /* Drop any existing mapping */ - iova_tree_remove(as->iova_tree, &target); + iova_tree_remove(as->iova_tree, target); /* Recover the correct type */ event->type = IOMMU_NOTIFIER_MAP; entry->perm = cache_perm; @@ -1200,7 +1200,7 @@ static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info) trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask); return 0; } - iova_tree_remove(as->iova_tree, &target); + iova_tree_remove(as->iova_tree, target); } trace_vtd_page_walk_one(info->domain_id, entry->iova, @@ -3563,7 +3563,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) map.iova = n->start; map.size = size; - iova_tree_remove(as->iova_tree, &map); + iova_tree_remove(as->iova_tree, map); } static void vtd_address_space_unmap_all(IntelIOMMUState *s) @@ -3818,6 +3818,11 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) error_setg(errp, "eim=on requires accel=kvm,kernel-irqchip=split"); return false; } + if (!kvm_enable_x2apic()) { + error_setg(errp, "eim=on requires support on the KVM side" + "(X2APIC_API, first shipped in v4.7)"); + return false; + } } /* Currently only address widths supported are 39 and 48 bits */ diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index 0a10089f14..963e29362e 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -163,6 +163,7 @@ int load_multiboot(X86MachineState *x86ms, uint8_t *mb_bootinfo_data; uint32_t cmdline_len; GList *mods = NULL; + g_autofree char *kcmdline = NULL; /* Ok, let's see if it is a multiboot image. The header is 12x32bit long, so the latest entry may be 8192 - 48. */ @@ -362,9 +363,7 @@ int load_multiboot(X86MachineState *x86ms, } /* Commandline support */ - char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2]; - snprintf(kcmdline, sizeof(kcmdline), "%s %s", - kernel_filename, kernel_cmdline); + kcmdline = g_strdup_printf("%s %s", kernel_filename, kernel_cmdline); stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline)); stl_p(bootinfo + MBI_BOOTLOADER, mb_add_bootloader(&mbs, bootloader_name)); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d2b5823ffb..566accf7e6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -107,6 +107,9 @@ { "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ { "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, }, +GlobalProperty pc_compat_7_1[] = {}; +const size_t pc_compat_7_1_len = G_N_ELEMENTS(pc_compat_7_1); + GlobalProperty pc_compat_7_0[] = {}; const size_t pc_compat_7_0_len = G_N_ELEMENTS(pc_compat_7_0); @@ -814,10 +817,122 @@ void xen_load_linux(PCMachineState *pcms) #define PC_ROM_ALIGN 0x800 #define PC_ROM_SIZE (PC_ROM_MAX - PC_ROM_MIN_VGA) +static hwaddr pc_above_4g_end(PCMachineState *pcms) +{ + X86MachineState *x86ms = X86_MACHINE(pcms); + + if (pcms->sgx_epc.size != 0) { + return sgx_epc_above_4g_end(&pcms->sgx_epc); + } + + return x86ms->above_4g_mem_start + x86ms->above_4g_mem_size; +} + +static void pc_get_device_memory_range(PCMachineState *pcms, + hwaddr *base, + ram_addr_t *device_mem_size) +{ + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); + MachineState *machine = MACHINE(pcms); + ram_addr_t size; + hwaddr addr; + + size = machine->maxram_size - machine->ram_size; + addr = ROUND_UP(pc_above_4g_end(pcms), 1 * GiB); + + if (pcmc->enforce_aligned_dimm) { + /* size device region assuming 1G page max alignment per slot */ + size += (1 * GiB) * machine->ram_slots; + } + + *base = addr; + *device_mem_size = size; +} + +static uint64_t pc_get_cxl_range_start(PCMachineState *pcms) +{ + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); + hwaddr cxl_base; + ram_addr_t size; + + if (pcmc->has_reserved_memory) { + pc_get_device_memory_range(pcms, &cxl_base, &size); + cxl_base += size; + } else { + cxl_base = pc_above_4g_end(pcms); + } + + return cxl_base; +} + +static uint64_t pc_get_cxl_range_end(PCMachineState *pcms) +{ + uint64_t start = pc_get_cxl_range_start(pcms) + MiB; + + if (pcms->cxl_devices_state.fixed_windows) { + GList *it; + + start = ROUND_UP(start, 256 * MiB); + for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) { + CXLFixedWindow *fw = it->data; + start += fw->size; + } + } + + return start; +} + +static hwaddr pc_max_used_gpa(PCMachineState *pcms, uint64_t pci_hole64_size) +{ + X86CPU *cpu = X86_CPU(first_cpu); + + /* 32-bit systems don't have hole64 thus return max CPU address */ + if (cpu->phys_bits <= 32) { + return ((hwaddr)1 << cpu->phys_bits) - 1; + } + + return pc_pci_hole64_start() + pci_hole64_size - 1; +} + +/* + * AMD systems with an IOMMU have an additional hole close to the + * 1Tb, which are special GPAs that cannot be DMA mapped. Depending + * on kernel version, VFIO may or may not let you DMA map those ranges. + * Starting Linux v5.4 we validate it, and can't create guests on AMD machines + * with certain memory sizes. It's also wrong to use those IOVA ranges + * in detriment of leading to IOMMU INVALID_DEVICE_REQUEST or worse. + * The ranges reserved for Hyper-Transport are: + * + * FD_0000_0000h - FF_FFFF_FFFFh + * + * The ranges represent the following: + * + * Base Address Top Address Use + * + * FD_0000_0000h FD_F7FF_FFFFh Reserved interrupt address space + * FD_F800_0000h FD_F8FF_FFFFh Interrupt/EOI IntCtl + * FD_F900_0000h FD_F90F_FFFFh Legacy PIC IACK + * FD_F910_0000h FD_F91F_FFFFh System Management + * FD_F920_0000h FD_FAFF_FFFFh Reserved Page Tables + * FD_FB00_0000h FD_FBFF_FFFFh Address Translation + * FD_FC00_0000h FD_FDFF_FFFFh I/O Space + * FD_FE00_0000h FD_FFFF_FFFFh Configuration + * FE_0000_0000h FE_1FFF_FFFFh Extended Configuration/Device Messages + * FE_2000_0000h FF_FFFF_FFFFh Reserved + * + * See AMD IOMMU spec, section 2.1.2 "IOMMU Logical Topology", + * Table 3: Special Address Controls (GPA) for more information. + */ +#define AMD_HT_START 0xfd00000000UL +#define AMD_HT_END 0xffffffffffUL +#define AMD_ABOVE_1TB_START (AMD_HT_END + 1) +#define AMD_HT_SIZE (AMD_ABOVE_1TB_START - AMD_HT_START) + void pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, MemoryRegion *rom_memory, - MemoryRegion **ram_memory) + MemoryRegion **ram_memory, + uint64_t pci_hole64_size) { int linux_boot, i; MemoryRegion *option_rom_mr; @@ -827,13 +942,49 @@ void pc_memory_init(PCMachineState *pcms, MachineClass *mc = MACHINE_GET_CLASS(machine); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); X86MachineState *x86ms = X86_MACHINE(pcms); + hwaddr maxphysaddr, maxusedaddr; hwaddr cxl_base, cxl_resv_end = 0; + X86CPU *cpu = X86_CPU(first_cpu); assert(machine->ram_size == x86ms->below_4g_mem_size + x86ms->above_4g_mem_size); linux_boot = (machine->kernel_filename != NULL); + /* + * The HyperTransport range close to the 1T boundary is unique to AMD + * hosts with IOMMUs enabled. Restrict the ram-above-4g relocation + * to above 1T to AMD vCPUs only. @enforce_amd_1tb_hole is only false in + * older machine types (<= 7.0) for compatibility purposes. + */ + if (IS_AMD_CPU(&cpu->env) && pcmc->enforce_amd_1tb_hole) { + /* Bail out if max possible address does not cross HT range */ + if (pc_max_used_gpa(pcms, pci_hole64_size) >= AMD_HT_START) { + x86ms->above_4g_mem_start = AMD_ABOVE_1TB_START; + } + + /* + * Advertise the HT region if address space covers the reserved + * region or if we relocate. + */ + if (cpu->phys_bits >= 40) { + e820_add_entry(AMD_HT_START, AMD_HT_SIZE, E820_RESERVED); + } + } + + /* + * phys-bits is required to be appropriately configured + * to make sure max used GPA is reachable. + */ + maxusedaddr = pc_max_used_gpa(pcms, pci_hole64_size); + maxphysaddr = ((hwaddr)1 << cpu->phys_bits) - 1; + if (maxphysaddr < maxusedaddr) { + error_report("Address space limit 0x%"PRIx64" < 0x%"PRIx64 + " phys-bits too low (%u)", + maxphysaddr, maxusedaddr, cpu->phys_bits); + exit(EXIT_FAILURE); + } + /* * Split single memory region and use aliases to address portions of it, * done for backwards compatibility with older qemus. @@ -850,9 +1001,10 @@ void pc_memory_init(PCMachineState *pcms, machine->ram, x86ms->below_4g_mem_size, x86ms->above_4g_mem_size); - memory_region_add_subregion(system_memory, 0x100000000ULL, + memory_region_add_subregion(system_memory, x86ms->above_4g_mem_start, ram_above_4g); - e820_add_entry(0x100000000ULL, x86ms->above_4g_mem_size, E820_RAM); + e820_add_entry(x86ms->above_4g_mem_start, x86ms->above_4g_mem_size, + E820_RAM); } if (pcms->sgx_epc.size != 0) { @@ -874,7 +1026,7 @@ void pc_memory_init(PCMachineState *pcms, /* initialize device memory address space */ if (pcmc->has_reserved_memory && (machine->ram_size < machine->maxram_size)) { - ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size; + ram_addr_t device_mem_size; if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) { error_report("unsupported amount of memory slots: %"PRIu64, @@ -889,20 +1041,7 @@ void pc_memory_init(PCMachineState *pcms, exit(EXIT_FAILURE); } - if (pcms->sgx_epc.size != 0) { - machine->device_memory->base = sgx_epc_above_4g_end(&pcms->sgx_epc); - } else { - machine->device_memory->base = - 0x100000000ULL + x86ms->above_4g_mem_size; - } - - machine->device_memory->base = - ROUND_UP(machine->device_memory->base, 1 * GiB); - - if (pcmc->enforce_aligned_dimm) { - /* size device region assuming 1G page max alignment per slot */ - device_mem_size += (1 * GiB) * machine->ram_slots; - } + pc_get_device_memory_range(pcms, &machine->device_memory->base, &device_mem_size); if ((machine->device_memory->base + device_mem_size) < device_mem_size) { @@ -921,17 +1060,7 @@ void pc_memory_init(PCMachineState *pcms, MemoryRegion *mr = &pcms->cxl_devices_state.host_mr; hwaddr cxl_size = MiB; - if (pcmc->has_reserved_memory && machine->device_memory->base) { - cxl_base = machine->device_memory->base; - if (!pcmc->broken_reserved_end) { - cxl_base += memory_region_size(&machine->device_memory->mr); - } - } else if (pcms->sgx_epc.size != 0) { - cxl_base = sgx_epc_above_4g_end(&pcms->sgx_epc); - } else { - cxl_base = 0x100000000ULL + x86ms->above_4g_mem_size; - } - + cxl_base = pc_get_cxl_range_start(pcms); e820_add_entry(cxl_base, cxl_size, E820_RESERVED); memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size); memory_region_add_subregion(system_memory, cxl_base, mr); @@ -1016,28 +1145,18 @@ uint64_t pc_pci_hole64_start(void) PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); MachineState *ms = MACHINE(pcms); - X86MachineState *x86ms = X86_MACHINE(pcms); uint64_t hole64_start = 0; + ram_addr_t size = 0; - if (pcms->cxl_devices_state.host_mr.addr) { - hole64_start = pcms->cxl_devices_state.host_mr.addr + - memory_region_size(&pcms->cxl_devices_state.host_mr); - if (pcms->cxl_devices_state.fixed_windows) { - GList *it; - for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) { - CXLFixedWindow *fw = it->data; - hole64_start = fw->mr.addr + memory_region_size(&fw->mr); - } - } - } else if (pcmc->has_reserved_memory && ms->device_memory->base) { - hole64_start = ms->device_memory->base; + if (pcms->cxl_devices_state.is_enabled) { + hole64_start = pc_get_cxl_range_end(pcms); + } else if (pcmc->has_reserved_memory && (ms->ram_size < ms->maxram_size)) { + pc_get_device_memory_range(pcms, &hole64_start, &size); if (!pcmc->broken_reserved_end) { - hole64_start += memory_region_size(&ms->device_memory->mr); + hole64_start += size; } - } else if (pcms->sgx_epc.size != 0) { - hole64_start = sgx_epc_above_4g_end(&pcms->sgx_epc); } else { - hole64_start = 0x100000000ULL + x86ms->above_4g_mem_size; + hole64_start = pc_above_4g_end(pcms); } return ROUND_UP(hole64_start, 1 * GiB); @@ -1787,6 +1906,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) pcmc->has_reserved_memory = true; pcmc->kvmclock_enabled = true; pcmc->enforce_aligned_dimm = true; + pcmc->enforce_amd_1tb_hole = true; /* BIOS ACPI tables: 128K. Other BIOS datastructures: less than 4K reported * to be used at the moment, 32K should be enough for a while. */ pcmc->acpi_data_size = 0x20000 + 0x8000; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index fbf9465318..0b1a79c0fa 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -91,6 +91,8 @@ static void pc_init1(MachineState *machine, MemoryRegion *pci_memory; MemoryRegion *rom_memory; ram_addr_t lowmem; + uint64_t hole64_size; + DeviceState *i440fx_host; /* * Calculate ram split, for memory below and above 4G. It's a bit @@ -164,9 +166,15 @@ static void pc_init1(MachineState *machine, pci_memory = g_new(MemoryRegion, 1); memory_region_init(pci_memory, NULL, "pci", UINT64_MAX); rom_memory = pci_memory; + i440fx_host = qdev_new(host_type); + hole64_size = object_property_get_uint(OBJECT(i440fx_host), + PCI_HOST_PROP_PCI_HOLE64_SIZE, + &error_abort); } else { pci_memory = NULL; rom_memory = system_memory; + i440fx_host = NULL; + hole64_size = 0; } pc_guest_info_init(pcms); @@ -183,7 +191,7 @@ static void pc_init1(MachineState *machine, /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(pcms, system_memory, - rom_memory, &ram_memory); + rom_memory, &ram_memory, hole64_size); } else { pc_system_flash_cleanup_unused(pcms); if (machine->kernel_filename != NULL) { @@ -200,8 +208,8 @@ static void pc_init1(MachineState *machine, const char *type = xen_enabled() ? TYPE_PIIX3_XEN_DEVICE : TYPE_PIIX3_DEVICE; - pci_bus = i440fx_init(host_type, - pci_type, + pci_bus = i440fx_init(pci_type, + i440fx_host, system_memory, system_io, machine->ram_size, x86ms->below_4g_mem_size, x86ms->above_4g_mem_size, @@ -424,7 +432,7 @@ static void pc_i440fx_machine_options(MachineClass *m) machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE); } -static void pc_i440fx_7_1_machine_options(MachineClass *m) +static void pc_i440fx_7_2_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_machine_options(m); @@ -433,6 +441,20 @@ static void pc_i440fx_7_1_machine_options(MachineClass *m) pcmc->default_cpu_version = 1; } +DEFINE_I440FX_MACHINE(v7_2, "pc-i440fx-7.2", NULL, + pc_i440fx_7_2_machine_options); + +static void pc_i440fx_7_1_machine_options(MachineClass *m) +{ + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_i440fx_7_2_machine_options(m); + m->alias = NULL; + m->is_default = false; + pcmc->legacy_no_rng_seed = true; + compat_props_add(m->compat_props, hw_compat_7_1, hw_compat_7_1_len); + compat_props_add(m->compat_props, pc_compat_7_1, pc_compat_7_1_len); +} + DEFINE_I440FX_MACHINE(v7_1, "pc-i440fx-7.1", NULL, pc_i440fx_7_1_machine_options); @@ -442,7 +464,7 @@ static void pc_i440fx_7_0_machine_options(MachineClass *m) pc_i440fx_7_1_machine_options(m); m->alias = NULL; m->is_default = false; - pcmc->legacy_no_rng_seed = true; + pcmc->enforce_amd_1tb_hole = false; compat_props_add(m->compat_props, hw_compat_7_0, hw_compat_7_0_len); compat_props_add(m->compat_props, pc_compat_7_0, pc_compat_7_0_len); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 12cc76aaf8..a496bd6e74 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -138,6 +138,7 @@ static void pc_q35_init(MachineState *machine) MachineClass *mc = MACHINE_GET_CLASS(machine); bool acpi_pcihp; bool keep_pci_slot_hpc; + uint64_t pci_hole64_size = 0; /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory * and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping @@ -203,12 +204,19 @@ static void pc_q35_init(MachineState *machine) pcms->smbios_entry_point_type); } - /* allocate ram and load rom/bios */ - pc_memory_init(pcms, get_system_memory(), rom_memory, &ram_memory); - /* create pci host bus */ q35_host = Q35_HOST_DEVICE(qdev_new(TYPE_Q35_HOST_DEVICE)); + if (pcmc->pci_enabled) { + pci_hole64_size = object_property_get_uint(OBJECT(q35_host), + PCI_HOST_PROP_PCI_HOLE64_SIZE, + &error_abort); + } + + /* allocate ram and load rom/bios */ + pc_memory_init(pcms, get_system_memory(), rom_memory, &ram_memory, + pci_hole64_size); + object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host)); object_property_set_link(OBJECT(q35_host), MCH_HOST_PROP_RAM_MEM, OBJECT(ram_memory), NULL); @@ -362,7 +370,7 @@ static void pc_q35_machine_options(MachineClass *m) m->max_cpus = 288; } -static void pc_q35_7_1_machine_options(MachineClass *m) +static void pc_q35_7_2_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_machine_options(m); @@ -370,6 +378,19 @@ static void pc_q35_7_1_machine_options(MachineClass *m) pcmc->default_cpu_version = 1; } +DEFINE_Q35_MACHINE(v7_2, "pc-q35-7.2", NULL, + pc_q35_7_2_machine_options); + +static void pc_q35_7_1_machine_options(MachineClass *m) +{ + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_q35_7_2_machine_options(m); + m->alias = NULL; + pcmc->legacy_no_rng_seed = true; + compat_props_add(m->compat_props, hw_compat_7_1, hw_compat_7_1_len); + compat_props_add(m->compat_props, pc_compat_7_1, pc_compat_7_1_len); +} + DEFINE_Q35_MACHINE(v7_1, "pc-q35-7.1", NULL, pc_q35_7_1_machine_options); @@ -378,7 +399,7 @@ static void pc_q35_7_0_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_7_1_machine_options(m); m->alias = NULL; - pcmc->legacy_no_rng_seed = true; + pcmc->enforce_amd_1tb_hole = false; compat_props_add(m->compat_props, hw_compat_7_0, hw_compat_7_0_len); compat_props_add(m->compat_props, pc_compat_7_0, pc_compat_7_0_len); } diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index a44d66ba2a..09d9c7c73d 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -295,7 +295,7 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms) return; } - sgx_epc->base = 0x100000000ULL + x86ms->above_4g_mem_size; + sgx_epc->base = x86ms->above_4g_mem_start + x86ms->above_4g_mem_size; memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX); memory_region_add_subregion(get_system_memory(), sgx_epc->base, diff --git a/hw/i386/x86.c b/hw/i386/x86.c index ecea25d249..1148f70c03 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -37,6 +37,7 @@ #include "sysemu/whpx.h" #include "sysemu/numa.h" #include "sysemu/replay.h" +#include "sysemu/reset.h" #include "sysemu/sysemu.h" #include "sysemu/cpu-timers.h" #include "sysemu/xen.h" @@ -652,12 +653,12 @@ DeviceState *ioapic_init_secondary(GSIState *gsi_state) return dev; } -struct setup_data { +typedef struct SetupData { uint64_t next; uint32_t type; uint32_t len; uint8_t data[]; -} __attribute__((packed)); +} __attribute__((packed)) SetupData; /* @@ -764,6 +765,30 @@ static bool load_elfboot(const char *kernel_filename, return true; } +typedef struct SetupDataFixup { + void *pos; + hwaddr orig_val, new_val; + uint32_t addr; +} SetupDataFixup; + +static void fixup_setup_data(void *opaque) +{ + SetupDataFixup *fixup = opaque; + stq_p(fixup->pos, fixup->new_val); +} + +static void reset_setup_data(void *opaque) +{ + SetupDataFixup *fixup = opaque; + stq_p(fixup->pos, fixup->orig_val); +} + +static void reset_rng_seed(void *opaque) +{ + SetupData *setup_data = opaque; + qemu_guest_getrandom_nofail(setup_data->data, le32_to_cpu(setup_data->len)); +} + void x86_load_linux(X86MachineState *x86ms, FWCfgState *fw_cfg, int acpi_data_size, @@ -780,7 +805,7 @@ void x86_load_linux(X86MachineState *x86ms, FILE *f; char *vmode; MachineState *machine = MACHINE(x86ms); - struct setup_data *setup_data; + SetupData *setup_data; const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; const char *dtb_filename = machine->dtb; @@ -1063,11 +1088,11 @@ void x86_load_linux(X86MachineState *x86ms, } setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(struct setup_data) + dtb_size; + kernel_size = setup_data_offset + sizeof(SetupData) + dtb_size; kernel = g_realloc(kernel, kernel_size); - setup_data = (struct setup_data *)(kernel + setup_data_offset); + setup_data = (SetupData *)(kernel + setup_data_offset); setup_data->next = cpu_to_le64(first_setup_data); first_setup_data = prot_addr + setup_data_offset; setup_data->type = cpu_to_le32(SETUP_DTB); @@ -1078,18 +1103,25 @@ void x86_load_linux(X86MachineState *x86ms, if (!legacy_no_rng_seed) { setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(struct setup_data) + RNG_SEED_LENGTH; + kernel_size = setup_data_offset + sizeof(SetupData) + RNG_SEED_LENGTH; kernel = g_realloc(kernel, kernel_size); - setup_data = (struct setup_data *)(kernel + setup_data_offset); + setup_data = (SetupData *)(kernel + setup_data_offset); setup_data->next = cpu_to_le64(first_setup_data); first_setup_data = prot_addr + setup_data_offset; setup_data->type = cpu_to_le32(SETUP_RNG_SEED); setup_data->len = cpu_to_le32(RNG_SEED_LENGTH); qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH); + qemu_register_reset(reset_rng_seed, setup_data); + fw_cfg_add_bytes_callback(fw_cfg, FW_CFG_KERNEL_DATA, reset_rng_seed, NULL, + setup_data, kernel, kernel_size, true); + } else { + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); } - /* Offset 0x250 is a pointer to the first setup_data link. */ - stq_p(header + 0x250, first_setup_data); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + sev_load_ctx.kernel_data = (char *)kernel; + sev_load_ctx.kernel_size = kernel_size; /* * If we're starting an encrypted VM, it will be OVMF based, which uses the @@ -1099,16 +1131,20 @@ void x86_load_linux(X86MachineState *x86ms, * file the user passed in. */ if (!sev_enabled()) { + SetupDataFixup *fixup = g_malloc(sizeof(*fixup)); + memcpy(setup, header, MIN(sizeof(header), setup_size)); + /* Offset 0x250 is a pointer to the first setup_data link. */ + fixup->pos = setup + 0x250; + fixup->orig_val = ldq_p(fixup->pos); + fixup->new_val = first_setup_data; + fixup->addr = cpu_to_le32(real_addr); + fw_cfg_add_bytes_callback(fw_cfg, FW_CFG_SETUP_ADDR, fixup_setup_data, NULL, + fixup, &fixup->addr, sizeof(fixup->addr), true); + qemu_register_reset(reset_setup_data, fixup); + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr); } - - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); - sev_load_ctx.kernel_data = (char *)kernel; - sev_load_ctx.kernel_size = kernel_size; - - fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size); sev_load_ctx.setup_data = (char *)setup; @@ -1391,6 +1427,7 @@ static void x86_machine_initfn(Object *obj) x86ms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); x86ms->bus_lock_ratelimit = 0; + x86ms->above_4g_mem_start = 4 * GiB; } static void x86_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/ide/core.c b/hw/ide/core.c index 7cbc0a54a7..39afdc0006 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1340,6 +1340,11 @@ static void ide_reset(IDEState *s) s->pio_aiocb = NULL; } + if (s->reset_reverts) { + s->reset_reverts = false; + s->heads = s->drive_heads; + s->sectors = s->drive_sectors; + } if (s->drive_kind == IDE_CFATA) s->mult_sectors = 0; else @@ -1618,6 +1623,20 @@ static bool cmd_check_power_mode(IDEState *s, uint8_t cmd) return true; } +/* INITIALIZE DEVICE PARAMETERS */ +static bool cmd_specify(IDEState *s, uint8_t cmd) +{ + if (s->blk && s->drive_kind != IDE_CD) { + s->heads = (s->select & (ATA_DEV_HS)) + 1; + s->sectors = s->nsector; + ide_set_irq(s->bus); + } else { + ide_abort_command(s); + } + + return true; +} + static bool cmd_set_features(IDEState *s, uint8_t cmd) { uint16_t *identify_data; @@ -1641,7 +1660,11 @@ static bool cmd_set_features(IDEState *s, uint8_t cmd) ide_flush_cache(s); return false; case 0xcc: /* reverting to power-on defaults enable */ + s->reset_reverts = true; + return true; case 0x66: /* reverting to power-on defaults disable */ + s->reset_reverts = false; + return true; case 0xaa: /* read look-ahead enable */ case 0x55: /* read look-ahead disable */ case 0x05: /* set advanced power management mode */ @@ -1704,8 +1727,14 @@ static bool cmd_identify_packet(IDEState *s, uint8_t cmd) return false; } +/* EXECUTE DEVICE DIAGNOSTIC */ static bool cmd_exec_dev_diagnostic(IDEState *s, uint8_t cmd) { + /* + * Clear the device register per the ATA (v6) specification, + * because ide_set_signature does not clear LBA or drive bits. + */ + s->select = (ATA_DEV_ALWAYS_ON); ide_set_signature(s); if (s->drive_kind == IDE_CD) { @@ -2045,7 +2074,7 @@ static const struct { [WIN_SEEK] = { cmd_seek, HD_CFA_OK | SET_DSC }, [CFA_TRANSLATE_SECTOR] = { cmd_cfa_translate_sector, CFA_OK }, [WIN_DIAGNOSE] = { cmd_exec_dev_diagnostic, ALL_OK }, - [WIN_SPECIFY] = { cmd_nop, HD_CFA_OK | SET_DSC }, + [WIN_SPECIFY] = { cmd_specify, HD_CFA_OK | SET_DSC }, [WIN_STANDBYNOW2] = { cmd_nop, HD_CFA_OK }, [WIN_IDLEIMMEDIATE2] = { cmd_nop, HD_CFA_OK }, [WIN_STANDBY2] = { cmd_nop, HD_CFA_OK }, @@ -2535,8 +2564,8 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, blk_get_geometry(blk, &nb_sectors); s->cylinders = cylinders; - s->heads = heads; - s->sectors = secs; + s->heads = s->drive_heads = heads; + s->sectors = s->drive_sectors = secs; s->chs_trans = chs_trans; s->nb_sectors = nb_sectors; s->wwn = wwn; diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 9a9b28078e..de1f4f0efb 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -21,6 +21,10 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. + * + * References: + * [1] 82371FB (PIIX) AND 82371SB (PIIX3) PCI ISA IDE XCELERATOR, + * 290550-002, Intel Corporation, April 1997. */ #include "qemu/osdep.h" @@ -114,14 +118,11 @@ static void piix_ide_reset(DeviceState *dev) ide_bus_reset(&d->bus[i]); } - /* TODO: this is the default. do not override. */ - pci_conf[PCI_COMMAND] = 0x00; - /* TODO: this is the default. do not override. */ - pci_conf[PCI_COMMAND + 1] = 0x00; - /* TODO: use pci_set_word */ - pci_conf[PCI_STATUS] = PCI_STATUS_FAST_BACK; - pci_conf[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8; - pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */ + /* PCI command register default value (0000h) per [1, p.48]. */ + pci_set_word(pci_conf + PCI_COMMAND, 0x0000); + pci_set_word(pci_conf + PCI_STATUS, + PCI_STATUS_DEVSEL_MEDIUM | PCI_STATUS_FAST_BACK); + pci_set_byte(pci_conf + 0x20, 0x01); /* BMIBA: 20-23h */ } static int pci_piix_init_ports(PCIIDEState *d) diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index f1ecb2502b..c92ceecc16 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -492,7 +492,7 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, return MEMTX_OK; case GICR_WAKER: /* Only the ProcessorSleep bit is writable. When the guest sets - * it it requests that we transition the channel between the + * it, it requests that we transition the channel between the * redistributor and the cpu interface to quiescent, and that * we set the ChildrenAsleep bit once the inteface has reached the * quiescent state. diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c index 60013f2dde..dcf5de5d43 100644 --- a/hw/intc/ppc-uic.c +++ b/hw/intc/ppc-uic.c @@ -25,11 +25,8 @@ #include "qemu/osdep.h" #include "hw/intc/ppc-uic.h" #include "hw/irq.h" -#include "cpu.h" -#include "hw/ppc/ppc.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "qapi/error.h" enum { DCR_UICSR = 0x000, @@ -105,10 +102,9 @@ static void ppcuic_trigger_irq(PPCUIC *uic) static void ppcuic_set_irq(void *opaque, int irq_num, int level) { - PPCUIC *uic; + PPCUIC *uic = opaque; uint32_t mask, sr; - uic = opaque; mask = 1U << (31 - irq_num); LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32 " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", @@ -144,10 +140,9 @@ static void ppcuic_set_irq(void *opaque, int irq_num, int level) static uint32_t dcr_read_uic(void *opaque, int dcrn) { - PPCUIC *uic; + PPCUIC *uic = opaque; uint32_t ret; - uic = opaque; dcrn -= uic->dcr_base; switch (dcrn) { case DCR_UICSR: @@ -192,9 +187,8 @@ static uint32_t dcr_read_uic(void *opaque, int dcrn) static void dcr_write_uic(void *opaque, int dcrn, uint32_t val) { - PPCUIC *uic; + PPCUIC *uic = opaque; - uic = opaque; dcrn -= uic->dcr_base; LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val); switch (dcrn) { @@ -251,19 +245,12 @@ static void ppc_uic_reset(DeviceState *dev) static void ppc_uic_realize(DeviceState *dev, Error **errp) { PPCUIC *uic = PPC_UIC(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - PowerPCCPU *cpu; int i; - if (!uic->cpu) { - /* This is a programming error in the code using this device */ - error_setg(errp, "ppc-uic 'cpu' link property was not set"); - return; - } - - cpu = POWERPC_CPU(uic->cpu); for (i = 0; i < DCR_UICMAX; i++) { - ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic, + ppc4xx_dcr_register(dcr, uic->dcr_base + i, uic, &dcr_read_uic, &dcr_write_uic); } @@ -273,7 +260,6 @@ static void ppc_uic_realize(DeviceState *dev, Error **errp) } static Property ppc_uic_properties[] = { - DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *), DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0xc0), DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true), DEFINE_PROP_END_OF_LIST() @@ -308,7 +294,7 @@ static void ppc_uic_class_init(ObjectClass *klass, void *data) static const TypeInfo ppc_uic_info = { .name = TYPE_PPC_UIC, - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_PPC4xx_DCR_DEVICE, .instance_size = sizeof(PPCUIC), .class_init = ppc_uic_class_init, }; diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c index e7942c4e5a..eee04643cb 100644 --- a/hw/intc/riscv_aclint.c +++ b/hw/intc/riscv_aclint.c @@ -32,6 +32,7 @@ #include "hw/intc/riscv_aclint.h" #include "qemu/timer.h" #include "hw/irq.h" +#include "migration/vmstate.h" typedef struct riscv_aclint_mtimer_callback { RISCVAclintMTimerState *s; @@ -65,19 +66,22 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer, uint64_t rtc_r = cpu_riscv_read_rtc(mtimer); - cpu->env.timecmp = value; - if (cpu->env.timecmp <= rtc_r) { + /* Compute the relative hartid w.r.t the socket */ + hartid = hartid - mtimer->hartid_base; + + mtimer->timecmp[hartid] = value; + if (mtimer->timecmp[hartid] <= rtc_r) { /* * If we're setting an MTIMECMP value in the "past", * immediately raise the timer interrupt */ - qemu_irq_raise(mtimer->timer_irqs[hartid - mtimer->hartid_base]); + qemu_irq_raise(mtimer->timer_irqs[hartid]); return; } /* otherwise, set up the future timer interrupt */ - qemu_irq_lower(mtimer->timer_irqs[hartid - mtimer->hartid_base]); - diff = cpu->env.timecmp - rtc_r; + qemu_irq_lower(mtimer->timer_irqs[hartid]); + diff = mtimer->timecmp[hartid] - rtc_r; /* back to ns (note args switched in muldiv64) */ uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq); @@ -102,7 +106,7 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer, next = MIN(next, INT64_MAX); } - timer_mod(cpu->env.timer, next); + timer_mod(mtimer->timers[hartid], next); } /* @@ -133,11 +137,11 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr, "aclint-mtimer: invalid hartid: %zu", hartid); } else if ((addr & 0x7) == 0) { /* timecmp_lo for RV32/RV64 or timecmp for RV64 */ - uint64_t timecmp = env->timecmp; + uint64_t timecmp = mtimer->timecmp[hartid]; return (size == 4) ? (timecmp & 0xFFFFFFFF) : timecmp; } else if ((addr & 0x7) == 4) { /* timecmp_hi */ - uint64_t timecmp = env->timecmp; + uint64_t timecmp = mtimer->timecmp[hartid]; return (timecmp >> 32) & 0xFFFFFFFF; } else { qemu_log_mask(LOG_UNIMP, @@ -177,7 +181,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, } else if ((addr & 0x7) == 0) { if (size == 4) { /* timecmp_lo for RV32/RV64 */ - uint64_t timecmp_hi = env->timecmp >> 32; + uint64_t timecmp_hi = mtimer->timecmp[hartid] >> 32; riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, timecmp_hi << 32 | (value & 0xFFFFFFFF)); } else { @@ -188,7 +192,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, } else if ((addr & 0x7) == 4) { if (size == 4) { /* timecmp_hi for RV32/RV64 */ - uint64_t timecmp_lo = env->timecmp; + uint64_t timecmp_lo = mtimer->timecmp[hartid]; riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, value << 32 | (timecmp_lo & 0xFFFFFFFF)); } else { @@ -234,7 +238,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, } riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), mtimer->hartid_base + i, - env->timecmp); + mtimer->timecmp[i]); } return; } @@ -284,6 +288,8 @@ static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp) s->timer_irqs = g_new(qemu_irq, s->num_harts); qdev_init_gpio_out(dev, s->timer_irqs, s->num_harts); + s->timers = g_new0(QEMUTimer *, s->num_harts); + s->timecmp = g_new0(uint64_t, s->num_harts); /* Claim timer interrupt bits */ for (i = 0; i < s->num_harts; i++) { RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i)); @@ -310,6 +316,18 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type) riscv_aclint_mtimer_write(mtimer, mtimer->time_base, 0, 8); } +static const VMStateDescription vmstate_riscv_mtimer = { + .name = "riscv_mtimer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState, + num_harts, 0, + vmstate_info_uint64, uint64_t), + VMSTATE_END_OF_LIST() + } +}; + static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -317,6 +335,7 @@ static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, riscv_aclint_mtimer_properties); ResettableClass *rc = RESETTABLE_CLASS(klass); rc->phases.enter = riscv_aclint_mtimer_reset_enter; + dc->vmsd = &vmstate_riscv_mtimer; } static const TypeInfo riscv_aclint_mtimer_info = { @@ -336,6 +355,7 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size, { int i; DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER); + RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev); assert(num_harts <= RISCV_ACLINT_MAX_HARTS); assert(!(addr & 0x7)); @@ -366,11 +386,11 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size, riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, dev); } - cb->s = RISCV_ACLINT_MTIMER(dev); + cb->s = s; cb->num = i; - env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + s->timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_aclint_mtimer_cb, cb); - env->timecmp = 0; + s->timecmp[i] = 0; qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(DEVICE(rvcpu), IRQ_M_TIMER)); diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c index 8615e4cc1d..4d4d5b50ca 100644 --- a/hw/intc/riscv_imsic.c +++ b/hw/intc/riscv_imsic.c @@ -344,9 +344,11 @@ static void riscv_imsic_realize(DeviceState *dev, Error **errp) /* Force select AIA feature and setup CSR read-modify-write callback */ if (env) { - riscv_set_feature(env, RISCV_FEATURE_AIA); if (!imsic->mmode) { + rcpu->cfg.ext_ssaia = true; riscv_cpu_set_geilen(env, imsic->num_pages - 1); + } else { + rcpu->cfg.ext_smaia = true; } riscv_cpu_set_aia_ireg_rmw_fn(env, (imsic->mmode) ? PRV_M : PRV_S, riscv_imsic_rmw, imsic); diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index 56d60e9ac9..af4ae3630e 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -454,10 +454,10 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, for (i = 0; i < plic->num_addrs; i++) { int cpu_num = plic->addr_config[i].hartid; - CPUState *cpu = qemu_get_cpu(hartid_base + cpu_num); + CPUState *cpu = qemu_get_cpu(cpu_num); if (plic->addr_config[i].mode == PLICMode_M) { - qdev_connect_gpio_out(dev, num_harts + cpu_num, + qdev_connect_gpio_out(dev, num_harts - plic->hartid_base + cpu_num, qdev_get_gpio_in(DEVICE(cpu), IRQ_M_EXT)); } if (plic->addr_config[i].mode == PLICMode_S) { diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 5b0b4d9624..dcd021af66 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -567,8 +567,8 @@ static void ics_reset_irq(ICSIRQState *irq) static void ics_reset(DeviceState *dev) { ICSState *ics = ICS(dev); + g_autofree uint8_t *flags = g_malloc(ics->nr_irqs); int i; - uint8_t flags[ics->nr_irqs]; for (i = 0; i < ics->nr_irqs; i++) { flags[i] = ics->irqs[i].flags; diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c index 9ef9112dd5..d0991ab7f9 100644 --- a/hw/ipmi/smbus_ipmi.c +++ b/hw/ipmi/smbus_ipmi.c @@ -281,7 +281,9 @@ static int ipmi_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len) */ send = true; } - memcpy(sid->inmsg + sid->inlen, buf, len); + if (len > 0) { + memcpy(sid->inmsg + sid->inlen, buf, len); + } sid->inlen += len; break; } diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index a99aa387c3..17d15b6c90 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -2,13 +2,14 @@ config LOONGARCH_VIRT bool select PCI select PCI_EXPRESS_GENERIC_BRIDGE - imply VGA_PCI imply VIRTIO_VGA imply PCI_DEVICES + imply NVDIMM select ISA_BUS select SERIAL select SERIAL_ISA select VIRTIO_PCI + select PLATFORM_BUS select LOONGARCH_IPI select LOONGARCH_PCH_PIC select LOONGARCH_PCH_MSI @@ -17,3 +18,5 @@ config LOONGARCH_VIRT select SMBIOS select ACPI_PCI select ACPI_HW_REDUCED + select FW_CFG_DMA + select DIMM diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c index b95b83b079..378a6d9d38 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -30,6 +30,7 @@ #include "qom/qom-qobject.h" #include "hw/acpi/generic_event_device.h" +#include "hw/pci-host/gpex.h" #define ACPI_BUILD_ALIGN_SIZE 0x1000 #define ACPI_BUILD_TABLE_SIZE 0x20000 @@ -135,7 +136,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams) build_append_int_noprefix(table_data, 21, 1); /* Type */ build_append_int_noprefix(table_data, 19, 1); /* Length */ build_append_int_noprefix(table_data, 1, 1); /* Version */ - build_append_int_noprefix(table_data, LS7A_PCH_MSI_ADDR_LOW, 8);/* Address */ + build_append_int_noprefix(table_data, VIRT_PCH_MSI_ADDR_LOW, 8);/* Address */ build_append_int_noprefix(table_data, 0x40, 4); /* Start */ build_append_int_noprefix(table_data, 0xc0, 4); /* Count */ @@ -143,7 +144,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams) build_append_int_noprefix(table_data, 22, 1); /* Type */ build_append_int_noprefix(table_data, 17, 1); /* Length */ build_append_int_noprefix(table_data, 1, 1); /* Version */ - build_append_int_noprefix(table_data, LS7A_PCH_REG_BASE, 8);/* Address */ + build_append_int_noprefix(table_data, VIRT_PCH_REG_BASE, 8);/* Address */ build_append_int_noprefix(table_data, 0x1000, 2); /* Size */ build_append_int_noprefix(table_data, 0, 2); /* Id */ build_append_int_noprefix(table_data, 0x40, 2); /* Base */ @@ -186,6 +187,12 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) build_srat_memory(table_data, VIRT_HIGHMEM_BASE, machine->ram_size - VIRT_LOWMEM_SIZE, 0, MEM_AFFINITY_ENABLED); + if (ms->device_memory) { + build_srat_memory(table_data, ms->device_memory->base, + memory_region_size(&ms->device_memory->mr), + 0, MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); + } + acpi_table_end(linker, &table); } @@ -200,114 +207,12 @@ struct AcpiBuildState { MemoryRegion *linker_mr; } AcpiBuildState; -static void build_gpex_pci0_int(Aml *table) -{ - Aml *sb_scope = aml_scope("_SB"); - Aml *pci0_scope = aml_scope("PCI0"); - Aml *prt_pkg = aml_varpackage(128); - int slot, pin; - - for (slot = 0; slot < PCI_SLOT_MAX; slot++) { - for (pin = 0; pin < PCI_NUM_PINS; pin++) { - Aml *pkg = aml_package(4); - aml_append(pkg, aml_int((slot << 16) | 0xFFFF)); - aml_append(pkg, aml_int(pin)); - aml_append(pkg, aml_int(0)); - aml_append(pkg, aml_int(80 + (slot + pin) % 4)); - aml_append(prt_pkg, pkg); - } - } - aml_append(pci0_scope, aml_name_decl("_PRT", prt_pkg)); - aml_append(sb_scope, pci0_scope); - aml_append(table, sb_scope); -} - -static void build_dbg_aml(Aml *table) -{ - Aml *field; - Aml *method; - Aml *while_ctx; - Aml *scope = aml_scope("\\"); - Aml *buf = aml_local(0); - Aml *len = aml_local(1); - Aml *idx = aml_local(2); - - aml_append(scope, - aml_operation_region("DBG", AML_SYSTEM_IO, aml_int(0x0402), 0x01)); - field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("DBGB", 8)); - aml_append(scope, field); - - method = aml_method("DBUG", 1, AML_NOTSERIALIZED); - - aml_append(method, aml_to_hexstring(aml_arg(0), buf)); - aml_append(method, aml_to_buffer(buf, buf)); - aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len)); - aml_append(method, aml_store(aml_int(0), idx)); - - while_ctx = aml_while(aml_lless(idx, len)); - aml_append(while_ctx, - aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB"))); - aml_append(while_ctx, aml_increment(idx)); - aml_append(method, while_ctx); - aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB"))); - aml_append(scope, method); - aml_append(table, scope); -} - -static Aml *build_osc_method(void) -{ - Aml *if_ctx; - Aml *if_ctx2; - Aml *else_ctx; - Aml *method; - Aml *a_cwd1 = aml_name("CDW1"); - Aml *a_ctrl = aml_local(0); - - method = aml_method("_OSC", 4, AML_NOTSERIALIZED); - aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); - - if_ctx = aml_if(aml_equal( - aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"))); - aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); - aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); - aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl)); - - /* - * Always allow native PME, AER (no dependencies) - * Allow SHPC (PCI bridges can have SHPC controller) - */ - aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); - - if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1)))); - /* Unknown revision */ - aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1)); - aml_append(if_ctx, if_ctx2); - - if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); - /* Capabilities bits were masked */ - aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1)); - aml_append(if_ctx, if_ctx2); - - /* Update DWORD3 in the buffer */ - aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3"))); - aml_append(method, if_ctx); - - else_ctx = aml_else(); - /* Unrecognized UUID */ - aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1)); - aml_append(method, else_ctx); - - aml_append(method, aml_return(aml_arg(3))); - return method; -} - static void build_uart_device_aml(Aml *table) { Aml *dev; Aml *crs; Aml *pkg0, *pkg1, *pkg2; - uint32_t uart_irq = LS7A_UART_IRQ; + uint32_t uart_irq = VIRT_UART_IRQ; Aml *scope = aml_scope("_SB"); dev = aml_device("COMA"); @@ -335,61 +240,55 @@ static void build_uart_device_aml(Aml *table) aml_append(table, scope); } +static void +build_la_ged_aml(Aml *dsdt, MachineState *machine) +{ + uint32_t event; + LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); + + build_ged_aml(dsdt, "\\_SB."GED_DEVICE, + HOTPLUG_HANDLER(lams->acpi_ged), + VIRT_SCI_IRQ, AML_SYSTEM_MEMORY, + VIRT_GED_EVT_ADDR); + event = object_property_get_uint(OBJECT(lams->acpi_ged), + "ged-event", &error_abort); + if (event & ACPI_GED_MEM_HOTPLUG_EVT) { + build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL, + AML_SYSTEM_MEMORY, + VIRT_GED_MEM_ADDR); + } +} + +static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams) +{ + struct GPEXConfig cfg = { + .mmio64.base = VIRT_PCI_MEM_BASE, + .mmio64.size = VIRT_PCI_MEM_SIZE, + .pio.base = VIRT_PCI_IO_BASE, + .pio.size = VIRT_PCI_IO_SIZE, + .ecam.base = VIRT_PCI_CFG_BASE, + .ecam.size = VIRT_PCI_CFG_SIZE, + .irq = PCH_PIC_IRQ_OFFSET + VIRT_DEVICE_IRQS, + .bus = lams->pci_bus, + }; + + acpi_dsdt_add_gpex(scope, &cfg); +} + /* build DSDT */ static void build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) { - Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg; - int root_bus_limit = 0x7F; + Aml *dsdt, *scope, *pkg; LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id, .oem_table_id = lams->oem_table_id }; acpi_table_begin(&table, table_data); - dsdt = init_aml_allocator(); - - build_dbg_aml(dsdt); - - sb_scope = aml_scope("_SB"); - dev = aml_device("PCI0"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); - aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); - aml_append(dev, aml_name_decl("_ADR", aml_int(0))); - aml_append(dev, aml_name_decl("_BBN", aml_int(0))); - aml_append(dev, aml_name_decl("_UID", aml_int(1))); - aml_append(dev, build_osc_method()); - aml_append(sb_scope, dev); - aml_append(dsdt, sb_scope); - - build_gpex_pci0_int(dsdt); build_uart_device_aml(dsdt); - if (lams->acpi_ged) { - build_ged_aml(dsdt, "\\_SB."GED_DEVICE, - HOTPLUG_HANDLER(lams->acpi_ged), - LS7A_SCI_IRQ - PCH_PIC_IRQ_OFFSET, AML_SYSTEM_MEMORY, - VIRT_GED_EVT_ADDR); - } - - scope = aml_scope("\\_SB.PCI0"); - /* Build PCI0._CRS */ - crs = aml_resource_template(); - aml_append(crs, - aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, - 0x0000, 0x0, root_bus_limit, - 0x0000, root_bus_limit + 1)); - aml_append(crs, - aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED, - AML_POS_DECODE, AML_ENTIRE_RANGE, - 0x0000, 0x0000, 0xFFFF, 0x18000000, 0x10000)); - aml_append(crs, - aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, - AML_CACHEABLE, AML_READ_WRITE, - 0, LS7A_PCI_MEM_BASE, - LS7A_PCI_MEM_BASE + LS7A_PCI_MEM_SIZE - 1, - 0, LS7A_PCI_MEM_BASE)); - aml_append(scope, aml_name_decl("_CRS", crs)); - aml_append(dsdt, scope); + build_pci_device_aml(dsdt, lams); + build_la_ged_aml(dsdt, machine); /* System State Package */ scope = aml_scope("\\"); @@ -411,9 +310,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); GArray *table_offsets; AcpiFadtData fadt_data; - unsigned facs, rsdt, fadt, dsdt; + unsigned facs, rsdt, dsdt; uint8_t *u; - size_t aml_len = 0; GArray *tables_blob = tables->table_data; init_common_fadt_data(&fadt_data); @@ -437,21 +335,13 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) dsdt = tables_blob->len; build_dsdt(tables_blob, tables->linker, machine); - /* - * Count the size of the DSDT, we will need it for - * legacy sizing of ACPI tables. - */ - aml_len += tables_blob->len - dsdt; - /* ACPI tables pointed to by RSDT */ - fadt = tables_blob->len; acpi_add_table(table_offsets, tables_blob); fadt_data.facs_tbl_offset = &facs; fadt_data.dsdt_tbl_offset = &dsdt; fadt_data.xdsdt_tbl_offset = &dsdt; build_fadt(tables_blob, tables->linker, &fadt_data, lams->oem_id, lams->oem_table_id); - aml_len += tables_blob->len - fadt; acpi_add_table(table_offsets, tables_blob); build_madt(tables_blob, tables->linker, lams); @@ -462,8 +352,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(table_offsets, tables_blob); { AcpiMcfgInfo mcfg = { - .base = cpu_to_le64(LS_PCIECFG_BASE), - .size = cpu_to_le64(LS_PCIECFG_SIZE), + .base = cpu_to_le64(VIRT_PCI_CFG_BASE), + .size = cpu_to_le64(VIRT_PCI_CFG_SIZE), }; build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id, lams->oem_table_id); diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c index f6503d5607..f15a17416c 100644 --- a/hw/loongarch/fw_cfg.c +++ b/hw/loongarch/fw_cfg.c @@ -23,7 +23,8 @@ FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms) int max_cpus = ms->smp.max_cpus; int smp_cpus = ms->smp.cpus; - fw_cfg = fw_cfg_init_mem_wide(VIRT_FWCFG_BASE + 8, VIRT_FWCFG_BASE, 8, 0, NULL); + fw_cfg = fw_cfg_init_mem_wide(VIRT_FWCFG_BASE + 8, VIRT_FWCFG_BASE, 8, + VIRT_FWCFG_BASE + 16, &address_space_memory); fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build index 6a2a1b18e5..c0421502ab 100644 --- a/hw/loongarch/meson.build +++ b/hw/loongarch/meson.build @@ -2,7 +2,7 @@ loongarch_ss = ss.source_set() loongarch_ss.add(files( 'fw_cfg.c', )) -loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: [files('loongson3.c'), fdt]) +loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: [files('virt.c'), fdt]) loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c')) hw_arch += {'loongarch': loongarch_ss} diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/virt.c similarity index 72% rename from hw/loongarch/loongson3.c rename to hw/loongarch/virt.c index a08dc9d299..29df99727d 100644 --- a/hw/loongarch/loongson3.c +++ b/hw/loongarch/virt.c @@ -37,6 +37,10 @@ #include "hw/mem/nvdimm.h" #include "sysemu/device_tree.h" #include +#include "hw/core/sysbus-fdt.h" +#include "hw/platform-bus.h" +#include "hw/display/ramfb.h" +#include "hw/mem/pc-dimm.h" static void create_fdt(LoongArchMachineState *lams) { @@ -118,7 +122,7 @@ static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams) qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "qemu,fw-cfg-mmio"); qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", - 2, base, 2, 0x8); + 2, base, 2, 0x18); qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); g_free(nodename); } @@ -126,12 +130,12 @@ static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams) static void fdt_add_pcie_node(const LoongArchMachineState *lams) { char *nodename; - hwaddr base_mmio = LS7A_PCI_MEM_BASE; - hwaddr size_mmio = LS7A_PCI_MEM_SIZE; - hwaddr base_pio = LS7A_PCI_IO_BASE; - hwaddr size_pio = LS7A_PCI_IO_SIZE; - hwaddr base_pcie = LS_PCIECFG_BASE; - hwaddr size_pcie = LS_PCIECFG_SIZE; + hwaddr base_mmio = VIRT_PCI_MEM_BASE; + hwaddr size_mmio = VIRT_PCI_MEM_SIZE; + hwaddr base_pio = VIRT_PCI_IO_BASE; + hwaddr size_pio = VIRT_PCI_IO_SIZE; + hwaddr base_pcie = VIRT_PCI_CFG_BASE; + hwaddr size_pcie = VIRT_PCI_CFG_SIZE; hwaddr base = base_pcie; const MachineState *ms = MACHINE(lams); @@ -145,12 +149,12 @@ static void fdt_add_pcie_node(const LoongArchMachineState *lams) qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2); qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0); qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0, - PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1)); + PCIE_MMCFG_BUS(VIRT_PCI_CFG_SIZE - 1)); qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base_pcie, 2, size_pcie); qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges", - 1, FDT_PCI_RANGE_IOPORT, 2, LS7A_PCI_IO_OFFSET, + 1, FDT_PCI_RANGE_IOPORT, 2, VIRT_PCI_IO_OFFSET, 2, base_pio, 2, size_pio, 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, 2, base_mmio, 2, size_mmio); @@ -158,6 +162,33 @@ static void fdt_add_pcie_node(const LoongArchMachineState *lams) qemu_fdt_dumpdtb(ms->fdt, lams->fdt_size); } +static void fdt_add_irqchip_node(LoongArchMachineState *lams) +{ + MachineState *ms = MACHINE(lams); + char *nodename; + uint32_t irqchip_phandle; + + irqchip_phandle = qemu_fdt_alloc_phandle(ms->fdt); + qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", irqchip_phandle); + + nodename = g_strdup_printf("/intc@%lx", VIRT_IOAPIC_REG_BASE); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3); + qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2); + qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0); + + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", + "loongarch,ls7a"); + + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", + 2, VIRT_IOAPIC_REG_BASE, + 2, PCH_PIC_ROUTE_ENTRY_OFFSET); + + qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", irqchip_phandle); + g_free(nodename); +} #define PM_BASE 0x10080000 #define PM_SIZE 0x100 @@ -313,11 +344,36 @@ static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_GED_REG_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, - qdev_get_gpio_in(pch_pic, LS7A_SCI_IRQ - PCH_PIC_IRQ_OFFSET)); + qdev_get_gpio_in(pch_pic, VIRT_SCI_IRQ - PCH_PIC_IRQ_OFFSET)); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); return dev; } +static DeviceState *create_platform_bus(DeviceState *pch_pic) +{ + DeviceState *dev; + SysBusDevice *sysbus; + int i, irq; + MemoryRegion *sysmem = get_system_memory(); + + dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); + dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); + qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS); + qdev_prop_set_uint32(dev, "mmio_size", VIRT_PLATFORM_BUS_SIZE); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + sysbus = SYS_BUS_DEVICE(dev); + for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) { + irq = VIRT_PLATFORM_BUS_IRQ - PCH_PIC_IRQ_OFFSET + i; + sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(pch_pic, irq)); + } + + memory_region_add_subregion(sysmem, + VIRT_PLATFORM_BUS_BASEADDRESS, + sysbus_mmio_get_region(sysbus, 0)); + return dev; +} + static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState *lams) { DeviceState *gpex_dev; @@ -331,29 +387,30 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * d = SYS_BUS_DEVICE(gpex_dev); sysbus_realize_and_unref(d, &error_fatal); pci_bus = PCI_HOST_BRIDGE(gpex_dev)->bus; + lams->pci_bus = pci_bus; /* Map only part size_ecam bytes of ECAM space */ ecam_alias = g_new0(MemoryRegion, 1); ecam_reg = sysbus_mmio_get_region(d, 0); memory_region_init_alias(ecam_alias, OBJECT(gpex_dev), "pcie-ecam", - ecam_reg, 0, LS_PCIECFG_SIZE); - memory_region_add_subregion(get_system_memory(), LS_PCIECFG_BASE, + ecam_reg, 0, VIRT_PCI_CFG_SIZE); + memory_region_add_subregion(get_system_memory(), VIRT_PCI_CFG_BASE, ecam_alias); /* Map PCI mem space */ mmio_alias = g_new0(MemoryRegion, 1); mmio_reg = sysbus_mmio_get_region(d, 1); memory_region_init_alias(mmio_alias, OBJECT(gpex_dev), "pcie-mmio", - mmio_reg, LS7A_PCI_MEM_BASE, LS7A_PCI_MEM_SIZE); - memory_region_add_subregion(get_system_memory(), LS7A_PCI_MEM_BASE, + mmio_reg, VIRT_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE); + memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias); /* Map PCI IO port space. */ pio_alias = g_new0(MemoryRegion, 1); pio_reg = sysbus_mmio_get_region(d, 2); memory_region_init_alias(pio_alias, OBJECT(gpex_dev), "pcie-io", pio_reg, - LS7A_PCI_IO_OFFSET, LS7A_PCI_IO_SIZE); - memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE, + VIRT_PCI_IO_OFFSET, VIRT_PCI_IO_SIZE); + memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias); for (i = 0; i < GPEX_NUM_IRQS; i++) { @@ -362,9 +419,9 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i); } - serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0, + serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0, qdev_get_gpio_in(pch_pic, - LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET), + VIRT_UART_IRQ - PCH_PIC_IRQ_OFFSET), 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); /* Network init */ @@ -378,17 +435,14 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * pci_nic_init_nofail(nd, pci_bus, nd->model, NULL); } - /* VGA setup */ - pci_vga_init(pci_bus); - /* * There are some invalid guest memory access. * Create some unimplemented devices to emulate this. */ create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4); - sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE, + sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE, qdev_get_gpio_in(pch_pic, - LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET)); + VIRT_RTC_IRQ - PCH_PIC_IRQ_OFFSET)); pm_mem = g_new(MemoryRegion, 1); memory_region_init_io(pm_mem, NULL, &loongarch_virt_pm_ops, @@ -396,6 +450,8 @@ static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState * memory_region_add_subregion(get_system_memory(), PM_BASE, pm_mem); /* acpi ged */ lams->acpi_ged = create_acpi_ged(pch_pic, lams); + /* platform bus */ + lams->platform_bus_dev = create_platform_bus(pch_pic); } static void loongarch_irq_init(LoongArchMachineState *lams) @@ -472,13 +528,13 @@ static void loongarch_irq_init(LoongArchMachineState *lams) pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); d = SYS_BUS_DEVICE(pch_pic); sysbus_realize_and_unref(d, &error_fatal); - memory_region_add_subregion(get_system_memory(), LS7A_IOAPIC_REG_BASE, + memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, sysbus_mmio_get_region(d, 0)); memory_region_add_subregion(get_system_memory(), - LS7A_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, + VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, sysbus_mmio_get_region(d, 1)); memory_region_add_subregion(get_system_memory(), - LS7A_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, + VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, sysbus_mmio_get_region(d, 2)); /* Connect 64 pch_pic irqs to extioi */ @@ -490,7 +546,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) qdev_prop_set_uint32(pch_msi, "msi_irq_base", PCH_MSI_IRQ_START); d = SYS_BUS_DEVICE(pch_msi); sysbus_realize_and_unref(d, &error_fatal); - sysbus_mmio_map(d, 0, LS7A_PCH_MSI_ADDR_LOW); + sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW); for (i = 0; i < PCH_MSI_IRQ_NUM; i++) { /* Connect 192 pch_msi irqs to extioi */ qdev_connect_gpio_out(DEVICE(d), i, @@ -664,10 +720,39 @@ static void loongarch_init(MachineState *machine) machine->ram, offset, highram_size); memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem); memmap_add_entry(0x90000000, highram_size, 1); + + /* initialize device memory address space */ + if (machine->ram_size < machine->maxram_size) { + machine->device_memory = g_malloc0(sizeof(*machine->device_memory)); + ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size; + + if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) { + error_report("unsupported amount of memory slots: %"PRIu64, + machine->ram_slots); + exit(EXIT_FAILURE); + } + + if (QEMU_ALIGN_UP(machine->maxram_size, + TARGET_PAGE_SIZE) != machine->maxram_size) { + error_report("maximum memory size must by aligned to multiple of " + "%d bytes", TARGET_PAGE_SIZE); + exit(EXIT_FAILURE); + } + /* device memory base is the top of high memory address. */ + machine->device_memory->base = 0x90000000 + highram_size; + machine->device_memory->base = + ROUND_UP(machine->device_memory->base, 1 * GiB); + + memory_region_init(&machine->device_memory->mr, OBJECT(lams), + "device-memory", device_mem_size); + memory_region_add_subregion(address_space_mem, machine->device_memory->base, + &machine->device_memory->mr); + } + /* Add isa io region */ memory_region_init_alias(&lams->isa_io, NULL, "isa-io", - get_system_io(), 0, LOONGARCH_ISA_IO_SIZE); - memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE, + get_system_io(), 0, VIRT_ISA_IO_SIZE); + memory_region_add_subregion(address_space_mem, VIRT_ISA_IO_BASE, &lams->isa_io); /* load the BIOS image. */ loongarch_firmware_init(lams); @@ -700,15 +785,20 @@ static void loongarch_init(MachineState *machine) } /* Initialize the IO interrupt subsystem */ loongarch_irq_init(lams); + fdt_add_irqchip_node(lams); + platform_bus_add_all_fdt_nodes(machine->fdt, "/intc", + VIRT_PLATFORM_BUS_BASEADDRESS, + VIRT_PLATFORM_BUS_SIZE, + VIRT_PLATFORM_BUS_IRQ); lams->machine_done.notify = virt_machine_done; qemu_add_machine_init_done_notifier(&lams->machine_done); fdt_add_pcie_node(lams); /* load fdt */ MemoryRegion *fdt_rom = g_new(MemoryRegion, 1); - memory_region_init_rom(fdt_rom, NULL, "fdt", LA_FDT_SIZE, &error_fatal); - memory_region_add_subregion(get_system_memory(), LA_FDT_BASE, fdt_rom); - rom_add_blob_fixed("fdt", machine->fdt, lams->fdt_size, LA_FDT_BASE); + memory_region_init_rom(fdt_rom, NULL, "fdt", VIRT_FDT_SIZE, &error_fatal); + memory_region_add_subregion(get_system_memory(), VIRT_FDT_BASE, fdt_rom); + rom_add_blob_fixed("fdt", machine->fdt, lams->fdt_size, VIRT_FDT_BASE); } bool loongarch_is_acpi_enabled(LoongArchMachineState *lams) @@ -745,9 +835,105 @@ static void loongarch_machine_initfn(Object *obj) lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); } +static bool memhp_type_supported(DeviceState *dev) +{ + /* we only support pc dimm now */ + return object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && + !object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); +} + +static void virt_mem_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp); +} + +static void virt_machine_device_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (memhp_type_supported(dev)) { + virt_mem_pre_plug(hotplug_dev, dev, errp); + } +} + +static void virt_mem_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); + + /* the acpi ged is always exist */ + hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev, + errp); +} + +static void virt_machine_device_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (memhp_type_supported(dev)) { + virt_mem_unplug_request(hotplug_dev, dev, errp); + } +} + +static void virt_mem_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); + + hotplug_handler_unplug(HOTPLUG_HANDLER(lams->acpi_ged), dev, errp); + pc_dimm_unplug(PC_DIMM(dev), MACHINE(lams)); + qdev_unrealize(dev); +} + +static void virt_machine_device_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (memhp_type_supported(dev)) { + virt_mem_unplug(hotplug_dev, dev, errp); + } +} + +static void virt_mem_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); + + pc_dimm_plug(PC_DIMM(dev), MACHINE(lams)); + hotplug_handler_plug(HOTPLUG_HANDLER(lams->acpi_ged), + dev, &error_abort); +} + +static void loongarch_machine_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev); + MachineClass *mc = MACHINE_GET_CLASS(lams); + + if (device_is_dynamic_sysbus(mc, dev)) { + if (lams->platform_bus_dev) { + platform_bus_link_device(PLATFORM_BUS_DEVICE(lams->platform_bus_dev), + SYS_BUS_DEVICE(dev)); + } + } else if (memhp_type_supported(dev)) { + virt_mem_plug(hotplug_dev, dev, errp); + } +} + +static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, + DeviceState *dev) +{ + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (device_is_dynamic_sysbus(mc, dev) || + memhp_type_supported(dev)) { + return HOTPLUG_HANDLER(machine); + } + return NULL; +} + static void loongarch_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); mc->desc = "Loongson-3A5000 LS7A1000 machine"; mc->init = loongarch_init; @@ -760,12 +946,18 @@ static void loongarch_class_init(ObjectClass *oc, void *data) mc->block_default_type = IF_VIRTIO; mc->default_boot_order = "c"; mc->no_cdrom = 1; + mc->get_hotplug_handler = virt_machine_get_hotplug_handler; + hc->plug = loongarch_machine_device_plug_cb; + hc->pre_plug = virt_machine_device_pre_plug; + hc->unplug_request = virt_machine_device_unplug_request; + hc->unplug = virt_machine_device_unplug; object_class_property_add(oc, "acpi", "OnOffAuto", loongarch_get_acpi, loongarch_set_acpi, NULL, NULL); object_class_property_set_description(oc, "acpi", "Enable ACPI"); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); } static const TypeInfo loongarch_machine_types[] = { @@ -775,6 +967,10 @@ static const TypeInfo loongarch_machine_types[] = { .instance_size = sizeof(LoongArchMachineState), .class_init = loongarch_class_init, .instance_init = loongarch_machine_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, } }; diff --git a/hw/m68k/bootinfo.h b/hw/m68k/bootinfo.h index bd8b212fd3..897162b818 100644 --- a/hw/m68k/bootinfo.h +++ b/hw/m68k/bootinfo.h @@ -48,13 +48,14 @@ stw_phys(as, base, id); \ base += 2; \ stw_phys(as, base, \ - (sizeof(struct bi_record) + strlen(string) + 2) & ~1); \ + (sizeof(struct bi_record) + strlen(string) + \ + 1 /* null termination */ + 3 /* padding */) & ~3); \ base += 2; \ for (i = 0; string[i]; i++) { \ stb_phys(as, base++, string[i]); \ } \ stb_phys(as, base++, 0); \ - base = (base + 1) & ~1; \ + base = (base + 3) & ~3; \ } while (0) #define BOOTINFODATA(as, base, id, data, len) \ @@ -63,13 +64,14 @@ stw_phys(as, base, id); \ base += 2; \ stw_phys(as, base, \ - (sizeof(struct bi_record) + len + 3) & ~1); \ + (sizeof(struct bi_record) + len + \ + 2 /* length field */ + 3 /* padding */) & ~3); \ base += 2; \ stw_phys(as, base, len); \ base += 2; \ for (i = 0; i < len; ++i) { \ stb_phys(as, base++, data[i]); \ } \ - base = (base + 1) & ~1; \ + base = (base + 3) & ~3; \ } while (0) #endif diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 0aa383fa6b..2f3ffc0de6 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -173,6 +173,7 @@ static void virt_init(MachineState *machine) io_base = VIRT_GF_RTC_MMIO_BASE; for (i = 0; i < VIRT_GF_RTC_NB; i++) { dev = qdev_new(TYPE_GOLDFISH_RTC); + qdev_prop_set_bit(dev, "big-endian", true); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, io_base); @@ -322,10 +323,17 @@ type_init(virt_machine_register_types) } \ type_init(machvirt_machine_##major##_##minor##_init); -static void virt_machine_7_1_options(MachineClass *mc) +static void virt_machine_7_2_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE(7, 1, true) +DEFINE_VIRT_MACHINE(7, 2, true) + +static void virt_machine_7_1_options(MachineClass *mc) +{ + virt_machine_7_2_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len); +} +DEFINE_VIRT_MACHINE(7, 1, false) static void virt_machine_7_0_options(MachineClass *mc) { diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 3bf2869573..a71bf1afeb 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -14,6 +14,12 @@ #include "sysemu/hostmem.h" #include "hw/cxl/cxl.h" +/* + * Null value of all Fs suggested by IEEE RA guidelines for use of + * EU, OUI and CID + */ +#define UI64_NULL ~(0ULL) + static void build_dvsecs(CXLType3Dev *ct3d) { CXLComponentState *cxl_cstate = &ct3d->cxl_cstate; @@ -49,7 +55,7 @@ static void build_dvsecs(CXLType3Dev *ct3d) .phase2_power = 0x33, /* 0x33 miliwatts */ }; cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE, - GPF_DEVICE_DVSEC_LENGTH, GPF_PORT_DVSEC, + GPF_DEVICE_DVSEC_LENGTH, GPF_DEVICE_DVSEC, GPF_DEVICE_DVSEC_REVID, dvsec); } @@ -149,7 +155,12 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_CXL); pcie_endpoint_cap_init(pci_dev, 0x80); - cxl_cstate->dvsec_offset = 0x100; + if (ct3d->sn != UI64_NULL) { + pcie_dev_ser_num_init(pci_dev, 0x100, ct3d->sn); + cxl_cstate->dvsec_offset = 0x100 + 0x0c; + } else { + cxl_cstate->dvsec_offset = 0x100; + } ct3d->cxl_cstate.pdev = pci_dev; build_dvsecs(ct3d); @@ -275,6 +286,7 @@ static Property ct3_props[] = { HostMemoryBackend *), DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND, HostMemoryBackend *), + DEFINE_PROP_UINT64("sn", CXLType3Dev, sn, UI64_NULL), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index 8b92a9801a..25ad54754e 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -30,6 +30,7 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "sysemu/device_tree.h" #include "sysemu/reset.h" #include "hw/boards.h" @@ -75,6 +76,7 @@ static int microblaze_load_dtb(hwaddr addr, int fdt_size; void *fdt = NULL; int r; + uint8_t rng_seed[32]; if (dtb_filename) { fdt = load_device_tree(dtb_filename, &fdt_size); @@ -83,6 +85,9 @@ static int microblaze_load_dtb(hwaddr addr, return 0; } + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + if (kernel_cmdline) { r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 7a0ec513b0..0e932988e0 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1442,6 +1442,14 @@ static const TypeInfo mips_malta_device = { .instance_init = mips_malta_instance_init, }; +GlobalProperty malta_compat[] = { + { "PIIX4_PM", "memory-hotplug-support", "off" }, + { "PIIX4_PM", "acpi-pci-hotplug-with-bridge-support", "off" }, + { "PIIX4_PM", "acpi-root-pci-hotplug", "off" }, + { "PIIX4_PM", "x-not-migrate-acpi-index", "true" }, +}; +const size_t malta_compat_len = G_N_ELEMENTS(malta_compat); + static void mips_malta_machine_init(MachineClass *mc) { mc->desc = "MIPS Malta Core LV"; @@ -1455,6 +1463,7 @@ static void mips_malta_machine_init(MachineClass *mc) mc->default_cpu_type = MIPS_CPU_TYPE_NAME("24Kf"); #endif mc->default_ram_id = "mips_malta.ram"; + compat_props_add(mc->compat_props, malta_compat, malta_compat_len); } DEFINE_MACHINE("malta", mips_malta_machine_init) diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index e94e951057..890ae7bae5 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -270,6 +270,10 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) stl_le_phys(&s->dma_as, value + 12, 0); resplen = 4; break; + case 0x00040013: /* Get number of displays */ + stl_le_phys(&s->dma_as, value + 12, 1); + resplen = 4; + break; case 0x00060001: /* Get DMA channels */ /* channels 2-5 */ diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c index 43e001c3c7..5b05f15859 100644 --- a/hw/misc/grlib_ahb_apb_pnp.c +++ b/hw/misc/grlib_ahb_apb_pnp.c @@ -136,7 +136,8 @@ static uint64_t grlib_ahb_pnp_read(void *opaque, hwaddr offset, unsigned size) uint32_t val; val = ahb_pnp->regs[offset >> 2]; - trace_grlib_ahb_pnp_read(offset, val); + val = extract32(val, (4 - (offset & 3) - size) * 8, size * 8); + trace_grlib_ahb_pnp_read(offset, size, val); return val; } @@ -152,7 +153,7 @@ static const MemoryRegionOps grlib_ahb_pnp_ops = { .write = grlib_ahb_pnp_write, .endianness = DEVICE_BIG_ENDIAN, .impl = { - .min_access_size = 4, + .min_access_size = 1, .max_access_size = 4, }, }; @@ -247,7 +248,8 @@ static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size) uint32_t val; val = apb_pnp->regs[offset >> 2]; - trace_grlib_apb_pnp_read(offset, val); + val = extract32(val, (4 - (offset & 3) - size) * 8, size * 8); + trace_grlib_apb_pnp_read(offset, size, val); return val; } @@ -263,7 +265,7 @@ static const MemoryRegionOps grlib_apb_pnp_ops = { .write = grlib_apb_pnp_write, .endianness = DEVICE_BIG_ENDIAN, .impl = { - .min_access_size = 4, + .min_access_size = 1, .max_access_size = 4, }, }; diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c index 7b41cfa8fc..b5a9e30a2c 100644 --- a/hw/misc/iotkit-secctl.c +++ b/hw/misc/iotkit-secctl.c @@ -114,7 +114,7 @@ static const uint8_t iotkit_secctl_ns_sse300_idregs[] = { * AHB expansion, APB expansion) are all set up so that they are * in 16-aligned blocks so offsets 0xN0, 0xN4, 0xN8, 0xNC are PPCs * 0, 1, 2, 3 of that type, so we can convert a register address offset - * into an an index into a PPC array easily. + * into an index into a PPC array easily. */ static inline int offset_to_ppc_idx(uint32_t offset) { diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c index 9ee8fe8495..7147e2f84e 100644 --- a/hw/misc/iotkit-sysctl.c +++ b/hw/misc/iotkit-sysctl.c @@ -237,7 +237,7 @@ static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset, r = s->ewctrl; break; case ARMSSE_SSE300: - /* In SSE300 this offset is is NMI_ENABLE */ + /* In SSE300 this offset is NMI_ENABLE */ r = s->nmi_enable; break; default: @@ -555,7 +555,7 @@ static void iotkit_sysctl_write(void *opaque, hwaddr offset, s->ewctrl = value; break; case ARMSSE_SSE300: - /* In SSE300 this offset is is NMI_ENABLE */ + /* In SSE300 this offset is NMI_ENABLE */ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl NMI_ENABLE unimplemented\n"); s->nmi_enable = value; break; diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index fba85a53d7..f42c12755a 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -587,7 +587,7 @@ static void adb_via_poll(void *opaque) /* * For older Linux kernels that switch to IDLE mode after sending the * ADB command, detect if there is an existing response and return that - * as a a "fake" autopoll reply or bus timeout accordingly + * as a "fake" autopoll reply or bus timeout accordingly */ *data = v1s->adb_data_out[0]; olen = v1s->adb_data_in_size; diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c index f9e646350e..fe38c44426 100644 --- a/hw/misc/mos6522.c +++ b/hw/misc/mos6522.c @@ -595,7 +595,7 @@ void hmp_info_via(Monitor *mon, const QDict *qdict) if (hmp_handle_error(mon, err)) { return; } - monitor_printf(mon, "%s", info->human_readable_text); + monitor_puts(mon, info->human_readable_text); } static const MemoryRegionOps mos6522_ops = { diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 4d51a80de1..c18bc0605e 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -247,8 +247,8 @@ via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size via1_auxmode(int mode) "setting auxmode to %d" # grlib_ahb_apb_pnp.c -grlib_ahb_pnp_read(uint64_t addr, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" data:0x%08x" -grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx64" data:0x%08x" +grlib_ahb_pnp_read(uint64_t addr, unsigned size, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" size:%u data:0x%08x" +grlib_apb_pnp_read(uint64_t addr, unsigned size, uint32_t value) "APB PnP read addr:0x%03"PRIx64" size:%u data:0x%08x" # led.c led_set_intensity(const char *color, const char *desc, uint8_t intensity_percent) "LED desc:'%s' color:%s intensity: %u%%" diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c index 82ac48cee2..e93e6c5e19 100644 --- a/hw/net/can/xlnx-zynqmp-can.c +++ b/hw/net/can/xlnx-zynqmp-can.c @@ -696,30 +696,30 @@ static void update_rx_fifo(XlnxZynqMPCANState *s, const qemu_can_frame *frame) timestamp)); /* First 32 bit of the data. */ - fifo32_push(&s->rx_fifo, deposit32(0, R_TXFIFO_DATA1_DB3_SHIFT, - R_TXFIFO_DATA1_DB3_LENGTH, + fifo32_push(&s->rx_fifo, deposit32(0, R_RXFIFO_DATA1_DB3_SHIFT, + R_RXFIFO_DATA1_DB3_LENGTH, frame->data[0]) | - deposit32(0, R_TXFIFO_DATA1_DB2_SHIFT, - R_TXFIFO_DATA1_DB2_LENGTH, + deposit32(0, R_RXFIFO_DATA1_DB2_SHIFT, + R_RXFIFO_DATA1_DB2_LENGTH, frame->data[1]) | - deposit32(0, R_TXFIFO_DATA1_DB1_SHIFT, - R_TXFIFO_DATA1_DB1_LENGTH, + deposit32(0, R_RXFIFO_DATA1_DB1_SHIFT, + R_RXFIFO_DATA1_DB1_LENGTH, frame->data[2]) | - deposit32(0, R_TXFIFO_DATA1_DB0_SHIFT, - R_TXFIFO_DATA1_DB0_LENGTH, + deposit32(0, R_RXFIFO_DATA1_DB0_SHIFT, + R_RXFIFO_DATA1_DB0_LENGTH, frame->data[3])); /* Last 32 bit of the data. */ - fifo32_push(&s->rx_fifo, deposit32(0, R_TXFIFO_DATA2_DB7_SHIFT, - R_TXFIFO_DATA2_DB7_LENGTH, + fifo32_push(&s->rx_fifo, deposit32(0, R_RXFIFO_DATA2_DB7_SHIFT, + R_RXFIFO_DATA2_DB7_LENGTH, frame->data[4]) | - deposit32(0, R_TXFIFO_DATA2_DB6_SHIFT, - R_TXFIFO_DATA2_DB6_LENGTH, + deposit32(0, R_RXFIFO_DATA2_DB6_SHIFT, + R_RXFIFO_DATA2_DB6_LENGTH, frame->data[5]) | - deposit32(0, R_TXFIFO_DATA2_DB5_SHIFT, - R_TXFIFO_DATA2_DB5_LENGTH, + deposit32(0, R_RXFIFO_DATA2_DB5_SHIFT, + R_RXFIFO_DATA2_DB5_LENGTH, frame->data[6]) | - deposit32(0, R_TXFIFO_DATA2_DB4_SHIFT, - R_TXFIFO_DATA2_DB4_LENGTH, + deposit32(0, R_RXFIFO_DATA2_DB4_SHIFT, + R_RXFIFO_DATA2_DB4_LENGTH, frame->data[7])); ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 1); diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 208e3e0d79..fc9cdb4528 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -1364,6 +1364,57 @@ struct NetRxPkt *pkt, const E1000E_RSSInfo *rss_info, } } +static inline void +e1000e_pci_dma_write_rx_desc(E1000ECore *core, dma_addr_t addr, + uint8_t *desc, dma_addr_t len) +{ + PCIDevice *dev = core->owner; + + if (e1000e_rx_use_legacy_descriptor(core)) { + struct e1000_rx_desc *d = (struct e1000_rx_desc *) desc; + size_t offset = offsetof(struct e1000_rx_desc, status); + uint8_t status = d->status; + + d->status &= ~E1000_RXD_STAT_DD; + pci_dma_write(dev, addr, desc, len); + + if (status & E1000_RXD_STAT_DD) { + d->status = status; + pci_dma_write(dev, addr + offset, &status, sizeof(status)); + } + } else { + if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) { + union e1000_rx_desc_packet_split *d = + (union e1000_rx_desc_packet_split *) desc; + size_t offset = offsetof(union e1000_rx_desc_packet_split, + wb.middle.status_error); + uint32_t status = d->wb.middle.status_error; + + d->wb.middle.status_error &= ~E1000_RXD_STAT_DD; + pci_dma_write(dev, addr, desc, len); + + if (status & E1000_RXD_STAT_DD) { + d->wb.middle.status_error = status; + pci_dma_write(dev, addr + offset, &status, sizeof(status)); + } + } else { + union e1000_rx_desc_extended *d = + (union e1000_rx_desc_extended *) desc; + size_t offset = offsetof(union e1000_rx_desc_extended, + wb.upper.status_error); + uint32_t status = d->wb.upper.status_error; + + d->wb.upper.status_error &= ~E1000_RXD_STAT_DD; + pci_dma_write(dev, addr, desc, len); + + if (status & E1000_RXD_STAT_DD) { + d->wb.upper.status_error = status; + pci_dma_write(dev, addr + offset, &status, sizeof(status)); + } + } + } +} + typedef struct e1000e_ba_state_st { uint16_t written[MAX_PS_BUFFERS]; uint8_t cur_idx; @@ -1600,7 +1651,7 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, e1000e_write_rx_descr(core, desc, is_last ? core->rx_pkt : NULL, rss_info, do_ps ? ps_hdr_len : 0, &bastate.written); - pci_dma_write(d, base, &desc, core->rx_desc_len); + e1000e_pci_dma_write_rx_desc(core, base, desc, core->rx_desc_len); e1000e_ring_advance(core, rxi, core->rx_desc_len / E1000_MIN_RX_DESC_LEN); @@ -1622,15 +1673,16 @@ e1000e_rx_fix_l4_csum(E1000ECore *core, struct NetRxPkt *pkt) } } +/* Min. octets in an ethernet frame sans FCS */ +#define MIN_BUF_SIZE 60 + ssize_t e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt) { static const int maximum_ethernet_hdr_len = (14 + 4); - /* Min. octets in an ethernet frame sans FCS */ - static const int min_buf_size = 60; uint32_t n = 0; - uint8_t min_buf[min_buf_size]; + uint8_t min_buf[MIN_BUF_SIZE]; struct iovec min_iov; uint8_t *filter_buf; size_t size, orig_size; diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 456ae38107..f1cba55967 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -696,6 +696,14 @@ static void do_tx_packet(lan9118_state *s) n = (s->tx_status_fifo_head + s->tx_status_fifo_used) & 511; s->tx_status_fifo[n] = status; s->tx_status_fifo_used++; + + /* + * Generate TSFL interrupt if TX FIFO level exceeds the level + * specified in the FIFO_INT TX Status Level field. + */ + if (s->tx_status_fifo_used > ((s->fifo_int >> 16) & 0xff)) { + s->int_sts |= TSFL_INT; + } if (s->tx_status_fifo_used == 512) { s->int_sts |= TSFF_INT; /* TODO: Stop transmission. */ diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 31f2340fb9..d8f3f16fe8 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -1010,7 +1010,7 @@ static uint64_t rocker_port_phys_link_status(Rocker *r) FpPort *port = r->fp_port[i]; if (fp_port_get_link_up(port)) { - status |= 1 << (i + 1); + status |= 1ULL << (i + 1); } } return status; @@ -1025,7 +1025,7 @@ static uint64_t rocker_port_phys_enable_read(Rocker *r) FpPort *port = r->fp_port[i]; if (fp_port_enabled(port)) { - ret |= 1 << (i + 1); + ret |= 1ULL << (i + 1); } } return ret; diff --git a/hw/net/tulip.c b/hw/net/tulip.c index 097e905bec..b9e42c322a 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -70,7 +70,7 @@ static const VMStateDescription vmstate_pci_tulip = { static void tulip_desc_read(TULIPState *s, hwaddr p, struct tulip_descriptor *desc) { - const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + const MemTxAttrs attrs = { .memory = true }; if (s->csr[0] & CSR0_DBO) { ldl_be_pci_dma(&s->dev, p, &desc->status, attrs); @@ -88,7 +88,7 @@ static void tulip_desc_read(TULIPState *s, hwaddr p, static void tulip_desc_write(TULIPState *s, hwaddr p, struct tulip_descriptor *desc) { - const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + const MemTxAttrs attrs = { .memory = true }; if (s->csr[0] & CSR0_DBO) { stl_be_pci_dma(&s->dev, p, desc->status, attrs); diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index ccac5b7a64..d28f8b974b 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -244,6 +244,13 @@ static int vhost_net_start_one(struct vhost_net *net, struct vhost_vring_file file = { }; int r; + if (net->nc->info->start) { + r = net->nc->info->start(net->nc); + if (r < 0) { + return r; + } + } + r = vhost_dev_enable_notifiers(&net->dev, dev); if (r < 0) { goto fail_notifiers; @@ -274,6 +281,13 @@ static int vhost_net_start_one(struct vhost_net *net, } } } + + if (net->nc->info->load) { + r = net->nc->info->load(net->nc); + if (r < 0) { + goto fail; + } + } return 0; fail: file.fd = -1; @@ -313,6 +327,9 @@ static void vhost_net_stop_one(struct vhost_net *net, net->nc->info->poll(net->nc, true); } vhost_dev_stop(&net->dev, dev); + if (net->nc->info->stop) { + net->nc->info->stop(net->nc); + } vhost_dev_disable_notifiers(&net->dev, dev); } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index dd0d056fde..e9f696b4cf 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -106,6 +106,12 @@ static const VirtIOFeature feature_sizes[] = { {} }; +static const VirtIOConfigSizeParams cfg_size_params = { + .min_size = endof(struct virtio_net_config, mac), + .max_size = sizeof(struct virtio_net_config), + .feature_sizes = feature_sizes +}; + static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc) { VirtIONet *n = qemu_get_nic_opaque(nc); @@ -1412,19 +1418,14 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; } - /* Avoid changing the number of queue_pairs for vdpa device in - * userspace handler. A future fix is needed to handle the mq - * change in userspace handler with vhost-vdpa. Let's disable - * the mq handling from userspace for now and only allow get - * done through the kernel. Ripples may be seen when falling - * back to userspace, but without doing it qemu process would - * crash on a recursive entry to virtio_net_set_status(). - */ - if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { - return VIRTIO_NET_ERR; - } - n->curr_queue_pairs = queue_pairs; + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { + /* + * Avoid updating the backend for a vdpa device: We're only interested + * in updating the device model queues. + */ + return VIRTIO_NET_OK; + } /* stop the backend before changing the number of queue_pairs to avoid handling a * disabled queue */ virtio_net_set_status(vdev, vdev->status); @@ -3246,8 +3247,7 @@ static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) { virtio_add_feature(&host_features, VIRTIO_NET_F_MAC); - n->config_size = virtio_feature_get_config_size(feature_sizes, - host_features); + n->config_size = virtio_get_config_size(&cfg_size_params, host_features); } void virtio_net_set_netclient_name(VirtIONet *n, const char *name, diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 533ad14e7a..87aeba0564 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -4238,7 +4238,9 @@ static void nvme_cq_notifier(EventNotifier *e) NvmeCQueue *cq = container_of(e, NvmeCQueue, notifier); NvmeCtrl *n = cq->ctrl; - event_notifier_test_and_clear(&cq->notifier); + if (!event_notifier_test_and_clear(e)) { + return; + } nvme_update_cq_head(cq); @@ -4275,7 +4277,9 @@ static void nvme_sq_notifier(EventNotifier *e) { NvmeSQueue *sq = container_of(e, NvmeSQueue, notifier); - event_notifier_test_and_clear(&sq->notifier); + if (!event_notifier_test_and_clear(e)) { + return; + } nvme_process_sq(sq); } @@ -4307,6 +4311,7 @@ static void nvme_free_sq(NvmeSQueue *sq, NvmeCtrl *n) if (sq->ioeventfd_enabled) { memory_region_del_eventfd(&n->iomem, 0x1000 + offset, 4, false, 0, &sq->notifier); + event_notifier_set_handler(&sq->notifier, NULL); event_notifier_cleanup(&sq->notifier); } g_free(sq->io_req); @@ -4697,6 +4702,7 @@ static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n) if (cq->ioeventfd_enabled) { memory_region_del_eventfd(&n->iomem, 0x1000 + offset, 4, false, 0, &cq->notifier); + event_notifier_set_handler(&cq->notifier, NULL); event_notifier_cleanup(&cq->notifier); } if (msix_enabled(&n->parent_obj)) { @@ -7664,7 +7670,7 @@ static Property nvme_props[] = { DEFINE_PROP_UINT8("vsl", NvmeCtrl, params.vsl, 7), DEFINE_PROP_BOOL("use-intel-id", NvmeCtrl, params.use_intel_id, false), DEFINE_PROP_BOOL("legacy-cmb", NvmeCtrl, params.legacy_cmb, false), - DEFINE_PROP_BOOL("ioeventfd", NvmeCtrl, params.ioeventfd, true), + DEFINE_PROP_BOOL("ioeventfd", NvmeCtrl, params.ioeventfd, false), DEFINE_PROP_UINT8("zoned.zasl", NvmeCtrl, params.zasl, 0), DEFINE_PROP_BOOL("zoned.auto_transition", NvmeCtrl, params.auto_transition_zones, true), diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index d605f3f45a..564bda3395 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -692,12 +692,12 @@ static const VMStateDescription vmstate_fw_cfg = { } }; -static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, - FWCfgCallback select_cb, - FWCfgWriteCallback write_cb, - void *callback_opaque, - void *data, size_t len, - bool read_only) +void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, + FWCfgCallback select_cb, + FWCfgWriteCallback write_cb, + void *callback_opaque, + void *data, size_t len, + bool read_only) { int arch = !!(key & FW_CFG_ARCH_LOCAL); diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba0..97af258b55 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -4,3 +4,15 @@ config OR1K_SIM select OPENCORES_ETH select OMPIC select SPLIT_IRQ + +config OR1K_VIRT + bool + imply PCI_DEVICES + imply VIRTIO_VGA + imply TEST_DEVICES + select PCI + select PCI_EXPRESS_GENERIC_BRIDGE + select GOLDFISH_RTC + select SERIAL + select SIFIVE_TEST + select VIRTIO_MMIO diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c new file mode 100644 index 0000000000..128ccbcba2 --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,116 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QEMU OpenRISC boot helpers. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu-defs.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/openrisc/boot.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" + +#include + +#define KERNEL_LOAD_ADDR 0x100 + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, + const char *kernel_filename, + uint32_t *bootstrap_pc) +{ + long kernel_size; + uint64_t elf_entry; + uint64_t high_addr; + hwaddr entry; + + if (kernel_filename && !qtest_enabled()) { + kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, + &elf_entry, NULL, &high_addr, NULL, 1, + EM_OPENRISC, 1, 0); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uimage(kernel_filename, + &entry, NULL, NULL, NULL, NULL); + high_addr = entry + kernel_size; + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); + high_addr = KERNEL_LOAD_ADDR + kernel_size; + } + + if (entry <= 0) { + entry = KERNEL_LOAD_ADDR; + } + + if (kernel_size < 0) { + error_report("couldn't load the kernel '%s'", kernel_filename); + exit(1); + } + *bootstrap_pc = entry; + + return high_addr; + } + return 0; +} + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, + hwaddr load_start, uint64_t mem_size) +{ + int size; + hwaddr start; + + /* We put the initrd right after the kernel; page aligned. */ + start = TARGET_PAGE_ALIGN(load_start); + + size = load_ramdisk(filename, start, mem_size - start); + if (size < 0) { + size = load_image_targphys(filename, start, mem_size - start); + if (size < 0) { + error_report("could not load ramdisk '%s'", filename); + exit(1); + } + } + + if (fdt) { + qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); + qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); + } + + return start + size; +} + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size) +{ + uint32_t fdt_addr; + int ret; + int fdtsize = fdt_totalsize(fdt); + + if (fdtsize <= 0) { + error_report("invalid device-tree"); + exit(1); + } + + /* We put fdt right after the kernel and/or initrd. */ + fdt_addr = TARGET_PAGE_ALIGN(load_start); + + ret = fdt_pack(fdt); + /* Should only fail if we've built a corrupted tree */ + g_assert(ret == 0); + /* copy in the device tree */ + qemu_fdt_dumpdtb(fdt, fdtsize); + + rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + &address_space_memory); + + return fdt_addr; +} diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 93268815d8..10163b391b 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "migration/vmstate.h" #include "qemu/timer.h" +#include "sysemu/reset.h" #define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */ @@ -122,6 +123,24 @@ static void openrisc_timer_cb(void *opaque) qemu_cpu_kick(CPU(cpu)); } +/* Reset the per CPU counter state. */ +static void openrisc_count_reset(void *opaque) +{ + OpenRISCCPU *cpu = opaque; + + if (cpu->env.is_counting) { + cpu_openrisc_count_stop(cpu); + } + cpu->env.ttmr = 0x00000000; +} + +/* Reset the global timer state. */ +static void openrisc_timer_reset(void *opaque) +{ + or1k_timer->ttcr = 0x00000000; + or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + static const VMStateDescription vmstate_or1k_timer = { .name = "or1k_timer", .version_id = 1, @@ -136,10 +155,11 @@ static const VMStateDescription vmstate_or1k_timer = { void cpu_openrisc_clock_init(OpenRISCCPU *cpu) { cpu->env.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &openrisc_timer_cb, cpu); - cpu->env.ttmr = 0x00000000; + qemu_register_reset(openrisc_count_reset, cpu); if (or1k_timer == NULL) { or1k_timer = g_new0(OR1KTimerState, 1); + qemu_register_reset(openrisc_timer_reset, cpu); vmstate_register(NULL, 0, &vmstate_or1k_timer, or1k_timer); } } diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ec48172c9d..2dbc6365bb 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,7 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) +openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) +openrisc_ss.add(when: 'CONFIG_OR1K_VIRT', if_true: [files('virt.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 35adce17ac..35da123aef 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -24,10 +24,9 @@ #include "cpu.h" #include "hw/irq.h" #include "hw/boards.h" -#include "elf.h" #include "hw/char/serial.h" #include "net/net.h" -#include "hw/loader.h" +#include "hw/openrisc/boot.h" #include "hw/qdev-properties.h" #include "exec/address-spaces.h" #include "sysemu/device_tree.h" @@ -283,101 +282,6 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, g_free(nodename); } -static hwaddr openrisc_load_kernel(ram_addr_t ram_size, - const char *kernel_filename) -{ - long kernel_size; - uint64_t elf_entry; - uint64_t high_addr; - hwaddr entry; - - if (kernel_filename && !qtest_enabled()) { - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &elf_entry, NULL, &high_addr, NULL, 1, - EM_OPENRISC, 1, 0); - entry = elf_entry; - if (kernel_size < 0) { - kernel_size = load_uimage(kernel_filename, - &entry, NULL, NULL, NULL, NULL); - high_addr = entry + kernel_size; - } - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, - KERNEL_LOAD_ADDR, - ram_size - KERNEL_LOAD_ADDR); - high_addr = KERNEL_LOAD_ADDR + kernel_size; - } - - if (entry <= 0) { - entry = KERNEL_LOAD_ADDR; - } - - if (kernel_size < 0) { - error_report("couldn't load the kernel '%s'", kernel_filename); - exit(1); - } - boot_info.bootstrap_pc = entry; - - return high_addr; - } - return 0; -} - -static hwaddr openrisc_load_initrd(Or1ksimState *state, const char *filename, - hwaddr load_start, uint64_t mem_size) -{ - void *fdt = state->fdt; - int size; - hwaddr start; - - /* We put the initrd right after the kernel; page aligned. */ - start = TARGET_PAGE_ALIGN(load_start); - - size = load_ramdisk(filename, start, mem_size - start); - if (size < 0) { - size = load_image_targphys(filename, start, mem_size - start); - if (size < 0) { - error_report("could not load ramdisk '%s'", filename); - exit(1); - } - } - - qemu_fdt_setprop_cell(fdt, "/chosen", - "linux,initrd-start", start); - qemu_fdt_setprop_cell(fdt, "/chosen", - "linux,initrd-end", start + size); - - return start + size; -} - -static uint32_t openrisc_load_fdt(Or1ksimState *state, hwaddr load_start, - uint64_t mem_size) -{ - void *fdt = state->fdt; - uint32_t fdt_addr; - int ret; - int fdtsize = fdt_totalsize(fdt); - - if (fdtsize <= 0) { - error_report("invalid device-tree"); - exit(1); - } - - /* We put fdt right after the kernel and/or initrd. */ - fdt_addr = TARGET_PAGE_ALIGN(load_start); - - ret = fdt_pack(fdt); - /* Should only fail if we've built a corrupted tree */ - g_assert(ret == 0); - /* copy in the device tree */ - qemu_fdt_dumpdtb(fdt, fdtsize); - - rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, - &address_space_memory); - - return fdt_addr; -} - static void openrisc_sim_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; @@ -428,13 +332,15 @@ static void openrisc_sim_init(MachineState *machine) or1ksim_memmap[OR1KSIM_UART].size, smp_cpus, cpus, OR1KSIM_UART_IRQ, n); - load_addr = openrisc_load_kernel(ram_size, kernel_filename); + load_addr = openrisc_load_kernel(ram_size, kernel_filename, + &boot_info.bootstrap_pc); if (load_addr > 0) { if (machine->initrd_filename) { - load_addr = openrisc_load_initrd(state, machine->initrd_filename, + load_addr = openrisc_load_initrd(state->fdt, + machine->initrd_filename, load_addr, machine->ram_size); } - boot_info.fdt_addr = openrisc_load_fdt(state, load_addr, + boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr, machine->ram_size); } } diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c new file mode 100644 index 0000000000..f8a68a6a6b --- /dev/null +++ b/hw/openrisc/virt.c @@ -0,0 +1,571 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * OpenRISC QEMU virtual machine. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu/guest-random.h" +#include "qapi/error.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/irq.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "hw/core/split-irq.h" +#include "hw/openrisc/boot.h" +#include "hw/misc/sifive_test.h" +#include "hw/pci/pci.h" +#include "hw/pci-host/gpex.h" +#include "hw/qdev-properties.h" +#include "hw/rtc/goldfish_rtc.h" +#include "hw/sysbus.h" +#include "hw/virtio/virtio-mmio.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/reset.h" + +#include + +#define VIRT_CPUS_MAX 4 +#define VIRT_CLK_MHZ 20000000 + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ + OBJECT_CHECK(OR1KVirtState, (obj), TYPE_VIRT_MACHINE) + +typedef struct OR1KVirtState { + /*< private >*/ + MachineState parent_obj; + + /*< public >*/ + void *fdt; + int fdt_size; + +} OR1KVirtState; + +enum { + VIRT_DRAM, + VIRT_ECAM, + VIRT_MMIO, + VIRT_PIO, + VIRT_TEST, + VIRT_RTC, + VIRT_VIRTIO, + VIRT_UART, + VIRT_OMPIC, +}; + +enum { + VIRT_OMPIC_IRQ = 1, + VIRT_UART_IRQ = 2, + VIRT_RTC_IRQ = 3, + VIRT_VIRTIO_IRQ = 4, /* to 12 */ + VIRTIO_COUNT = 8, + VIRT_PCI_IRQ_BASE = 13, /* to 17 */ +}; + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} virt_memmap[] = { + [VIRT_DRAM] = { 0x00000000, 0 }, + [VIRT_UART] = { 0x90000000, 0x100 }, + [VIRT_TEST] = { 0x96000000, 0x8 }, + [VIRT_RTC] = { 0x96005000, 0x1000 }, + [VIRT_VIRTIO] = { 0x97000000, 0x1000 }, + [VIRT_OMPIC] = { 0x98000000, VIRT_CPUS_MAX * 8 }, + [VIRT_ECAM] = { 0x9e000000, 0x1000000 }, + [VIRT_PIO] = { 0x9f000000, 0x1000000 }, + [VIRT_MMIO] = { 0xa0000000, 0x10000000 }, +}; + +static struct openrisc_boot_info { + uint32_t bootstrap_pc; + uint32_t fdt_addr; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ + OpenRISCCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + + cpu_reset(CPU(cpu)); + + cpu_set_pc(cs, boot_info.bootstrap_pc); + cpu_set_gpr(&cpu->env, 3, boot_info.fdt_addr); +} + +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ + return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); +} + +static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) +{ + int i; + + if (num_cpus > 1) { + DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); + qdev_prop_set_uint32(splitter, "num-lines", num_cpus); + qdev_realize_and_unref(splitter, NULL, &error_fatal); + for (i = 0; i < num_cpus; i++) { + qdev_connect_gpio_out(splitter, i, get_cpu_irq(cpus, i, irq_pin)); + } + return qdev_get_gpio_in(splitter, 0); + } else { + return get_cpu_irq(cpus, 0, irq_pin); + } +} + +static void openrisc_create_fdt(OR1KVirtState *state, + const struct MemmapEntry *memmap, + int num_cpus, uint64_t mem_size, + const char *cmdline, + int32_t *pic_phandle) +{ + void *fdt; + int cpu; + char *nodename; + uint8_t rng_seed[32]; + + fdt = state->fdt = create_device_tree(&state->fdt_size); + if (!fdt) { + error_report("create_device_tree() failed"); + exit(1); + } + + qemu_fdt_setprop_string(fdt, "/", "compatible", "opencores,or1ksim"); + qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x1); + qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1); + + qemu_fdt_add_subnode(fdt, "/soc"); + qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0); + qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus"); + qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x1); + qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1); + + nodename = g_strdup_printf("/memory@%" HWADDR_PRIx, + memmap[VIRT_DRAM].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + memmap[VIRT_DRAM].base, mem_size); + qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); + g_free(nodename); + + qemu_fdt_add_subnode(fdt, "/cpus"); + qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0); + qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); + + for (cpu = 0; cpu < num_cpus; cpu++) { + nodename = g_strdup_printf("/cpus/cpu@%d", cpu); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "opencores,or1200-rtlsvn481"); + qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu); + qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", + VIRT_CLK_MHZ); + g_free(nodename); + } + + nodename = (char *)"/pic"; + qemu_fdt_add_subnode(fdt, nodename); + *pic_phandle = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "opencores,or1k-pic-level"); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); + qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", *pic_phandle); + + qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", *pic_phandle); + + qemu_fdt_add_subnode(fdt, "/chosen"); + if (cmdline) { + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); + } + + /* Pass seed to RNG. */ + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + + /* Create aliases node for use by devices. */ + qemu_fdt_add_subnode(fdt, "/aliases"); +} + +static void openrisc_virt_ompic_init(OR1KVirtState *state, hwaddr base, + hwaddr size, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ + void *fdt = state->fdt; + DeviceState *dev; + SysBusDevice *s; + char *nodename; + int i; + + dev = qdev_new("or1k-ompic"); + qdev_prop_set_uint32(dev, "num-cpus", num_cpus); + + s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); + for (i = 0; i < num_cpus; i++) { + sysbus_connect_irq(s, i, get_cpu_irq(cpus, i, irq_pin)); + } + sysbus_mmio_map(s, 0, base); + + /* Add device tree node for ompic. */ + nodename = g_strdup_printf("/ompic@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "openrisc,ompic"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 0); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", irq_pin); + g_free(nodename); +} + +static void openrisc_virt_serial_init(OR1KVirtState *state, hwaddr base, + hwaddr size, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ + void *fdt = state->fdt; + char *nodename; + qemu_irq serial_irq = get_per_cpu_irq(cpus, num_cpus, irq_pin); + + serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200, + serial_hd(0), DEVICE_NATIVE_ENDIAN); + + /* Add device tree node for serial. */ + nodename = g_strdup_printf("/serial@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "ns16550a"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", irq_pin); + qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", VIRT_CLK_MHZ); + qemu_fdt_setprop(fdt, nodename, "big-endian", NULL, 0); + + /* The /chosen node is created during fdt creation. */ + qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); + qemu_fdt_setprop_string(fdt, "/aliases", "uart0", nodename); + g_free(nodename); +} + +static void openrisc_virt_test_init(OR1KVirtState *state, hwaddr base, + hwaddr size) +{ + void *fdt = state->fdt; + int test_ph; + char *nodename; + + /* SiFive Test MMIO device */ + sifive_test_create(base); + + /* SiFive Test MMIO Reset device FDT */ + nodename = g_strdup_printf("/soc/test@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "syscon"); + test_ph = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", test_ph); + qemu_fdt_setprop(fdt, nodename, "big-endian", NULL, 0); + g_free(nodename); + + nodename = g_strdup_printf("/soc/reboot"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "syscon-reboot"); + qemu_fdt_setprop_cell(fdt, nodename, "regmap", test_ph); + qemu_fdt_setprop_cell(fdt, nodename, "offset", 0x0); + qemu_fdt_setprop_cell(fdt, nodename, "value", FINISHER_RESET); + g_free(nodename); + + nodename = g_strdup_printf("/soc/poweroff"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "syscon-poweroff"); + qemu_fdt_setprop_cell(fdt, nodename, "regmap", test_ph); + qemu_fdt_setprop_cell(fdt, nodename, "offset", 0x0); + qemu_fdt_setprop_cell(fdt, nodename, "value", FINISHER_PASS); + g_free(nodename); + +} + +static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, + hwaddr size, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ + void *fdt = state->fdt; + char *nodename; + qemu_irq rtc_irq = get_per_cpu_irq(cpus, num_cpus, irq_pin); + + /* Goldfish RTC */ + sysbus_create_simple(TYPE_GOLDFISH_RTC, base, rtc_irq); + + /* Goldfish RTC FDT */ + nodename = g_strdup_printf("/soc/rtc@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "google,goldfish-rtc"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", irq_pin); + g_free(nodename); + +} + +static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, + uint32_t irqchip_phandle) +{ + int pin, dev; + uint32_t irq_map_stride = 0; + uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; + uint32_t *irq_map = full_irq_map; + + /* + * This code creates a standard swizzle of interrupts such that + * each device's first interrupt is based on it's PCI_SLOT number. + * (See pci_swizzle_map_irq_fn()) + * + * We only need one entry per interrupt in the table (not one per + * possible slot) seeing the interrupt-map-mask will allow the table + * to wrap to any number of devices. + */ + for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { + int devfn = dev << 3; + + for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { + int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); + int i = 0; + + /* Fill PCI address cells */ + irq_map[i++] = cpu_to_be32(devfn << 8); + irq_map[i++] = 0; + irq_map[i++] = 0; + + /* Fill PCI Interrupt cells */ + irq_map[i++] = cpu_to_be32(pin + 1); + + /* Fill interrupt controller phandle and cells */ + irq_map[i++] = cpu_to_be32(irqchip_phandle); + irq_map[i++] = cpu_to_be32(irq_nr); + + if (!irq_map_stride) { + irq_map_stride = i; + } + irq_map += irq_map_stride; + } + } + + qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map, + GPEX_NUM_IRQS * GPEX_NUM_IRQS * + irq_map_stride * sizeof(uint32_t)); + + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", + 0x1800, 0, 0, 0x7); +} + +static void openrisc_virt_pcie_init(OR1KVirtState *state, + hwaddr ecam_base, hwaddr ecam_size, + hwaddr pio_base, hwaddr pio_size, + hwaddr mmio_base, hwaddr mmio_size, + int num_cpus, OpenRISCCPU *cpus[], + int irq_base, int32_t pic_phandle) +{ + void *fdt = state->fdt; + char *nodename; + MemoryRegion *alias; + MemoryRegion *reg; + DeviceState *dev; + qemu_irq pcie_irq; + int i; + + dev = qdev_new(TYPE_GPEX_HOST); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + /* Map ECAM space. */ + alias = g_new0(MemoryRegion, 1); + reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_init_alias(alias, OBJECT(dev), "pcie-ecam", + reg, 0, ecam_size); + memory_region_add_subregion(get_system_memory(), ecam_base, alias); + + /* + * Map the MMIO window into system address space so as to expose + * the section of PCI MMIO space which starts at the same base address + * (ie 1:1 mapping for that part of PCI MMIO space visible through + * the window). + */ + alias = g_new0(MemoryRegion, 1); + reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); + memory_region_init_alias(alias, OBJECT(dev), "pcie-mmio", + reg, mmio_base, mmio_size); + memory_region_add_subregion(get_system_memory(), mmio_base, alias); + + /* Map IO port space. */ + alias = g_new0(MemoryRegion, 1); + reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 2); + memory_region_init_alias(alias, OBJECT(dev), "pcie-pio", + reg, 0, pio_size); + memory_region_add_subregion(get_system_memory(), pio_base, alias); + + /* Connect IRQ lines. */ + for (i = 0; i < GPEX_NUM_IRQS; i++) { + pcie_irq = get_per_cpu_irq(cpus, num_cpus, irq_base + i); + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pcie_irq); + gpex_set_irq_num(GPEX_HOST(dev), i, irq_base + i); + } + + nodename = g_strdup_printf("/soc/pci@%" HWADDR_PRIx, ecam_base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 3); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 2); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "pci-host-ecam-generic"); + qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci"); + qemu_fdt_setprop_cell(fdt, nodename, "linux,pci-domain", 0); + qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0, + ecam_size / PCIE_MMCFG_SIZE_MIN - 1); + qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0); + qemu_fdt_setprop_cells(fdt, nodename, "reg", ecam_base, ecam_size); + /* pci-address(3) cpu-address(1) pci-size(2) */ + qemu_fdt_setprop_cells(fdt, nodename, "ranges", + FDT_PCI_RANGE_IOPORT, 0, 0, + pio_base, 0, pio_size, + FDT_PCI_RANGE_MMIO, 0, mmio_base, + mmio_base, 0, mmio_size); + + create_pcie_irq_map(fdt, nodename, irq_base, pic_phandle); + g_free(nodename); +} + +static void openrisc_virt_virtio_init(OR1KVirtState *state, hwaddr base, + hwaddr size, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ + void *fdt = state->fdt; + char *nodename; + DeviceState *dev; + SysBusDevice *sysbus; + qemu_irq virtio_irq = get_per_cpu_irq(cpus, num_cpus, irq_pin); + + /* VirtIO MMIO devices */ + dev = qdev_new(TYPE_VIRTIO_MMIO); + qdev_prop_set_bit(dev, "force-legacy", false); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); + sysbus_connect_irq(sysbus, 0, virtio_irq); + sysbus_mmio_map(sysbus, 0, base); + + /* VirtIO MMIO devices FDT */ + nodename = g_strdup_printf("/soc/virtio_mmio@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "virtio,mmio"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", irq_pin); + g_free(nodename); +} + +static void openrisc_virt_init(MachineState *machine) +{ + ram_addr_t ram_size = machine->ram_size; + const char *kernel_filename = machine->kernel_filename; + OpenRISCCPU *cpus[VIRT_CPUS_MAX] = {}; + OR1KVirtState *state = VIRT_MACHINE(machine); + MemoryRegion *ram; + hwaddr load_addr; + int n; + unsigned int smp_cpus = machine->smp.cpus; + int32_t pic_phandle; + + assert(smp_cpus >= 1 && smp_cpus <= VIRT_CPUS_MAX); + for (n = 0; n < smp_cpus; n++) { + cpus[n] = OPENRISC_CPU(cpu_create(machine->cpu_type)); + if (cpus[n] == NULL) { + fprintf(stderr, "Unable to find CPU definition!\n"); + exit(1); + } + + cpu_openrisc_clock_init(cpus[n]); + + qemu_register_reset(main_cpu_reset, cpus[n]); + } + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, NULL, "openrisc.ram", ram_size, &error_fatal); + memory_region_add_subregion(get_system_memory(), 0, ram); + + openrisc_create_fdt(state, virt_memmap, smp_cpus, machine->ram_size, + machine->kernel_cmdline, &pic_phandle); + + if (smp_cpus > 1) { + openrisc_virt_ompic_init(state, virt_memmap[VIRT_OMPIC].base, + virt_memmap[VIRT_OMPIC].size, + smp_cpus, cpus, VIRT_OMPIC_IRQ); + } + + openrisc_virt_serial_init(state, virt_memmap[VIRT_UART].base, + virt_memmap[VIRT_UART].size, + smp_cpus, cpus, VIRT_UART_IRQ); + + openrisc_virt_test_init(state, virt_memmap[VIRT_TEST].base, + virt_memmap[VIRT_TEST].size); + + openrisc_virt_rtc_init(state, virt_memmap[VIRT_RTC].base, + virt_memmap[VIRT_RTC].size, smp_cpus, cpus, + VIRT_RTC_IRQ); + + openrisc_virt_pcie_init(state, virt_memmap[VIRT_ECAM].base, + virt_memmap[VIRT_ECAM].size, + virt_memmap[VIRT_PIO].base, + virt_memmap[VIRT_PIO].size, + virt_memmap[VIRT_MMIO].base, + virt_memmap[VIRT_MMIO].size, + smp_cpus, cpus, + VIRT_PCI_IRQ_BASE, pic_phandle); + + for (n = 0; n < VIRTIO_COUNT; n++) { + openrisc_virt_virtio_init(state, virt_memmap[VIRT_VIRTIO].base + + n * virt_memmap[VIRT_VIRTIO].size, + virt_memmap[VIRT_VIRTIO].size, + smp_cpus, cpus, VIRT_VIRTIO_IRQ + n); + } + + load_addr = openrisc_load_kernel(ram_size, kernel_filename, + &boot_info.bootstrap_pc); + if (load_addr > 0) { + if (machine->initrd_filename) { + load_addr = openrisc_load_initrd(state->fdt, + machine->initrd_filename, + load_addr, machine->ram_size); + } + boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr, + machine->ram_size); + } +} + +static void openrisc_virt_machine_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "or1k virtual machine"; + mc->init = openrisc_virt_init; + mc->max_cpus = VIRT_CPUS_MAX; + mc->is_default = false; + mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200"); +} + +static const TypeInfo or1ksim_machine_typeinfo = { + .name = TYPE_VIRT_MACHINE, + .parent = TYPE_MACHINE, + .class_init = openrisc_virt_machine_init, + .instance_size = sizeof(OR1KVirtState), +}; + +static void or1ksim_machine_init_register_types(void) +{ + type_register_static(&or1ksim_machine_typeinfo); +} + +type_init(or1ksim_machine_init_register_types) diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index 1c5ad5f918..d5426ef4a5 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -237,7 +237,8 @@ static void i440fx_realize(PCIDevice *dev, Error **errp) } } -PCIBus *i440fx_init(const char *host_type, const char *pci_type, +PCIBus *i440fx_init(const char *pci_type, + DeviceState *dev, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, @@ -246,7 +247,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, MemoryRegion *pci_address_space, MemoryRegion *ram_memory) { - DeviceState *dev; PCIBus *b; PCIDevice *d; PCIHostState *s; @@ -254,7 +254,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, unsigned i; I440FXState *i440fx; - dev = qdev_new(host_type); s = PCI_HOST_BRIDGE(dev); b = pci_root_bus_new(dev, NULL, pci_address_space, address_space_io, 0, TYPE_PCI_BUS); diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index c07596d0d1..e832babc9d 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -35,5 +35,6 @@ specific_ss.add(when: 'CONFIG_PCI_POWERNV', if_true: files( 'pnv_phb3_msi.c', 'pnv_phb3_pbcq.c', 'pnv_phb4.c', - 'pnv_phb4_pec.c' + 'pnv_phb4_pec.c', + 'pnv_phb.c', )) diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c new file mode 100644 index 0000000000..7b11f1e8dd --- /dev/null +++ b/hw/pci-host/pnv_phb.c @@ -0,0 +1,337 @@ +/* + * QEMU PowerPC PowerNV Proxy PHB model + * + * Copyright (c) 2022, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/visitor.h" +#include "qapi/error.h" +#include "hw/pci-host/pnv_phb.h" +#include "hw/pci-host/pnv_phb3.h" +#include "hw/pci-host/pnv_phb4.h" +#include "hw/ppc/pnv.h" +#include "hw/qdev-properties.h" +#include "qom/object.h" +#include "sysemu/sysemu.h" + + +/* + * Set the QOM parent and parent bus of an object child. If the device + * state associated with the child has an id, use it as QOM id. + * Otherwise use object_typename[index] as QOM id. + * + * This helper does both operations at the same time because seting + * a new QOM child will erase the bus parent of the device. This happens + * because object_unparent() will call object_property_del_child(), + * which in turn calls the property release callback prop->release if + * it's defined. In our case this callback is set to + * object_finalize_child_property(), which was assigned during the + * first object_property_add_child() call. This callback will end up + * calling device_unparent(), and this function removes the device + * from its parent bus. + * + * The QOM and parent bus to be set aren´t necessarily related, so + * let's receive both as arguments. + */ +static bool pnv_parent_fixup(Object *parent, BusState *parent_bus, + Object *child, int index, + Error **errp) +{ + g_autofree char *default_id = + g_strdup_printf("%s[%d]", object_get_typename(child), index); + const char *dev_id = DEVICE(child)->id; + + if (child->parent == parent) { + return true; + } + + object_ref(child); + object_unparent(child); + object_property_add_child(parent, dev_id ? dev_id : default_id, child); + object_unref(child); + + if (!qdev_set_parent_bus(DEVICE(child), parent_bus, errp)) { + return false; + } + + return true; +} + +/* + * User created devices won't have the initial setup that default + * devices have. This setup consists of assigning a parent device + * (chip for PHB3, PEC for PHB4/5) that will be the QOM/bus parent + * of the PHB. + */ +static bool pnv_phb_user_device_init(PnvPHB *phb, Error **errp) +{ + PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); + PnvChip *chip = pnv_get_chip(pnv, phb->chip_id); + Object *parent = NULL; + + if (!chip) { + error_setg(errp, "invalid chip id: %d", phb->chip_id); + return false; + } + + parent = pnv_chip_add_phb(chip, phb, errp); + if (!parent) { + return false; + } + + /* + * Reparent user created devices to the chip to build + * correctly the device tree. pnv_xscom_dt() needs every + * PHB to be a child of the chip to build the DT correctly. + */ + if (!pnv_parent_fixup(parent, qdev_get_parent_bus(DEVICE(chip)), + OBJECT(phb), phb->phb_id, errp)) { + return false; + } + + return true; +} + +static void pnv_phb_realize(DeviceState *dev, Error **errp) +{ + PnvPHB *phb = PNV_PHB(dev); + PCIHostState *pci = PCI_HOST_BRIDGE(dev); + g_autofree char *phb_typename = NULL; + + if (!phb->version) { + error_setg(errp, "version not specified"); + return; + } + + switch (phb->version) { + case 3: + phb_typename = g_strdup(TYPE_PNV_PHB3); + break; + case 4: + phb_typename = g_strdup(TYPE_PNV_PHB4); + break; + case 5: + phb_typename = g_strdup(TYPE_PNV_PHB5); + break; + default: + g_assert_not_reached(); + } + + phb->backend = object_new(phb_typename); + object_property_add_child(OBJECT(dev), "phb-backend", phb->backend); + + /* Passthrough child device properties to the proxy device */ + object_property_set_uint(phb->backend, "index", phb->phb_id, errp); + object_property_set_uint(phb->backend, "chip-id", phb->chip_id, errp); + object_property_set_link(phb->backend, "phb-base", OBJECT(phb), errp); + + /* + * Handle user created devices. User devices will not have a + * pointer to a chip (PHB3) and a PEC (PHB4/5). + */ + if (!phb->chip && !phb->pec) { + if (!pnv_phb_user_device_init(phb, errp)) { + return; + } + } + + if (phb->version == 3) { + object_property_set_link(phb->backend, "chip", + OBJECT(phb->chip), errp); + } else { + object_property_set_link(phb->backend, "pec", OBJECT(phb->pec), errp); + } + + if (!qdev_realize(DEVICE(phb->backend), NULL, errp)) { + return; + } + + if (phb->version == 3) { + pnv_phb3_bus_init(dev, PNV_PHB3(phb->backend)); + } else { + pnv_phb4_bus_init(dev, PNV_PHB4(phb->backend)); + } + + if (defaults_enabled()) { + PCIDevice *root = pci_new(PCI_DEVFN(0, 0), TYPE_PNV_PHB_ROOT_PORT); + + pci_realize_and_unref(root, pci->bus, errp); + } +} + +static const char *pnv_phb_root_bus_path(PCIHostState *host_bridge, + PCIBus *rootbus) +{ + PnvPHB *phb = PNV_PHB(host_bridge); + + snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x", + phb->chip_id, phb->phb_id); + return phb->bus_path; +} + +static Property pnv_phb_properties[] = { + DEFINE_PROP_UINT32("index", PnvPHB, phb_id, 0), + DEFINE_PROP_UINT32("chip-id", PnvPHB, chip_id, 0), + DEFINE_PROP_UINT32("version", PnvPHB, version, 0), + + DEFINE_PROP_LINK("chip", PnvPHB, chip, TYPE_PNV_CHIP, PnvChip *), + + DEFINE_PROP_LINK("pec", PnvPHB, pec, TYPE_PNV_PHB4_PEC, + PnvPhb4PecState *), + + DEFINE_PROP_END_OF_LIST(), +}; + +static void pnv_phb_class_init(ObjectClass *klass, void *data) +{ + PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + hc->root_bus_path = pnv_phb_root_bus_path; + dc->realize = pnv_phb_realize; + device_class_set_props(dc, pnv_phb_properties); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->user_creatable = true; +} + +static void pnv_phb_root_port_reset(DeviceState *dev) +{ + PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); + PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev); + PCIDevice *d = PCI_DEVICE(dev); + uint8_t *conf = d->config; + + rpc->parent_reset(dev); + + if (phb_rp->version == 3) { + return; + } + + /* PHB4 and later requires these extra reset steps */ + pci_byte_test_and_set_mask(conf + PCI_IO_BASE, + PCI_IO_RANGE_MASK & 0xff); + pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, + PCI_IO_RANGE_MASK & 0xff); + pci_set_word(conf + PCI_MEMORY_BASE, 0); + pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0); + pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1); + pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1); + pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */ + pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff); + pci_config_set_interrupt_pin(conf, 0); +} + +static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp) +{ + PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); + PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(dev); + PCIBus *bus = PCI_BUS(qdev_get_parent_bus(dev)); + PCIDevice *pci = PCI_DEVICE(dev); + uint16_t device_id = 0; + Error *local_err = NULL; + int chip_id, index; + + /* + * 'index' will be used both as a PCIE slot value and to calculate + * QOM id. 'chip_id' is going to be used as PCIE chassis for the + * root port. + */ + chip_id = object_property_get_int(OBJECT(bus), "chip-id", &error_fatal); + index = object_property_get_int(OBJECT(bus), "phb-id", &error_fatal); + + /* Set unique chassis/slot values for the root port */ + qdev_prop_set_uint8(dev, "chassis", chip_id); + qdev_prop_set_uint16(dev, "slot", index); + + /* + * User created root ports are QOM parented to one of + * the peripheral containers but it's already at the right + * parent bus. Change the QOM parent to be the same as the + * parent bus it's already assigned to. + */ + if (!pnv_parent_fixup(OBJECT(bus), BUS(bus), OBJECT(dev), + index, errp)) { + return; + } + + rpc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + switch (phb_rp->version) { + case 3: + device_id = PNV_PHB3_DEVICE_ID; + break; + case 4: + device_id = PNV_PHB4_DEVICE_ID; + break; + case 5: + device_id = PNV_PHB5_DEVICE_ID; + break; + default: + g_assert_not_reached(); + } + + pci_config_set_device_id(pci->config, device_id); + pci_config_set_interrupt_pin(pci->config, 0); +} + +static Property pnv_phb_root_port_properties[] = { + DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0), + + DEFINE_PROP_END_OF_LIST(), +}; + +static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass); + + dc->desc = "IBM PHB PCIE Root Port"; + + device_class_set_props(dc, pnv_phb_root_port_properties); + device_class_set_parent_realize(dc, pnv_phb_root_port_realize, + &rpc->parent_realize); + device_class_set_parent_reset(dc, pnv_phb_root_port_reset, + &rpc->parent_reset); + dc->reset = &pnv_phb_root_port_reset; + dc->user_creatable = true; + + k->vendor_id = PCI_VENDOR_ID_IBM; + /* device_id will be written during realize() */ + k->device_id = 0; + k->revision = 0; + + rpc->exp_offset = 0x48; + rpc->aer_offset = 0x100; +} + +static const TypeInfo pnv_phb_type_info = { + .name = TYPE_PNV_PHB, + .parent = TYPE_PCIE_HOST_BRIDGE, + .instance_size = sizeof(PnvPHB), + .class_init = pnv_phb_class_init, +}; + +static const TypeInfo pnv_phb_root_port_info = { + .name = TYPE_PNV_PHB_ROOT_PORT, + .parent = TYPE_PCIE_ROOT_PORT, + .instance_size = sizeof(PnvPHBRootPort), + .class_init = pnv_phb_root_port_class_init, +}; + +static void pnv_phb_register_types(void) +{ + type_register_static(&pnv_phb_type_info); + type_register_static(&pnv_phb_root_port_info); +} + +type_init(pnv_phb_register_types) diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h new file mode 100644 index 0000000000..58ebd6dd0f --- /dev/null +++ b/hw/pci-host/pnv_phb.h @@ -0,0 +1,55 @@ +/* + * QEMU PowerPC PowerNV Proxy PHB model + * + * Copyright (c) 2022, IBM Corporation. + * + * This code is licensed under the GPL version 2 or later. See the + * COPYING file in the top-level directory. + */ + +#ifndef PCI_HOST_PNV_PHB_H +#define PCI_HOST_PNV_PHB_H + +#include "hw/pci/pcie_host.h" +#include "hw/pci/pcie_port.h" +#include "qom/object.h" + +typedef struct PnvChip PnvChip; +typedef struct PnvPhb4PecState PnvPhb4PecState; + +struct PnvPHB { + PCIExpressHost parent_obj; + + uint32_t chip_id; + uint32_t phb_id; + uint32_t version; + char bus_path[8]; + + PnvChip *chip; + + PnvPhb4PecState *pec; + + /* The PHB backend (PnvPHB3, PnvPHB4 ...) being used */ + Object *backend; +}; + +#define TYPE_PNV_PHB "pnv-phb" +OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB, PNV_PHB) + +/* + * PHB PCIe Root port + */ +#define PNV_PHB3_DEVICE_ID 0x03dc +#define PNV_PHB4_DEVICE_ID 0x04c1 +#define PNV_PHB5_DEVICE_ID 0x0652 + +typedef struct PnvPHBRootPort { + PCIESlot parent_obj; + + uint32_t version; +} PnvPHBRootPort; + +#define TYPE_PNV_PHB_ROOT_PORT "pnv-phb-root-port" +OBJECT_DECLARE_SIMPLE_TYPE(PnvPHBRootPort, PNV_PHB_ROOT_PORT) + +#endif /* PCI_HOST_PNV_PHB_H */ diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index d58d3c1701..9054c393a2 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -11,6 +11,7 @@ #include "qapi/visitor.h" #include "qapi/error.h" #include "hw/pci-host/pnv_phb3_regs.h" +#include "hw/pci-host/pnv_phb.h" #include "hw/pci-host/pnv_phb3.h" #include "hw/pci/pcie_host.h" #include "hw/pci/pcie_port.h" @@ -26,7 +27,7 @@ static PCIDevice *pnv_phb3_find_cfg_dev(PnvPHB3 *phb) { - PCIHostState *pci = PCI_HOST_BRIDGE(phb); + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base); uint64_t addr = phb->regs[PHB_CONFIG_ADDRESS >> 3]; uint8_t bus, devfn; @@ -590,7 +591,7 @@ void pnv_phb3_reg_write(void *opaque, hwaddr off, uint64_t val, unsigned size) uint64_t pnv_phb3_reg_read(void *opaque, hwaddr off, unsigned size) { PnvPHB3 *phb = opaque; - PCIHostState *pci = PCI_HOST_BRIDGE(phb); + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base); uint64_t val; if ((off & 0xfffc) == PHB_CONFIG_DATA) { @@ -986,10 +987,36 @@ static void pnv_phb3_instance_init(Object *obj) } +void pnv_phb3_bus_init(DeviceState *dev, PnvPHB3 *phb) +{ + PCIHostState *pci = PCI_HOST_BRIDGE(dev); + + /* + * PHB3 doesn't support IO space. However, qemu gets very upset if + * we don't have an IO region to anchor IO BARs onto so we just + * initialize one which we never hook up to anything + */ + memory_region_init(&phb->pci_io, OBJECT(phb), "pci-io", 0x10000); + memory_region_init(&phb->pci_mmio, OBJECT(phb), "pci-mmio", + PCI_MMIO_TOTAL_SIZE); + + pci->bus = pci_register_root_bus(dev, + dev->id ? dev->id : NULL, + pnv_phb3_set_irq, pnv_phb3_map_irq, phb, + &phb->pci_mmio, &phb->pci_io, + 0, 4, TYPE_PNV_PHB3_ROOT_BUS); + + object_property_set_int(OBJECT(pci->bus), "phb-id", phb->phb_id, + &error_abort); + object_property_set_int(OBJECT(pci->bus), "chip-id", phb->chip_id, + &error_abort); + + pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb); +} + static void pnv_phb3_realize(DeviceState *dev, Error **errp) { PnvPHB3 *phb = PNV_PHB3(dev); - PCIHostState *pci = PCI_HOST_BRIDGE(dev); PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); int i; @@ -1034,26 +1061,6 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) /* Controller Registers */ memory_region_init_io(&phb->mr_regs, OBJECT(phb), &pnv_phb3_reg_ops, phb, "phb3-regs", 0x1000); - - /* - * PHB3 doesn't support IO space. However, qemu gets very upset if - * we don't have an IO region to anchor IO BARs onto so we just - * initialize one which we never hook up to anything - */ - memory_region_init(&phb->pci_io, OBJECT(phb), "pci-io", 0x10000); - memory_region_init(&phb->pci_mmio, OBJECT(phb), "pci-mmio", - PCI_MMIO_TOTAL_SIZE); - - pci->bus = pci_register_root_bus(dev, - dev->id ? dev->id : NULL, - pnv_phb3_set_irq, pnv_phb3_map_irq, phb, - &phb->pci_mmio, &phb->pci_io, - 0, 4, TYPE_PNV_PHB3_ROOT_BUS); - - pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb); - - pnv_phb_attach_root_port(pci, TYPE_PNV_PHB3_ROOT_PORT, - phb->phb_id, phb->chip_id); } void pnv_phb3_update_regions(PnvPHB3 *phb) @@ -1078,47 +1085,80 @@ void pnv_phb3_update_regions(PnvPHB3 *phb) pnv_phb3_check_all_m64s(phb); } -static const char *pnv_phb3_root_bus_path(PCIHostState *host_bridge, - PCIBus *rootbus) -{ - PnvPHB3 *phb = PNV_PHB3(host_bridge); - - snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x", - phb->chip_id, phb->phb_id); - return phb->bus_path; -} - static Property pnv_phb3_properties[] = { DEFINE_PROP_UINT32("index", PnvPHB3, phb_id, 0), DEFINE_PROP_UINT32("chip-id", PnvPHB3, chip_id, 0), DEFINE_PROP_LINK("chip", PnvPHB3, chip, TYPE_PNV_CHIP, PnvChip *), + DEFINE_PROP_LINK("phb-base", PnvPHB3, phb_base, TYPE_PNV_PHB, PnvPHB *), DEFINE_PROP_END_OF_LIST(), }; static void pnv_phb3_class_init(ObjectClass *klass, void *data) { - PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - hc->root_bus_path = pnv_phb3_root_bus_path; dc->realize = pnv_phb3_realize; device_class_set_props(dc, pnv_phb3_properties); - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->user_creatable = false; } static const TypeInfo pnv_phb3_type_info = { .name = TYPE_PNV_PHB3, - .parent = TYPE_PCIE_HOST_BRIDGE, + .parent = TYPE_DEVICE, .instance_size = sizeof(PnvPHB3), .class_init = pnv_phb3_class_init, .instance_init = pnv_phb3_instance_init, }; +static void pnv_phb3_root_bus_get_prop(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) +{ + PnvPHB3RootBus *bus = PNV_PHB3_ROOT_BUS(obj); + uint64_t value = 0; + + if (strcmp(name, "phb-id") == 0) { + value = bus->phb_id; + } else { + value = bus->chip_id; + } + + visit_type_size(v, name, &value, errp); +} + +static void pnv_phb3_root_bus_set_prop(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) + +{ + PnvPHB3RootBus *bus = PNV_PHB3_ROOT_BUS(obj); + uint64_t value; + + if (!visit_type_size(v, name, &value, errp)) { + return; + } + + if (strcmp(name, "phb-id") == 0) { + bus->phb_id = value; + } else { + bus->chip_id = value; + } +} + static void pnv_phb3_root_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); + object_class_property_add(klass, "phb-id", "int", + pnv_phb3_root_bus_get_prop, + pnv_phb3_root_bus_set_prop, + NULL, NULL); + + object_class_property_add(klass, "chip-id", "int", + pnv_phb3_root_bus_get_prop, + pnv_phb3_root_bus_set_prop, + NULL, NULL); + /* * PHB3 has only a single root complex. Enforce the limit on the * parent bus @@ -1129,54 +1169,13 @@ static void pnv_phb3_root_bus_class_init(ObjectClass *klass, void *data) static const TypeInfo pnv_phb3_root_bus_info = { .name = TYPE_PNV_PHB3_ROOT_BUS, .parent = TYPE_PCIE_BUS, + .instance_size = sizeof(PnvPHB3RootBus), .class_init = pnv_phb3_root_bus_class_init, }; -static void pnv_phb3_root_port_realize(DeviceState *dev, Error **errp) -{ - PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); - PCIDevice *pci = PCI_DEVICE(dev); - Error *local_err = NULL; - - rpc->parent_realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - pci_config_set_interrupt_pin(pci->config, 0); -} - -static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass); - - dc->desc = "IBM PHB3 PCIE Root Port"; - - device_class_set_parent_realize(dc, pnv_phb3_root_port_realize, - &rpc->parent_realize); - dc->user_creatable = false; - - k->vendor_id = PCI_VENDOR_ID_IBM; - k->device_id = 0x03dc; - k->revision = 0; - - rpc->exp_offset = 0x48; - rpc->aer_offset = 0x100; -} - -static const TypeInfo pnv_phb3_root_port_info = { - .name = TYPE_PNV_PHB3_ROOT_PORT, - .parent = TYPE_PCIE_ROOT_PORT, - .instance_size = sizeof(PnvPHB3RootPort), - .class_init = pnv_phb3_root_port_class_init, -}; - static void pnv_phb3_register_types(void) { type_register_static(&pnv_phb3_root_bus_info); - type_register_static(&pnv_phb3_root_port_info); type_register_static(&pnv_phb3_type_info); type_register_static(&pnv_phb3_iommu_memory_region_info); } diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 67ddde4a6e..ccbde841fc 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -33,7 +33,7 @@ static PCIDevice *pnv_phb4_find_cfg_dev(PnvPHB4 *phb) { - PCIHostState *pci = PCI_HOST_BRIDGE(phb); + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base); uint64_t addr = phb->regs[PHB_CONFIG_ADDRESS >> 3]; uint8_t bus, devfn; @@ -129,7 +129,7 @@ static uint64_t pnv_phb4_config_read(PnvPHB4 *phb, unsigned off, static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off, unsigned size, uint64_t val) { - PCIHostState *pci = PCI_HOST_BRIDGE(phb); + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base); PCIDevice *pdev; if (size != 4) { @@ -150,7 +150,7 @@ static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off, static uint64_t pnv_phb4_rc_config_read(PnvPHB4 *phb, unsigned off, unsigned size) { - PCIHostState *pci = PCI_HOST_BRIDGE(phb); + PCIHostState *pci = PCI_HOST_BRIDGE(phb->phb_base); PCIDevice *pdev; uint64_t val; @@ -1528,11 +1528,42 @@ static void pnv_phb4_instance_init(Object *obj) object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE); } +void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb) +{ + PCIHostState *pci = PCI_HOST_BRIDGE(dev); + char name[32]; + + /* + * PHB4 doesn't support IO space. However, qemu gets very upset if + * we don't have an IO region to anchor IO BARs onto so we just + * initialize one which we never hook up to anything + */ + snprintf(name, sizeof(name), "phb4-%d.%d-pci-io", phb->chip_id, + phb->phb_id); + memory_region_init(&phb->pci_io, OBJECT(phb), name, 0x10000); + + snprintf(name, sizeof(name), "phb4-%d.%d-pci-mmio", phb->chip_id, + phb->phb_id); + memory_region_init(&phb->pci_mmio, OBJECT(phb), name, + PCI_MMIO_TOTAL_SIZE); + + pci->bus = pci_register_root_bus(dev, dev->id ? dev->id : NULL, + pnv_phb4_set_irq, pnv_phb4_map_irq, phb, + &phb->pci_mmio, &phb->pci_io, + 0, 4, TYPE_PNV_PHB4_ROOT_BUS); + + object_property_set_int(OBJECT(pci->bus), "phb-id", phb->phb_id, + &error_abort); + object_property_set_int(OBJECT(pci->bus), "chip-id", phb->chip_id, + &error_abort); + + pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb); + pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; +} + static void pnv_phb4_realize(DeviceState *dev, Error **errp) { PnvPHB4 *phb = PNV_PHB4(dev); - PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(phb->pec); - PCIHostState *pci = PCI_HOST_BRIDGE(dev); XiveSource *xsrc = &phb->xsrc; int nr_irqs; char name[32]; @@ -1546,32 +1577,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) memory_region_init_io(&phb->mr_regs, OBJECT(phb), &pnv_phb4_reg_ops, phb, name, 0x2000); - /* - * PHB4 doesn't support IO space. However, qemu gets very upset if - * we don't have an IO region to anchor IO BARs onto so we just - * initialize one which we never hook up to anything - */ - - snprintf(name, sizeof(name), "phb4-%d.%d-pci-io", phb->chip_id, - phb->phb_id); - memory_region_init(&phb->pci_io, OBJECT(phb), name, 0x10000); - - snprintf(name, sizeof(name), "phb4-%d.%d-pci-mmio", phb->chip_id, - phb->phb_id); - memory_region_init(&phb->pci_mmio, OBJECT(phb), name, - PCI_MMIO_TOTAL_SIZE); - - pci->bus = pci_register_root_bus(dev, dev->id, - pnv_phb4_set_irq, pnv_phb4_map_irq, phb, - &phb->pci_mmio, &phb->pci_io, - 0, 4, TYPE_PNV_PHB4_ROOT_BUS); - pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb); - pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; - - /* Add a single Root port if running with defaults */ - pnv_phb_attach_root_port(pci, pecc->rp_model, - phb->phb_id, phb->chip_id); - /* Setup XIVE Source */ if (phb->big_phb) { nr_irqs = PNV_PHB4_MAX_INTs; @@ -1591,16 +1596,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp) pnv_phb4_xscom_realize(phb); } -static const char *pnv_phb4_root_bus_path(PCIHostState *host_bridge, - PCIBus *rootbus) -{ - PnvPHB4 *phb = PNV_PHB4(host_bridge); - - snprintf(phb->bus_path, sizeof(phb->bus_path), "00%02x:%02x", - phb->chip_id, phb->phb_id); - return phb->bus_path; -} - /* * Address base trigger mode (POWER10) * @@ -1685,19 +1680,17 @@ static Property pnv_phb4_properties[] = { DEFINE_PROP_UINT32("chip-id", PnvPHB4, chip_id, 0), DEFINE_PROP_LINK("pec", PnvPHB4, pec, TYPE_PNV_PHB4_PEC, PnvPhb4PecState *), + DEFINE_PROP_LINK("phb-base", PnvPHB4, phb_base, TYPE_PNV_PHB, PnvPHB *), DEFINE_PROP_END_OF_LIST(), }; static void pnv_phb4_class_init(ObjectClass *klass, void *data) { - PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass); - hc->root_bus_path = pnv_phb4_root_bus_path; dc->realize = pnv_phb4_realize; device_class_set_props(dc, pnv_phb4_properties); - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->user_creatable = false; xfc->notify = pnv_phb4_xive_notify; @@ -1705,7 +1698,7 @@ static void pnv_phb4_class_init(ObjectClass *klass, void *data) static const TypeInfo pnv_phb4_type_info = { .name = TYPE_PNV_PHB4, - .parent = TYPE_PCIE_HOST_BRIDGE, + .parent = TYPE_DEVICE, .instance_init = pnv_phb4_instance_init, .instance_size = sizeof(PnvPHB4), .class_init = pnv_phb4_class_init, @@ -1721,10 +1714,55 @@ static const TypeInfo pnv_phb5_type_info = { .instance_size = sizeof(PnvPHB4), }; +static void pnv_phb4_root_bus_get_prop(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) +{ + PnvPHB4RootBus *bus = PNV_PHB4_ROOT_BUS(obj); + uint64_t value = 0; + + if (strcmp(name, "phb-id") == 0) { + value = bus->phb_id; + } else { + value = bus->chip_id; + } + + visit_type_size(v, name, &value, errp); +} + +static void pnv_phb4_root_bus_set_prop(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) + +{ + PnvPHB4RootBus *bus = PNV_PHB4_ROOT_BUS(obj); + uint64_t value; + + if (!visit_type_size(v, name, &value, errp)) { + return; + } + + if (strcmp(name, "phb-id") == 0) { + bus->phb_id = value; + } else { + bus->chip_id = value; + } +} + static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); + object_class_property_add(klass, "phb-id", "int", + pnv_phb4_root_bus_get_prop, + pnv_phb4_root_bus_set_prop, + NULL, NULL); + + object_class_property_add(klass, "chip-id", "int", + pnv_phb4_root_bus_get_prop, + pnv_phb4_root_bus_set_prop, + NULL, NULL); + /* * PHB4 has only a single root complex. Enforce the limit on the * parent bus @@ -1735,97 +1773,13 @@ static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data) static const TypeInfo pnv_phb4_root_bus_info = { .name = TYPE_PNV_PHB4_ROOT_BUS, .parent = TYPE_PCIE_BUS, + .instance_size = sizeof(PnvPHB4RootBus), .class_init = pnv_phb4_root_bus_class_init, }; -static void pnv_phb4_root_port_reset(DeviceState *dev) -{ - PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); - PCIDevice *d = PCI_DEVICE(dev); - uint8_t *conf = d->config; - - rpc->parent_reset(dev); - - pci_byte_test_and_set_mask(conf + PCI_IO_BASE, - PCI_IO_RANGE_MASK & 0xff); - pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT, - PCI_IO_RANGE_MASK & 0xff); - pci_set_word(conf + PCI_MEMORY_BASE, 0); - pci_set_word(conf + PCI_MEMORY_LIMIT, 0xfff0); - pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0x1); - pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0xfff1); - pci_set_long(conf + PCI_PREF_BASE_UPPER32, 0x1); /* Hack */ - pci_set_long(conf + PCI_PREF_LIMIT_UPPER32, 0xffffffff); - pci_config_set_interrupt_pin(conf, 0); -} - -static void pnv_phb4_root_port_realize(DeviceState *dev, Error **errp) -{ - PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev); - Error *local_err = NULL; - - rpc->parent_realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - -static void pnv_phb4_root_port_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass); - - dc->desc = "IBM PHB4 PCIE Root Port"; - dc->user_creatable = false; - - device_class_set_parent_realize(dc, pnv_phb4_root_port_realize, - &rpc->parent_realize); - device_class_set_parent_reset(dc, pnv_phb4_root_port_reset, - &rpc->parent_reset); - - k->vendor_id = PCI_VENDOR_ID_IBM; - k->device_id = PNV_PHB4_DEVICE_ID; - k->revision = 0; - - rpc->exp_offset = 0x48; - rpc->aer_offset = 0x100; - - dc->reset = &pnv_phb4_root_port_reset; -} - -static const TypeInfo pnv_phb4_root_port_info = { - .name = TYPE_PNV_PHB4_ROOT_PORT, - .parent = TYPE_PCIE_ROOT_PORT, - .instance_size = sizeof(PnvPHB4RootPort), - .class_init = pnv_phb4_root_port_class_init, -}; - -static void pnv_phb5_root_port_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - dc->desc = "IBM PHB5 PCIE Root Port"; - dc->user_creatable = false; - - k->vendor_id = PCI_VENDOR_ID_IBM; - k->device_id = PNV_PHB5_DEVICE_ID; -} - -static const TypeInfo pnv_phb5_root_port_info = { - .name = TYPE_PNV_PHB5_ROOT_PORT, - .parent = TYPE_PNV_PHB4_ROOT_PORT, - .instance_size = sizeof(PnvPHB4RootPort), - .class_init = pnv_phb5_root_port_class_init, -}; - static void pnv_phb4_register_types(void) { type_register_static(&pnv_phb4_root_bus_info); - type_register_static(&pnv_phb5_root_port_info); - type_register_static(&pnv_phb4_root_port_info); type_register_static(&pnv_phb4_type_info); type_register_static(&pnv_phb5_type_info); type_register_static(&pnv_phb4_iommu_memory_region_info); diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index c9aaf1c28e..9871f462cd 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -115,8 +115,7 @@ static void pnv_pec_default_phb_realize(PnvPhb4PecState *pec, int stack_no, Error **errp) { - PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec); - PnvPHB4 *phb = PNV_PHB4(qdev_new(pecc->phb_type)); + PnvPHB *phb = PNV_PHB(qdev_new(TYPE_PNV_PHB)); int phb_id = pnv_phb4_pec_get_phb_id(pec, stack_no); object_property_add_child(OBJECT(pec), "phb[*]", OBJECT(phb)); @@ -147,8 +146,10 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp) pec->num_phbs = pecc->num_phbs[pec->index]; /* Create PHBs if running with defaults */ - for (i = 0; i < pec->num_phbs; i++) { - pnv_pec_default_phb_realize(pec, i, errp); + if (defaults_enabled()) { + for (i = 0; i < pec->num_phbs; i++) { + pnv_pec_default_phb_realize(pec, i, errp); + } } /* Initialize the XSCOM regions for the PEC registers */ @@ -261,7 +262,6 @@ static void pnv_pec_class_init(ObjectClass *klass, void *data) pecc->version = PNV_PHB4_VERSION; pecc->phb_type = TYPE_PNV_PHB4; pecc->num_phbs = pnv_pec_num_phbs; - pecc->rp_model = TYPE_PNV_PHB4_ROOT_PORT; } static const TypeInfo pnv_pec_type_info = { @@ -314,7 +314,6 @@ static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data) pecc->version = PNV_PHB5_VERSION; pecc->phb_type = TYPE_PNV_PHB5; pecc->num_phbs = pnv_phb5_pec_num_stacks; - pecc->rp_model = TYPE_PNV_PHB5_ROOT_PORT; } static const TypeInfo pnv_phb5_pec_type_info = { diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index 400511c6b7..3a4418a69e 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -58,7 +58,6 @@ config PPC4XX config SAM460EX bool - select PPC405 select PFLASH_CFI01 select IDE_SII3112 select M41T80 @@ -72,6 +71,7 @@ config SAM460EX config PEGASOS2 bool + imply ATI_VGA select MV64361 select VT82C686 select IDE_VIA @@ -79,7 +79,6 @@ config PEGASOS2 select VOF # This should come with VT82C686 select ACPI_X86 - imply ATI_VGA config PREP bool diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index aa4c8e6a2e..62801923f3 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -46,6 +46,7 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files( 'pnv_lpc.c', 'pnv_psi.c', 'pnv_occ.c', + 'pnv_sbe.c', 'pnv_bmc.c', 'pnv_homer.c', 'pnv_pnor.c', diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index d3f77c8367..78e00afb9b 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -43,6 +43,7 @@ #include "hw/ipmi/ipmi.h" #include "target/ppc/mmu-hash64.h" #include "hw/pci/msi.h" +#include "hw/pci-host/pnv_phb.h" #include "hw/ppc/xics.h" #include "hw/qdev-properties.h" @@ -137,7 +138,7 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) int smt_threads = CPU_CORE(pc)->nr_threads; CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); - uint32_t servers_prop[smt_threads]; + g_autofree uint32_t *servers_prop = g_new(uint32_t, smt_threads); int i; uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; @@ -240,7 +241,7 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) servers_prop[i] = cpu_to_be32(pc->pir + i); } _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", - servers_prop, sizeof(servers_prop)))); + servers_prop, sizeof(*servers_prop) * smt_threads))); } static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir, @@ -280,6 +281,75 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir, g_free(reg); } +static PnvPhb4PecState *pnv_phb4_get_pec(PnvChip *chip, PnvPHB4 *phb, + Error **errp) +{ + PnvPHB *phb_base = phb->phb_base; + PnvPhb4PecState *pecs = NULL; + int chip_id = phb->chip_id; + int index = phb->phb_id; + int i, j; + + if (phb_base->version == 4) { + Pnv9Chip *chip9 = PNV9_CHIP(chip); + + pecs = chip9->pecs; + } else if (phb_base->version == 5) { + Pnv10Chip *chip10 = PNV10_CHIP(chip); + + pecs = chip10->pecs; + } else { + g_assert_not_reached(); + } + + for (i = 0; i < chip->num_pecs; i++) { + /* + * For each PEC, check the amount of phbs it supports + * and see if the given phb4 index matches an index. + */ + PnvPhb4PecState *pec = &pecs[i]; + + for (j = 0; j < pec->num_phbs; j++) { + if (index == pnv_phb4_pec_get_phb_id(pec, j)) { + return pec; + } + } + } + error_setg(errp, + "pnv-phb4 chip-id %d index %d didn't match any existing PEC", + chip_id, index); + + return NULL; +} + +/* + * Adds a PnvPHB to the chip. Returns the parent obj of the + * PHB which varies with each version (phb version 3 is parented + * by the chip, version 4 and 5 are parented by the PEC + * device). + * + * TODO: for version 3 we're still parenting the PHB with the + * chip. We should parent with a (so far not implemented) + * PHB3 PEC device. + */ +Object *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp) +{ + if (phb->version == 3) { + Pnv8Chip *chip8 = PNV8_CHIP(chip); + + phb->chip = chip; + + chip8->phbs[chip8->num_phbs] = phb; + chip8->num_phbs++; + + return OBJECT(chip); + } + + phb->pec = pnv_phb4_get_pec(chip, PNV_PHB4(phb->backend), errp); + + return OBJECT(phb->pec); +} + static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt) { static const char compat[] = "ibm,power8-xscom\0ibm,xscom"; @@ -660,7 +730,8 @@ static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon) ics_pic_print_info(&chip8->psi.ics, mon); for (i = 0; i < chip8->num_phbs; i++) { - PnvPHB3 *phb3 = &chip8->phbs[i]; + PnvPHB *phb = chip8->phbs[i]; + PnvPHB3 *phb3 = PNV_PHB3(phb->backend); pnv_phb3_msi_pic_print_info(&phb3->msis, mon); ics_pic_print_info(&phb3->lsis, mon); @@ -670,11 +741,14 @@ static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon) static int pnv_chip_power9_pic_print_info_child(Object *child, void *opaque) { Monitor *mon = opaque; - PnvPHB4 *phb4 = (PnvPHB4 *) object_dynamic_cast(child, TYPE_PNV_PHB4); + PnvPHB *phb = (PnvPHB *) object_dynamic_cast(child, TYPE_PNV_PHB); - if (phb4) { - pnv_phb4_pic_print_info(phb4, mon); + if (!phb) { + return 0; } + + pnv_phb4_pic_print_info(PNV_PHB4(phb->backend), mon); + return 0; } @@ -714,7 +788,7 @@ static bool pnv_match_cpu(const char *default_type, const char *cpu_type) PowerPCCPUClass *ppc = POWERPC_CPU_CLASS(object_class_by_name(cpu_type)); - return ppc_default->pvr_match(ppc_default, ppc->pvr); + return ppc_default->pvr_match(ppc_default, ppc->pvr, false); } static void pnv_ipmi_bt_init(ISABus *bus, IPMIBmc *bmc, uint32_t irq) @@ -1146,10 +1220,22 @@ static void pnv_chip_power8_instance_init(Object *obj) object_initialize_child(obj, "homer", &chip8->homer, TYPE_PNV8_HOMER); - chip8->num_phbs = pcc->num_phbs; + if (defaults_enabled()) { + chip8->num_phbs = pcc->num_phbs; - for (i = 0; i < chip8->num_phbs; i++) { - object_initialize_child(obj, "phb[*]", &chip8->phbs[i], TYPE_PNV_PHB3); + for (i = 0; i < chip8->num_phbs; i++) { + Object *phb = object_new(TYPE_PNV_PHB); + + /* + * We need the chip to parent the PHB to allow the DT + * to build correctly (via pnv_xscom_dt()). + * + * TODO: the PHB should be parented by a PEC device that, at + * this moment, is not modelled powernv8/phb3. + */ + object_property_add_child(obj, "phb[*]", phb); + chip8->phbs[i] = PNV_PHB(phb); + } } } @@ -1183,30 +1269,6 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) } } -/* - * Attach a root port device. - * - * 'index' will be used both as a PCIE slot value and to calculate - * QOM id. 'chip_id' is going to be used as PCIE chassis for the - * root port. - */ -void pnv_phb_attach_root_port(PCIHostState *pci, const char *name, - int index, int chip_id) -{ - PCIDevice *root = pci_new(PCI_DEVFN(0, 0), name); - g_autofree char *default_id = g_strdup_printf("%s[%d]", name, index); - const char *dev_id = DEVICE(root)->id; - - object_property_add_child(OBJECT(pci->bus), dev_id ? dev_id : default_id, - OBJECT(root)); - - /* Set unique chassis/slot values for the root port */ - qdev_prop_set_uint8(DEVICE(root), "chassis", chip_id); - qdev_prop_set_uint16(DEVICE(root), "slot", index); - - pci_realize_and_unref(root, pci->bus, &error_fatal); -} - static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) { PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev); @@ -1287,9 +1349,9 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip), &chip8->homer.regs); - /* PHB3 controllers */ + /* PHB controllers */ for (i = 0; i < chip8->num_phbs; i++) { - PnvPHB3 *phb = &chip8->phbs[i]; + PnvPHB *phb = chip8->phbs[i]; object_property_set_int(OBJECT(phb), "index", i, &error_fatal); object_property_set_int(OBJECT(phb), "chip-id", chip->chip_id, @@ -1397,6 +1459,8 @@ static void pnv_chip_power9_instance_init(Object *obj) object_initialize_child(obj, "occ", &chip9->occ, TYPE_PNV9_OCC); + object_initialize_child(obj, "sbe", &chip9->sbe, TYPE_PNV9_SBE); + object_initialize_child(obj, "homer", &chip9->homer, TYPE_PNV9_HOMER); /* Number of PECs is the chip default */ @@ -1549,6 +1613,17 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(get_system_memory(), PNV9_OCC_SENSOR_BASE(chip), &chip9->occ.sram_regs); + /* SBE */ + if (!qdev_realize(DEVICE(&chip9->sbe), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV9_XSCOM_SBE_CTRL_BASE, + &chip9->sbe.xscom_ctrl_regs); + pnv_xscom_add_subregion(chip, PNV9_XSCOM_SBE_MBOX_BASE, + &chip9->sbe.xscom_mbox_regs); + qdev_connect_gpio_out(DEVICE(&chip9->sbe), 0, qdev_get_gpio_in( + DEVICE(&chip9->psi), PSIHB9_IRQ_PSU)); + /* HOMER */ object_property_set_link(OBJECT(&chip9->homer), "chip", OBJECT(chip), &error_abort); @@ -1613,6 +1688,7 @@ static void pnv_chip_power10_instance_init(Object *obj) object_initialize_child(obj, "psi", &chip10->psi, TYPE_PNV10_PSI); object_initialize_child(obj, "lpc", &chip10->lpc, TYPE_PNV10_LPC); object_initialize_child(obj, "occ", &chip10->occ, TYPE_PNV10_OCC); + object_initialize_child(obj, "sbe", &chip10->sbe, TYPE_PNV10_SBE); object_initialize_child(obj, "homer", &chip10->homer, TYPE_PNV10_HOMER); chip->num_pecs = pcc->num_pecs; @@ -1754,6 +1830,17 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) PNV10_OCC_SENSOR_BASE(chip), &chip10->occ.sram_regs); + /* SBE */ + if (!qdev_realize(DEVICE(&chip10->sbe), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV10_XSCOM_SBE_CTRL_BASE, + &chip10->sbe.xscom_ctrl_regs); + pnv_xscom_add_subregion(chip, PNV10_XSCOM_SBE_MBOX_BASE, + &chip10->sbe.xscom_mbox_regs); + qdev_connect_gpio_out(DEVICE(&chip10->sbe), 0, qdev_get_gpio_in( + DEVICE(&chip10->psi), PSIHB9_IRQ_PSU)); + /* HOMER */ object_property_set_link(OBJECT(&chip10->homer), "chip", OBJECT(chip), &error_abort); @@ -1957,7 +2044,8 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq) } for (j = 0; j < chip8->num_phbs; j++) { - PnvPHB3 *phb3 = &chip8->phbs[j]; + PnvPHB *phb = chip8->phbs[j]; + PnvPHB3 *phb3 = PNV_PHB3(phb->backend); if (ics_valid_irq(&phb3->lsis, irq)) { return &phb3->lsis; @@ -1995,7 +2083,8 @@ static void pnv_ics_resend(XICSFabric *xi) ics_resend(&chip8->psi.ics); for (j = 0; j < chip8->num_phbs; j++) { - PnvPHB3 *phb3 = &chip8->phbs[j]; + PnvPHB *phb = chip8->phbs[j]; + PnvPHB3 *phb3 = PNV_PHB3(phb->backend); ics_resend(&phb3->lsis); ics_resend(ICS(&phb3->msis)); @@ -2095,8 +2184,14 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data) PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc); static const char compat[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv"; + static GlobalProperty phb_compat[] = { + { TYPE_PNV_PHB, "version", "3" }, + { TYPE_PNV_PHB_ROOT_PORT, "version", "3" }, + }; + mc->desc = "IBM PowerNV (Non-Virtualized) POWER8"; mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); + compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat)); xic->icp_get = pnv_icp_get; xic->ics_get = pnv_ics_get; @@ -2104,6 +2199,8 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data) pmc->compat = compat; pmc->compat_size = sizeof(compat); + + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB); } static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) @@ -2113,8 +2210,15 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc); static const char compat[] = "qemu,powernv9\0ibm,powernv"; + static GlobalProperty phb_compat[] = { + { TYPE_PNV_PHB, "version", "4" }, + { TYPE_PNV_PHB_ROOT_PORT, "version", "4" }, + }; + mc->desc = "IBM PowerNV (Non-Virtualized) POWER9"; mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0"); + compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat)); + xfc->match_nvt = pnv_match_nvt; mc->alias = "powernv"; @@ -2122,6 +2226,8 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) pmc->compat = compat; pmc->compat_size = sizeof(compat); pmc->dt_power_mgt = pnv_dt_power_mgt; + + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB); } static void pnv_machine_power10_class_init(ObjectClass *oc, void *data) @@ -2131,14 +2237,22 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data) XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc); static const char compat[] = "qemu,powernv10\0ibm,powernv"; + static GlobalProperty phb_compat[] = { + { TYPE_PNV_PHB, "version", "5" }, + { TYPE_PNV_PHB_ROOT_PORT, "version", "5" }, + }; + mc->desc = "IBM PowerNV (Non-Virtualized) POWER10"; mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power10_v2.0"); + compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat)); pmc->compat = compat; pmc->compat_size = sizeof(compat); pmc->dt_power_mgt = pnv_dt_power_mgt; xfc->match_nvt = pnv10_xive_match_nvt; + + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB); } static bool pnv_machine_get_hb(Object *obj, Error **errp) diff --git a/hw/ppc/pnv_sbe.c b/hw/ppc/pnv_sbe.c new file mode 100644 index 0000000000..1c7812a135 --- /dev/null +++ b/hw/ppc/pnv_sbe.c @@ -0,0 +1,414 @@ +/* + * QEMU PowerPC PowerNV Emulation of some SBE behaviour + * + * Copyright (c) 2022, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "target/ppc/cpu.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_xscom.h" +#include "hw/ppc/pnv_sbe.h" +#include "trace.h" + +/* + * Most register and command definitions come from skiboot. + * + * xscom addresses are adjusted to be relative to xscom subregion bases + */ + +/* + * SBE MBOX register address + * Reg 0 - 3 : Host to send command packets to SBE + * Reg 4 - 7 : SBE to send response packets to Host + */ +#define PSU_HOST_SBE_MBOX_REG0 0x00000000 +#define PSU_HOST_SBE_MBOX_REG1 0x00000001 +#define PSU_HOST_SBE_MBOX_REG2 0x00000002 +#define PSU_HOST_SBE_MBOX_REG3 0x00000003 +#define PSU_HOST_SBE_MBOX_REG4 0x00000004 +#define PSU_HOST_SBE_MBOX_REG5 0x00000005 +#define PSU_HOST_SBE_MBOX_REG6 0x00000006 +#define PSU_HOST_SBE_MBOX_REG7 0x00000007 +#define PSU_SBE_DOORBELL_REG_RW 0x00000010 +#define PSU_SBE_DOORBELL_REG_AND 0x00000011 +#define PSU_SBE_DOORBELL_REG_OR 0x00000012 +#define PSU_HOST_DOORBELL_REG_RW 0x00000013 +#define PSU_HOST_DOORBELL_REG_AND 0x00000014 +#define PSU_HOST_DOORBELL_REG_OR 0x00000015 + +/* + * Doorbell register to trigger SBE interrupt. Set by OPAL to inform + * the SBE about a waiting message in the Host/SBE mailbox registers + */ +#define HOST_SBE_MSG_WAITING PPC_BIT(0) + +/* + * Doorbell register for host bridge interrupt. Set by the SBE to inform + * host about a response message in the Host/SBE mailbox registers + */ +#define SBE_HOST_RESPONSE_WAITING PPC_BIT(0) +#define SBE_HOST_MSG_READ PPC_BIT(1) +#define SBE_HOST_STOP15_EXIT PPC_BIT(2) +#define SBE_HOST_RESET PPC_BIT(3) +#define SBE_HOST_PASSTHROUGH PPC_BIT(4) +#define SBE_HOST_TIMER_EXPIRY PPC_BIT(14) +#define SBE_HOST_RESPONSE_MASK (PPC_BITMASK(0, 4) | \ + SBE_HOST_TIMER_EXPIRY) + +/* SBE Control Register */ +#define SBE_CONTROL_REG_RW 0x00000000 + +/* SBE interrupt s0/s1 bits */ +#define SBE_CONTROL_REG_S0 PPC_BIT(14) +#define SBE_CONTROL_REG_S1 PPC_BIT(15) + +struct sbe_msg { + uint64_t reg[4]; +}; + +static uint64_t pnv_sbe_power9_xscom_ctrl_read(void *opaque, hwaddr addr, + unsigned size) +{ + uint32_t offset = addr >> 3; + uint64_t val = 0; + + switch (offset) { + default: + qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%" + HWADDR_PRIx "\n", addr >> 3); + } + + trace_pnv_sbe_xscom_ctrl_read(addr, val); + + return val; +} + +static void pnv_sbe_power9_xscom_ctrl_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + uint32_t offset = addr >> 3; + + trace_pnv_sbe_xscom_ctrl_write(addr, val); + + switch (offset) { + default: + qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%" + HWADDR_PRIx "\n", addr >> 3); + } +} + +static const MemoryRegionOps pnv_sbe_power9_xscom_ctrl_ops = { + .read = pnv_sbe_power9_xscom_ctrl_read, + .write = pnv_sbe_power9_xscom_ctrl_write, + .valid.min_access_size = 8, + .valid.max_access_size = 8, + .impl.min_access_size = 8, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void pnv_sbe_set_host_doorbell(PnvSBE *sbe, uint64_t val) +{ + val &= SBE_HOST_RESPONSE_MASK; /* Is this right? What does HW do? */ + sbe->host_doorbell = val; + + trace_pnv_sbe_reg_set_host_doorbell(val); + qemu_set_irq(sbe->psi_irq, !!val); +} + +/* SBE Target Type */ +#define SBE_TARGET_TYPE_PROC 0x00 +#define SBE_TARGET_TYPE_EX 0x01 +#define SBE_TARGET_TYPE_PERV 0x02 +#define SBE_TARGET_TYPE_MCS 0x03 +#define SBE_TARGET_TYPE_EQ 0x04 +#define SBE_TARGET_TYPE_CORE 0x05 + +/* SBE MBOX command class */ +#define SBE_MCLASS_FIRST 0xD1 +#define SBE_MCLASS_CORE_STATE 0xD1 +#define SBE_MCLASS_SCOM 0xD2 +#define SBE_MCLASS_RING 0xD3 +#define SBE_MCLASS_TIMER 0xD4 +#define SBE_MCLASS_MPIPL 0xD5 +#define SBE_MCLASS_SECURITY 0xD6 +#define SBE_MCLASS_GENERIC 0xD7 +#define SBE_MCLASS_LAST 0xD7 + +/* + * Commands are provided in xxyy form where: + * - xx : command class + * - yy : command + * + * Both request and response message uses same seq ID, + * command class and command. + */ +#define SBE_CMD_CTRL_DEADMAN_LOOP 0xD101 +#define SBE_CMD_MULTI_SCOM 0xD201 +#define SBE_CMD_PUT_RING_FORM_IMAGE 0xD301 +#define SBE_CMD_CONTROL_TIMER 0xD401 +#define SBE_CMD_GET_ARCHITECTED_REG 0xD501 +#define SBE_CMD_CLR_ARCHITECTED_REG 0xD502 +#define SBE_CMD_SET_UNSEC_MEM_WINDOW 0xD601 +#define SBE_CMD_GET_SBE_FFDC 0xD701 +#define SBE_CMD_GET_CAPABILITY 0xD702 +#define SBE_CMD_READ_SBE_SEEPROM 0xD703 +#define SBE_CMD_SET_FFDC_ADDR 0xD704 +#define SBE_CMD_QUIESCE_SBE 0xD705 +#define SBE_CMD_SET_FABRIC_ID_MAP 0xD706 +#define SBE_CMD_STASH_MPIPL_CONFIG 0xD707 + +/* SBE MBOX control flags */ + +/* Generic flags */ +#define SBE_CMD_CTRL_RESP_REQ 0x0100 +#define SBE_CMD_CTRL_ACK_REQ 0x0200 + +/* Deadman loop */ +#define CTRL_DEADMAN_LOOP_START 0x0001 +#define CTRL_DEADMAN_LOOP_STOP 0x0002 + +/* Control timer */ +#define CONTROL_TIMER_START 0x0001 +#define CONTROL_TIMER_STOP 0x0002 + +/* Stash MPIPL config */ +#define SBE_STASH_KEY_SKIBOOT_BASE 0x03 + +static void sbe_timer(void *opaque) +{ + PnvSBE *sbe = opaque; + + trace_pnv_sbe_cmd_timer_expired(); + + pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_TIMER_EXPIRY); +} + +static void do_sbe_msg(PnvSBE *sbe) +{ + struct sbe_msg msg; + uint16_t cmd, ctrl_flags, seq_id; + int i; + + memset(&msg, 0, sizeof(msg)); + + for (i = 0; i < 4; i++) { + msg.reg[i] = sbe->mbox[i]; + } + + cmd = msg.reg[0]; + seq_id = msg.reg[0] >> 16; + ctrl_flags = msg.reg[0] >> 32; + + trace_pnv_sbe_msg_recv(cmd, seq_id, ctrl_flags); + + if (ctrl_flags & SBE_CMD_CTRL_ACK_REQ) { + pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_MSG_READ); + } + + switch (cmd) { + case SBE_CMD_CONTROL_TIMER: + if (ctrl_flags & CONTROL_TIMER_START) { + uint64_t us = msg.reg[1]; + trace_pnv_sbe_cmd_timer_start(us); + timer_mod(sbe->timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + us); + } + if (ctrl_flags & CONTROL_TIMER_STOP) { + trace_pnv_sbe_cmd_timer_stop(); + timer_del(sbe->timer); + } + break; + default: + qemu_log_mask(LOG_UNIMP, "SBE Unimplemented command: 0x%x\n", cmd); + } +} + +static void pnv_sbe_set_sbe_doorbell(PnvSBE *sbe, uint64_t val) +{ + val &= HOST_SBE_MSG_WAITING; + sbe->sbe_doorbell = val; + + if (val & HOST_SBE_MSG_WAITING) { + sbe->sbe_doorbell &= ~HOST_SBE_MSG_WAITING; + do_sbe_msg(sbe); + } +} + +static uint64_t pnv_sbe_power9_xscom_mbox_read(void *opaque, hwaddr addr, + unsigned size) +{ + PnvSBE *sbe = PNV_SBE(opaque); + uint32_t offset = addr >> 3; + uint64_t val = 0; + + if (offset <= PSU_HOST_SBE_MBOX_REG7) { + uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0; + val = sbe->mbox[idx]; + } else { + switch (offset) { + case PSU_SBE_DOORBELL_REG_RW: + val = sbe->sbe_doorbell; + break; + case PSU_HOST_DOORBELL_REG_RW: + val = sbe->host_doorbell; + break; + default: + qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%" + HWADDR_PRIx "\n", addr >> 3); + } + } + + trace_pnv_sbe_xscom_mbox_read(addr, val); + + return val; +} + +static void pnv_sbe_power9_xscom_mbox_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PnvSBE *sbe = PNV_SBE(opaque); + uint32_t offset = addr >> 3; + + trace_pnv_sbe_xscom_mbox_write(addr, val); + + if (offset <= PSU_HOST_SBE_MBOX_REG7) { + uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0; + sbe->mbox[idx] = val; + } else { + switch (offset) { + case PSU_SBE_DOORBELL_REG_RW: + pnv_sbe_set_sbe_doorbell(sbe, val); + break; + case PSU_SBE_DOORBELL_REG_AND: + pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell & val); + break; + case PSU_SBE_DOORBELL_REG_OR: + pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell | val); + break; + + case PSU_HOST_DOORBELL_REG_RW: + pnv_sbe_set_host_doorbell(sbe, val); + break; + case PSU_HOST_DOORBELL_REG_AND: + pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell & val); + break; + case PSU_HOST_DOORBELL_REG_OR: + pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | val); + break; + + default: + qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%" + HWADDR_PRIx "\n", addr >> 3); + } + } +} + +static const MemoryRegionOps pnv_sbe_power9_xscom_mbox_ops = { + .read = pnv_sbe_power9_xscom_mbox_read, + .write = pnv_sbe_power9_xscom_mbox_write, + .valid.min_access_size = 8, + .valid.max_access_size = 8, + .impl.min_access_size = 8, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void pnv_sbe_power9_class_init(ObjectClass *klass, void *data) +{ + PnvSBEClass *psc = PNV_SBE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "PowerNV SBE Controller (POWER9)"; + psc->xscom_ctrl_size = PNV9_XSCOM_SBE_CTRL_SIZE; + psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops; + psc->xscom_mbox_size = PNV9_XSCOM_SBE_MBOX_SIZE; + psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops; +} + +static const TypeInfo pnv_sbe_power9_type_info = { + .name = TYPE_PNV9_SBE, + .parent = TYPE_PNV_SBE, + .instance_size = sizeof(PnvSBE), + .class_init = pnv_sbe_power9_class_init, +}; + +static void pnv_sbe_power10_class_init(ObjectClass *klass, void *data) +{ + PnvSBEClass *psc = PNV_SBE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "PowerNV SBE Controller (POWER10)"; + psc->xscom_ctrl_size = PNV10_XSCOM_SBE_CTRL_SIZE; + psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops; + psc->xscom_mbox_size = PNV10_XSCOM_SBE_MBOX_SIZE; + psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops; +} + +static const TypeInfo pnv_sbe_power10_type_info = { + .name = TYPE_PNV10_SBE, + .parent = TYPE_PNV9_SBE, + .class_init = pnv_sbe_power10_class_init, +}; + +static void pnv_sbe_realize(DeviceState *dev, Error **errp) +{ + PnvSBE *sbe = PNV_SBE(dev); + PnvSBEClass *psc = PNV_SBE_GET_CLASS(sbe); + + /* XScom regions for SBE registers */ + pnv_xscom_region_init(&sbe->xscom_ctrl_regs, OBJECT(dev), + psc->xscom_ctrl_ops, sbe, "xscom-sbe-ctrl", + psc->xscom_ctrl_size); + pnv_xscom_region_init(&sbe->xscom_mbox_regs, OBJECT(dev), + psc->xscom_mbox_ops, sbe, "xscom-sbe-mbox", + psc->xscom_mbox_size); + + qdev_init_gpio_out(DEVICE(dev), &sbe->psi_irq, 1); + + sbe->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, sbe_timer, sbe); +} + +static void pnv_sbe_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pnv_sbe_realize; + dc->desc = "PowerNV SBE Controller"; + dc->user_creatable = false; +} + +static const TypeInfo pnv_sbe_type_info = { + .name = TYPE_PNV_SBE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(PnvSBE), + .class_init = pnv_sbe_class_init, + .class_size = sizeof(PnvSBEClass), + .abstract = true, +}; + +static void pnv_sbe_register_types(void) +{ + type_register_static(&pnv_sbe_type_info); + type_register_static(&pnv_sbe_power9_type_info); + type_register_static(&pnv_sbe_power10_type_info); +} + +type_init(pnv_sbe_register_types); diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 9ce018dbc2..79f10de57f 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -295,6 +295,9 @@ int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset, _FDT((fdt_setprop(fdt, xscom_offset, "reg", reg, sizeof(reg)))); _FDT((fdt_setprop(fdt, xscom_offset, "compatible", compat, compat_size))); _FDT((fdt_setprop(fdt, xscom_offset, "scom-controller", NULL, 0))); + if (chip->chip_id == 0) { + _FDT((fdt_setprop(fdt, xscom_offset, "primary", NULL, 0))); + } args.fdt = fdt; args.xscom_offset = xscom_offset; diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h index 83f156f585..1e558c7831 100644 --- a/hw/ppc/ppc405.h +++ b/hw/ppc/ppc405.h @@ -25,54 +25,168 @@ #ifndef PPC405_H #define PPC405_H +#include "qom/object.h" #include "hw/ppc/ppc4xx.h" +#include "hw/intc/ppc-uic.h" +#include "hw/i2c/ppc4xx_i2c.h" -#define PPC405EP_SDRAM_BASE 0x00000000 -#define PPC405EP_NVRAM_BASE 0xF0000000 -#define PPC405EP_FPGA_BASE 0xF0300000 -#define PPC405EP_SRAM_BASE 0xFFF00000 -#define PPC405EP_SRAM_SIZE (512 * KiB) -#define PPC405EP_FLASH_BASE 0xFFF80000 +/* PLB to OPB bridge */ +#define TYPE_PPC405_POB "ppc405-pob" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405PobState, PPC405_POB); +struct Ppc405PobState { + Ppc4xxDcrDeviceState parent_obj; -/* Bootinfo as set-up by u-boot */ -typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t; -struct ppc4xx_bd_info_t { - uint32_t bi_memstart; - uint32_t bi_memsize; - uint32_t bi_flashstart; - uint32_t bi_flashsize; - uint32_t bi_flashoffset; /* 0x10 */ - uint32_t bi_sramstart; - uint32_t bi_sramsize; - uint32_t bi_bootflags; - uint32_t bi_ipaddr; /* 0x20 */ - uint8_t bi_enetaddr[6]; - uint16_t bi_ethspeed; - uint32_t bi_intfreq; - uint32_t bi_busfreq; /* 0x30 */ - uint32_t bi_baudrate; - uint8_t bi_s_version[4]; - uint8_t bi_r_version[32]; - uint32_t bi_procfreq; - uint32_t bi_plb_busfreq; - uint32_t bi_pci_busfreq; - uint8_t bi_pci_enetaddr[6]; - uint8_t bi_pci_enetaddr2[6]; /* PPC405EP specific */ - uint32_t bi_opbfreq; - uint32_t bi_iic_fast[2]; + uint32_t bear; + uint32_t besr0; + uint32_t besr1; }; -/* PowerPC 405 core */ -ram_addr_t ppc405_set_bootinfo(CPUPPCState *env, ram_addr_t ram_size); +/* OPB arbitrer */ +#define TYPE_PPC405_OPBA "ppc405-opba" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405OpbaState, PPC405_OPBA); +struct Ppc405OpbaState { + SysBusDevice parent_obj; -void ppc4xx_plb_init(CPUPPCState *env); -void ppc405_ebc_init(CPUPPCState *env); + MemoryRegion io; + uint8_t cr; + uint8_t pr; +}; -PowerPCCPU *ppc405ep_init(MemoryRegion *address_space_mem, - MemoryRegion ram_memories[2], - hwaddr ram_bases[2], - hwaddr ram_sizes[2], - uint32_t sysclk, DeviceState **uicdev, - int do_init); +/* DMA controller */ +#define TYPE_PPC405_DMA "ppc405-dma" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405DmaState, PPC405_DMA); +struct Ppc405DmaState { + Ppc4xxDcrDeviceState parent_obj; + + qemu_irq irqs[4]; + uint32_t cr[4]; + uint32_t ct[4]; + uint32_t da[4]; + uint32_t sa[4]; + uint32_t sg[4]; + uint32_t sr; + uint32_t sgc; + uint32_t slp; + uint32_t pol; +}; + +/* GPIO */ +#define TYPE_PPC405_GPIO "ppc405-gpio" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405GpioState, PPC405_GPIO); +struct Ppc405GpioState { + SysBusDevice parent_obj; + + MemoryRegion io; + uint32_t or; + uint32_t tcr; + uint32_t osrh; + uint32_t osrl; + uint32_t tsrh; + uint32_t tsrl; + uint32_t odr; + uint32_t ir; + uint32_t rr1; + uint32_t isr1h; + uint32_t isr1l; +}; + +/* On Chip Memory */ +#define TYPE_PPC405_OCM "ppc405-ocm" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405OcmState, PPC405_OCM); +struct Ppc405OcmState { + Ppc4xxDcrDeviceState parent_obj; + + MemoryRegion ram; + MemoryRegion isarc_ram; + MemoryRegion dsarc_ram; + uint32_t isarc; + uint32_t isacntl; + uint32_t dsarc; + uint32_t dsacntl; +}; + +/* General purpose timers */ +#define TYPE_PPC405_GPT "ppc405-gpt" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405GptState, PPC405_GPT); +struct Ppc405GptState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + + int64_t tb_offset; + uint32_t tb_freq; + QEMUTimer *timer; + qemu_irq irqs[5]; + uint32_t oe; + uint32_t ol; + uint32_t im; + uint32_t is; + uint32_t ie; + uint32_t comp[5]; + uint32_t mask[5]; +}; + +#define TYPE_PPC405_CPC "ppc405-cpc" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405CpcState, PPC405_CPC); + +enum { + PPC405EP_CPU_CLK = 0, + PPC405EP_PLB_CLK = 1, + PPC405EP_OPB_CLK = 2, + PPC405EP_EBC_CLK = 3, + PPC405EP_MAL_CLK = 4, + PPC405EP_PCI_CLK = 5, + PPC405EP_UART0_CLK = 6, + PPC405EP_UART1_CLK = 7, + PPC405EP_CLK_NB = 8, +}; + +struct Ppc405CpcState { + Ppc4xxDcrDeviceState parent_obj; + + uint32_t sysclk; + clk_setup_t clk_setup[PPC405EP_CLK_NB]; + uint32_t boot; + uint32_t epctl; + uint32_t pllmr[2]; + uint32_t ucr; + uint32_t srr; + uint32_t jtagid; + uint32_t pci; + /* Clock and power management */ + uint32_t er; + uint32_t fr; + uint32_t sr; +}; + +#define TYPE_PPC405_SOC "ppc405-soc" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405SoCState, PPC405_SOC); + +struct Ppc405SoCState { + /* Private */ + DeviceState parent_obj; + + /* Public */ + MemoryRegion ram_banks[2]; + hwaddr ram_bases[2], ram_sizes[2]; + bool do_dram_init; + + MemoryRegion *dram_mr; + hwaddr ram_size; + + PowerPCCPU cpu; + PPCUIC uic; + Ppc405CpcState cpc; + Ppc405GptState gpt; + Ppc405OcmState ocm; + Ppc405GpioState gpio; + Ppc405DmaState dma; + PPC4xxI2CState i2c; + Ppc4xxEbcState ebc; + Ppc405OpbaState opba; + Ppc405PobState pob; + Ppc4xxPlbState plb; + Ppc4xxMalState mal; +}; #endif /* PPC405_H */ diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index a66ad05e3a..083f12b23e 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -48,97 +48,24 @@ #define KERNEL_LOAD_ADDR 0x01000000 #define INITRD_LOAD_ADDR 0x01800000 +#define PPC405EP_SDRAM_BASE 0x00000000 +#define PPC405EP_SRAM_BASE 0xFFF00000 +#define PPC405EP_SRAM_SIZE (512 * KiB) + #define USE_FLASH_BIOS -/*****************************************************************************/ -/* PPC405EP reference board (IBM) */ -/* Standalone board with: - * - PowerPC 405EP CPU - * - SDRAM (0x00000000) - * - Flash (0xFFF80000) - * - SRAM (0xFFF00000) - * - NVRAM (0xF0000000) - * - FPGA (0xF0300000) - */ -typedef struct ref405ep_fpga_t ref405ep_fpga_t; -struct ref405ep_fpga_t { - uint8_t reg0; - uint8_t reg1; +#define TYPE_PPC405_MACHINE MACHINE_TYPE_NAME("ppc405") +OBJECT_DECLARE_SIMPLE_TYPE(Ppc405MachineState, PPC405_MACHINE); + +struct Ppc405MachineState { + /* Private */ + MachineState parent_obj; + /* Public */ + + Ppc405SoCState soc; }; -static uint64_t ref405ep_fpga_readb(void *opaque, hwaddr addr, unsigned size) -{ - ref405ep_fpga_t *fpga; - uint32_t ret; - - fpga = opaque; - switch (addr) { - case 0x0: - ret = fpga->reg0; - break; - case 0x1: - ret = fpga->reg1; - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - ref405ep_fpga_t *fpga; - - fpga = opaque; - switch (addr) { - case 0x0: - /* Read only */ - break; - case 0x1: - fpga->reg1 = value; - break; - default: - break; - } -} - -static const MemoryRegionOps ref405ep_fpga_ops = { - .read = ref405ep_fpga_readb, - .write = ref405ep_fpga_writeb, - .impl.min_access_size = 1, - .impl.max_access_size = 1, - .valid.min_access_size = 1, - .valid.max_access_size = 4, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static void ref405ep_fpga_reset (void *opaque) -{ - ref405ep_fpga_t *fpga; - - fpga = opaque; - fpga->reg0 = 0x00; - fpga->reg1 = 0x0F; -} - -static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base) -{ - ref405ep_fpga_t *fpga; - MemoryRegion *fpga_memory = g_new(MemoryRegion, 1); - - fpga = g_new0(ref405ep_fpga_t, 1); - memory_region_init_io(fpga_memory, NULL, &ref405ep_fpga_ops, fpga, - "fpga", 0x00000100); - memory_region_add_subregion(sysmem, base, fpga_memory); - qemu_register_reset(&ref405ep_fpga_reset, fpga); -} - -/* - * CPU reset handler when booting directly from a loaded kernel - */ +/* CPU reset handler when booting directly from a loaded kernel */ static struct boot_info { uint32_t entry; uint32_t bdloc; @@ -169,6 +96,126 @@ static void main_cpu_reset(void *opaque) env->nip = bi->entry; } +/* Bootinfo as set-up by u-boot */ +typedef struct { + uint32_t bi_memstart; + uint32_t bi_memsize; + uint32_t bi_flashstart; + uint32_t bi_flashsize; + uint32_t bi_flashoffset; /* 0x10 */ + uint32_t bi_sramstart; + uint32_t bi_sramsize; + uint32_t bi_bootflags; + uint32_t bi_ipaddr; /* 0x20 */ + uint8_t bi_enetaddr[6]; + uint16_t bi_ethspeed; + uint32_t bi_intfreq; + uint32_t bi_busfreq; /* 0x30 */ + uint32_t bi_baudrate; + uint8_t bi_s_version[4]; + uint8_t bi_r_version[32]; + uint32_t bi_procfreq; + uint32_t bi_plb_busfreq; + uint32_t bi_pci_busfreq; + uint8_t bi_pci_enetaddr[6]; + uint8_t bi_pci_enetaddr2[6]; /* PPC405EP specific */ + uint32_t bi_opbfreq; + uint32_t bi_iic_fast[2]; +} ppc4xx_bd_info_t; + +static void ppc405_set_default_bootinfo(ppc4xx_bd_info_t *bd, + ram_addr_t ram_size) +{ + memset(bd, 0, sizeof(*bd)); + + bd->bi_memstart = PPC405EP_SDRAM_BASE; + bd->bi_memsize = ram_size; + bd->bi_sramstart = PPC405EP_SRAM_BASE; + bd->bi_sramsize = PPC405EP_SRAM_SIZE; + bd->bi_bootflags = 0; + bd->bi_intfreq = 133333333; + bd->bi_busfreq = 33333333; + bd->bi_baudrate = 115200; + bd->bi_s_version[0] = 'Q'; + bd->bi_s_version[1] = 'M'; + bd->bi_s_version[2] = 'U'; + bd->bi_s_version[3] = '\0'; + bd->bi_r_version[0] = 'Q'; + bd->bi_r_version[1] = 'E'; + bd->bi_r_version[2] = 'M'; + bd->bi_r_version[3] = 'U'; + bd->bi_r_version[4] = '\0'; + bd->bi_procfreq = 133333333; + bd->bi_plb_busfreq = 33333333; + bd->bi_pci_busfreq = 33333333; + bd->bi_opbfreq = 33333333; +} + +static ram_addr_t __ppc405_set_bootinfo(CPUPPCState *env, ppc4xx_bd_info_t *bd) +{ + CPUState *cs = env_cpu(env); + ram_addr_t bdloc; + int i, n; + + /* We put the bd structure at the top of memory */ + if (bd->bi_memsize >= 0x01000000UL) { + bdloc = 0x01000000UL - sizeof(ppc4xx_bd_info_t); + } else { + bdloc = bd->bi_memsize - sizeof(ppc4xx_bd_info_t); + } + stl_be_phys(cs->as, bdloc + 0x00, bd->bi_memstart); + stl_be_phys(cs->as, bdloc + 0x04, bd->bi_memsize); + stl_be_phys(cs->as, bdloc + 0x08, bd->bi_flashstart); + stl_be_phys(cs->as, bdloc + 0x0C, bd->bi_flashsize); + stl_be_phys(cs->as, bdloc + 0x10, bd->bi_flashoffset); + stl_be_phys(cs->as, bdloc + 0x14, bd->bi_sramstart); + stl_be_phys(cs->as, bdloc + 0x18, bd->bi_sramsize); + stl_be_phys(cs->as, bdloc + 0x1C, bd->bi_bootflags); + stl_be_phys(cs->as, bdloc + 0x20, bd->bi_ipaddr); + for (i = 0; i < 6; i++) { + stb_phys(cs->as, bdloc + 0x24 + i, bd->bi_enetaddr[i]); + } + stw_be_phys(cs->as, bdloc + 0x2A, bd->bi_ethspeed); + stl_be_phys(cs->as, bdloc + 0x2C, bd->bi_intfreq); + stl_be_phys(cs->as, bdloc + 0x30, bd->bi_busfreq); + stl_be_phys(cs->as, bdloc + 0x34, bd->bi_baudrate); + for (i = 0; i < 4; i++) { + stb_phys(cs->as, bdloc + 0x38 + i, bd->bi_s_version[i]); + } + for (i = 0; i < 32; i++) { + stb_phys(cs->as, bdloc + 0x3C + i, bd->bi_r_version[i]); + } + stl_be_phys(cs->as, bdloc + 0x5C, bd->bi_procfreq); + stl_be_phys(cs->as, bdloc + 0x60, bd->bi_plb_busfreq); + stl_be_phys(cs->as, bdloc + 0x64, bd->bi_pci_busfreq); + for (i = 0; i < 6; i++) { + stb_phys(cs->as, bdloc + 0x68 + i, bd->bi_pci_enetaddr[i]); + } + n = 0x70; /* includes 2 bytes hole */ + for (i = 0; i < 6; i++) { + stb_phys(cs->as, bdloc + n++, bd->bi_pci_enetaddr2[i]); + } + stl_be_phys(cs->as, bdloc + n, bd->bi_opbfreq); + n += 4; + for (i = 0; i < 2; i++) { + stl_be_phys(cs->as, bdloc + n, bd->bi_iic_fast[i]); + n += 4; + } + + return bdloc; +} + +static ram_addr_t ppc405_set_bootinfo(CPUPPCState *env, ram_addr_t ram_size) +{ + ppc4xx_bd_info_t bd; + + memset(&bd, 0, sizeof(bd)); + + ppc405_set_default_bootinfo(&bd, ram_size); + + return __ppc405_set_bootinfo(env, &bd); +} + static void boot_from_kernel(MachineState *machine, PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; @@ -221,18 +268,12 @@ static void boot_from_kernel(MachineState *machine, PowerPCCPU *cpu) env->load_info = &boot_info; } -static void ref405ep_init(MachineState *machine) +static void ppc405_init(MachineState *machine) { + Ppc405MachineState *ppc405 = PPC405_MACHINE(machine); MachineClass *mc = MACHINE_GET_CLASS(machine); const char *kernel_filename = machine->kernel_filename; - PowerPCCPU *cpu; - DeviceState *dev; - SysBusDevice *s; - MemoryRegion *sram = g_new(MemoryRegion, 1); - MemoryRegion *ram_memories = g_new(MemoryRegion, 2); - hwaddr ram_bases[2], ram_sizes[2]; MemoryRegion *sysmem = get_system_memory(); - DeviceState *uicdev; if (machine->ram_size != mc->default_ram_size) { char *sz = size_to_str(mc->default_ram_size); @@ -241,22 +282,17 @@ static void ref405ep_init(MachineState *machine) exit(EXIT_FAILURE); } - /* XXX: fix this */ - memory_region_init_alias(&ram_memories[0], NULL, "ef405ep.ram.alias", - machine->ram, 0, machine->ram_size); - ram_bases[0] = 0; - ram_sizes[0] = machine->ram_size; - memory_region_init(&ram_memories[1], NULL, "ef405ep.ram1", 0); - ram_bases[1] = 0x00000000; - ram_sizes[1] = 0x00000000; - - cpu = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes, - 33333333, &uicdev, kernel_filename == NULL ? 0 : 1); - - /* allocate SRAM */ - memory_region_init_ram(sram, NULL, "ef405ep.sram", PPC405EP_SRAM_SIZE, - &error_fatal); - memory_region_add_subregion(sysmem, PPC405EP_SRAM_BASE, sram); + object_initialize_child(OBJECT(machine), "soc", &ppc405->soc, + TYPE_PPC405_SOC); + object_property_set_uint(OBJECT(&ppc405->soc), "ram-size", + machine->ram_size, &error_fatal); + object_property_set_link(OBJECT(&ppc405->soc), "dram", + OBJECT(machine->ram), &error_abort); + object_property_set_bool(OBJECT(&ppc405->soc), "dram-init", + kernel_filename != NULL, &error_abort); + object_property_set_uint(OBJECT(&ppc405->soc), "sys-clk", 33333333, + &error_abort); + qdev_realize(DEVICE(&ppc405->soc), NULL, &error_fatal); /* allocate and load BIOS */ if (machine->firmware) { @@ -285,15 +321,6 @@ static void ref405ep_init(MachineState *machine) memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios); } - /* Register FPGA */ - ref405ep_fpga_init(sysmem, PPC405EP_FPGA_BASE); - /* Register NVRAM */ - dev = qdev_new("sysbus-m48t08"); - qdev_prop_set_int32(dev, "base-year", 1968); - s = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(s, &error_fatal); - sysbus_mmio_map(s, 0, PPC405EP_NVRAM_BASE); - /* Load kernel and initrd using U-Boot images */ if (kernel_filename && machine->firmware) { target_ulong kernel_base, initrd_base; @@ -322,63 +349,66 @@ static void ref405ep_init(MachineState *machine) /* Load ELF kernel and rootfs.cpio */ } else if (kernel_filename && !machine->firmware) { - boot_from_kernel(machine, cpu); + boot_from_kernel(machine, &ppc405->soc.cpu); } } -static void ref405ep_class_init(ObjectClass *oc, void *data) +static void ppc405_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->desc = "ref405ep"; - mc->init = ref405ep_init; - mc->default_ram_size = 0x08000000; - mc->default_ram_id = "ef405ep.ram"; + mc->desc = "PPC405 generic machine"; + mc->init = ppc405_init; + mc->default_ram_size = 128 * MiB; + mc->default_ram_id = "ppc405.ram"; } -static const TypeInfo ref405ep_type = { - .name = MACHINE_TYPE_NAME("ref405ep"), +static const TypeInfo ppc405_machine_type = { + .name = TYPE_PPC405_MACHINE, .parent = TYPE_MACHINE, - .class_init = ref405ep_class_init, + .instance_size = sizeof(Ppc405MachineState), + .class_init = ppc405_machine_class_init, + .abstract = true, }; /*****************************************************************************/ -/* AMCC Taihu evaluation board */ -/* - PowerPC 405EP processor - * - SDRAM 128 MB at 0x00000000 - * - Boot flash 2 MB at 0xFFE00000 - * - Application flash 32 MB at 0xFC000000 - * - 2 serial ports - * - 2 ethernet PHY - * - 1 USB 1.1 device 0x50000000 - * - 1 LCD display 0x50100000 - * - 1 CPLD 0x50100000 - * - 1 I2C EEPROM - * - 1 I2C thermal sensor - * - a set of LEDs - * - bit-bang SPI port using GPIOs - * - 1 EBC interface connector 0 0x50200000 - * - 1 cardbus controller + expansion slot. - * - 1 PCI expansion slot. +/* PPC405EP reference board (IBM) */ +/* + * Standalone board with: + * - PowerPC 405EP CPU + * - SDRAM (0x00000000) + * - Flash (0xFFF80000) + * - SRAM (0xFFF00000) + * - NVRAM (0xF0000000) + * - FPGA (0xF0300000) */ -typedef struct taihu_cpld_t taihu_cpld_t; -struct taihu_cpld_t { + +#define PPC405EP_NVRAM_BASE 0xF0000000 +#define PPC405EP_FPGA_BASE 0xF0300000 +#define PPC405EP_FLASH_BASE 0xFFF80000 + +#define TYPE_REF405EP_FPGA "ref405ep-fpga" +OBJECT_DECLARE_SIMPLE_TYPE(Ref405epFpgaState, REF405EP_FPGA); +struct Ref405epFpgaState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + uint8_t reg0; uint8_t reg1; }; -static uint64_t taihu_cpld_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ref405ep_fpga_readb(void *opaque, hwaddr addr, unsigned size) { - taihu_cpld_t *cpld; + Ref405epFpgaState *fpga = opaque; uint32_t ret; - cpld = opaque; switch (addr) { case 0x0: - ret = cpld->reg0; + ret = fpga->reg0; break; case 0x1: - ret = cpld->reg1; + ret = fpga->reg1; break; default: ret = 0; @@ -388,195 +418,113 @@ static uint64_t taihu_cpld_read(void *opaque, hwaddr addr, unsigned size) return ret; } -static void taihu_cpld_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) +static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value, + unsigned size) { - taihu_cpld_t *cpld; + Ref405epFpgaState *fpga = opaque; - cpld = opaque; switch (addr) { case 0x0: /* Read only */ break; case 0x1: - cpld->reg1 = value; + fpga->reg1 = value; break; default: break; } } -static const MemoryRegionOps taihu_cpld_ops = { - .read = taihu_cpld_read, - .write = taihu_cpld_write, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_NATIVE_ENDIAN, +static const MemoryRegionOps ref405ep_fpga_ops = { + .read = ref405ep_fpga_readb, + .write = ref405ep_fpga_writeb, + .impl.min_access_size = 1, + .impl.max_access_size = 1, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_BIG_ENDIAN, }; -static void taihu_cpld_reset (void *opaque) +static void ref405ep_fpga_reset(DeviceState *dev) { - taihu_cpld_t *cpld; + Ref405epFpgaState *fpga = REF405EP_FPGA(dev); - cpld = opaque; - cpld->reg0 = 0x01; - cpld->reg1 = 0x80; + fpga->reg0 = 0x00; + fpga->reg1 = 0x0F; } -static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base) +static void ref405ep_fpga_realize(DeviceState *dev, Error **errp) { - taihu_cpld_t *cpld; - MemoryRegion *cpld_memory = g_new(MemoryRegion, 1); + Ref405epFpgaState *s = REF405EP_FPGA(dev); - cpld = g_new0(taihu_cpld_t, 1); - memory_region_init_io(cpld_memory, NULL, &taihu_cpld_ops, cpld, "cpld", 0x100); - memory_region_add_subregion(sysmem, base, cpld_memory); - qemu_register_reset(&taihu_cpld_reset, cpld); + memory_region_init_io(&s->iomem, OBJECT(s), &ref405ep_fpga_ops, s, + "fpga", 0x00000100); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); } -static void taihu_405ep_init(MachineState *machine) +static void ref405ep_fpga_class_init(ObjectClass *oc, void *data) { - MachineClass *mc = MACHINE_GET_CLASS(machine); - const char *bios_name = machine->firmware ?: BIOS_FILENAME; - const char *kernel_filename = machine->kernel_filename; - const char *initrd_filename = machine->initrd_filename; - char *filename; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *bios; - MemoryRegion *ram_memories = g_new(MemoryRegion, 2); - hwaddr ram_bases[2], ram_sizes[2]; - long bios_size; - target_ulong kernel_base, initrd_base; - long kernel_size, initrd_size; - int linux_boot; - int fl_idx; - DriveInfo *dinfo; - DeviceState *uicdev; + DeviceClass *dc = DEVICE_CLASS(oc); - if (machine->ram_size != mc->default_ram_size) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - exit(EXIT_FAILURE); - } - - ram_bases[0] = 0; - ram_sizes[0] = 0x04000000; - memory_region_init_alias(&ram_memories[0], NULL, - "taihu_405ep.ram-0", machine->ram, ram_bases[0], - ram_sizes[0]); - ram_bases[1] = 0x04000000; - ram_sizes[1] = 0x04000000; - memory_region_init_alias(&ram_memories[1], NULL, - "taihu_405ep.ram-1", machine->ram, ram_bases[1], - ram_sizes[1]); - ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes, - 33333333, &uicdev, kernel_filename == NULL ? 0 : 1); - /* allocate and load BIOS */ - fl_idx = 0; -#if defined(USE_FLASH_BIOS) - dinfo = drive_get(IF_PFLASH, 0, fl_idx); - if (dinfo) { - bios_size = 2 * MiB; - pflash_cfi02_register(0xFFE00000, - "taihu_405ep.bios", bios_size, - blk_by_legacy_dinfo(dinfo), - 64 * KiB, 1, - 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, - 1); - fl_idx++; - } else -#endif - { - bios = g_new(MemoryRegion, 1); - memory_region_init_rom(bios, NULL, "taihu_405ep.bios", BIOS_SIZE, - &error_fatal); - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = load_image_size(filename, - memory_region_get_ram_ptr(bios), - BIOS_SIZE); - g_free(filename); - if (bios_size < 0) { - error_report("Could not load PowerPC BIOS '%s'", bios_name); - exit(1); - } - bios_size = (bios_size + 0xfff) & ~0xfff; - memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios); - } else if (!qtest_enabled()) { - error_report("Could not load PowerPC BIOS '%s'", bios_name); - exit(1); - } - } - /* Register Linux flash */ - dinfo = drive_get(IF_PFLASH, 0, fl_idx); - if (dinfo) { - bios_size = 32 * MiB; - pflash_cfi02_register(0xfc000000, "taihu_405ep.flash", bios_size, - blk_by_legacy_dinfo(dinfo), - 64 * KiB, 1, - 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, - 1); - fl_idx++; - } - /* Register CLPD & LCD display */ - taihu_cpld_init(sysmem, 0x50100000); - /* Load kernel */ - linux_boot = (kernel_filename != NULL); - if (linux_boot) { - kernel_base = KERNEL_LOAD_ADDR; - /* now we can load the kernel */ - kernel_size = load_image_targphys(kernel_filename, kernel_base, - machine->ram_size - kernel_base); - if (kernel_size < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - /* load initrd */ - if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - machine->ram_size - initrd_base); - if (initrd_size < 0) { - error_report("could not load initial ram disk '%s'", - initrd_filename); - exit(1); - } - } else { - initrd_base = 0; - initrd_size = 0; - } - } else { - kernel_base = 0; - kernel_size = 0; - initrd_base = 0; - initrd_size = 0; - } + dc->realize = ref405ep_fpga_realize; + dc->reset = ref405ep_fpga_reset; + /* Reason: only works as part of a ppc405 board */ + dc->user_creatable = false; } -static void taihu_class_init(ObjectClass *oc, void *data) +static const TypeInfo ref405ep_fpga_type = { + .name = TYPE_REF405EP_FPGA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Ref405epFpgaState), + .class_init = ref405ep_fpga_class_init, +}; + +static void ref405ep_init(MachineState *machine) +{ + DeviceState *dev; + SysBusDevice *s; + MemoryRegion *sram = g_new(MemoryRegion, 1); + + ppc405_init(machine); + + /* allocate SRAM */ + memory_region_init_ram(sram, NULL, "ref405ep.sram", PPC405EP_SRAM_SIZE, + &error_fatal); + memory_region_add_subregion(get_system_memory(), PPC405EP_SRAM_BASE, sram); + + /* Register FPGA */ + dev = qdev_new(TYPE_REF405EP_FPGA); + object_property_add_child(OBJECT(machine), "fpga", OBJECT(dev)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, PPC405EP_FPGA_BASE); + + /* Register NVRAM */ + dev = qdev_new("sysbus-m48t08"); + qdev_prop_set_int32(dev, "base-year", 1968); + s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); + sysbus_mmio_map(s, 0, PPC405EP_NVRAM_BASE); +} + +static void ref405ep_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); - mc->desc = "taihu"; - mc->init = taihu_405ep_init; - mc->default_ram_size = 0x08000000; - mc->default_ram_id = "taihu_405ep.ram"; - mc->deprecation_reason = "incomplete, use 'ref405ep' instead"; + mc->desc = "ref405ep"; + mc->init = ref405ep_init; } -static const TypeInfo taihu_type = { - .name = MACHINE_TYPE_NAME("taihu"), - .parent = TYPE_MACHINE, - .class_init = taihu_class_init, +static const TypeInfo ref405ep_type = { + .name = MACHINE_TYPE_NAME("ref405ep"), + .parent = TYPE_PPC405_MACHINE, + .class_init = ref405ep_class_init, }; static void ppc405_machine_init(void) { + type_register_static(&ppc405_machine_type); type_register_static(&ref405ep_type); - type_register_static(&taihu_type); + type_register_static(&ref405ep_fpga_type); } type_init(ppc405_machine_init) diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index d6420c88d3..2ca42fdef6 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -30,6 +30,7 @@ #include "hw/ppc/ppc.h" #include "hw/i2c/ppc4xx_i2c.h" #include "hw/irq.h" +#include "hw/qdev-properties.h" #include "ppc405.h" #include "hw/char/serial.h" #include "qemu/timer.h" @@ -41,190 +42,9 @@ #include "qapi/error.h" #include "trace.h" -static void ppc405_set_default_bootinfo(ppc4xx_bd_info_t *bd, - ram_addr_t ram_size) -{ - memset(bd, 0, sizeof(*bd)); - - bd->bi_memstart = PPC405EP_SDRAM_BASE; - bd->bi_memsize = ram_size; - bd->bi_sramstart = PPC405EP_SRAM_BASE; - bd->bi_sramsize = PPC405EP_SRAM_SIZE; - bd->bi_bootflags = 0; - bd->bi_intfreq = 133333333; - bd->bi_busfreq = 33333333; - bd->bi_baudrate = 115200; - bd->bi_s_version[0] = 'Q'; - bd->bi_s_version[1] = 'M'; - bd->bi_s_version[2] = 'U'; - bd->bi_s_version[3] = '\0'; - bd->bi_r_version[0] = 'Q'; - bd->bi_r_version[1] = 'E'; - bd->bi_r_version[2] = 'M'; - bd->bi_r_version[3] = 'U'; - bd->bi_r_version[4] = '\0'; - bd->bi_procfreq = 133333333; - bd->bi_plb_busfreq = 33333333; - bd->bi_pci_busfreq = 33333333; - bd->bi_opbfreq = 33333333; -} - -static ram_addr_t __ppc405_set_bootinfo(CPUPPCState *env, ppc4xx_bd_info_t *bd) -{ - CPUState *cs = env_cpu(env); - ram_addr_t bdloc; - int i, n; - - /* We put the bd structure at the top of memory */ - if (bd->bi_memsize >= 0x01000000UL) - bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t); - else - bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t); - stl_be_phys(cs->as, bdloc + 0x00, bd->bi_memstart); - stl_be_phys(cs->as, bdloc + 0x04, bd->bi_memsize); - stl_be_phys(cs->as, bdloc + 0x08, bd->bi_flashstart); - stl_be_phys(cs->as, bdloc + 0x0C, bd->bi_flashsize); - stl_be_phys(cs->as, bdloc + 0x10, bd->bi_flashoffset); - stl_be_phys(cs->as, bdloc + 0x14, bd->bi_sramstart); - stl_be_phys(cs->as, bdloc + 0x18, bd->bi_sramsize); - stl_be_phys(cs->as, bdloc + 0x1C, bd->bi_bootflags); - stl_be_phys(cs->as, bdloc + 0x20, bd->bi_ipaddr); - for (i = 0; i < 6; i++) { - stb_phys(cs->as, bdloc + 0x24 + i, bd->bi_enetaddr[i]); - } - stw_be_phys(cs->as, bdloc + 0x2A, bd->bi_ethspeed); - stl_be_phys(cs->as, bdloc + 0x2C, bd->bi_intfreq); - stl_be_phys(cs->as, bdloc + 0x30, bd->bi_busfreq); - stl_be_phys(cs->as, bdloc + 0x34, bd->bi_baudrate); - for (i = 0; i < 4; i++) { - stb_phys(cs->as, bdloc + 0x38 + i, bd->bi_s_version[i]); - } - for (i = 0; i < 32; i++) { - stb_phys(cs->as, bdloc + 0x3C + i, bd->bi_r_version[i]); - } - stl_be_phys(cs->as, bdloc + 0x5C, bd->bi_procfreq); - stl_be_phys(cs->as, bdloc + 0x60, bd->bi_plb_busfreq); - stl_be_phys(cs->as, bdloc + 0x64, bd->bi_pci_busfreq); - for (i = 0; i < 6; i++) { - stb_phys(cs->as, bdloc + 0x68 + i, bd->bi_pci_enetaddr[i]); - } - n = 0x70; /* includes 2 bytes hole */ - for (i = 0; i < 6; i++) { - stb_phys(cs->as, bdloc + n++, bd->bi_pci_enetaddr2[i]); - } - stl_be_phys(cs->as, bdloc + n, bd->bi_opbfreq); - n += 4; - for (i = 0; i < 2; i++) { - stl_be_phys(cs->as, bdloc + n, bd->bi_iic_fast[i]); - n += 4; - } - - return bdloc; -} - -ram_addr_t ppc405_set_bootinfo(CPUPPCState *env, ram_addr_t ram_size) -{ - ppc4xx_bd_info_t bd; - - memset(&bd, 0, sizeof(bd)); - - ppc405_set_default_bootinfo(&bd, ram_size); - - return __ppc405_set_bootinfo(env, &bd); -} - /*****************************************************************************/ /* Shared peripherals */ -/*****************************************************************************/ -/* Peripheral local bus arbitrer */ -enum { - PLB3A0_ACR = 0x077, - PLB4A0_ACR = 0x081, - PLB0_BESR = 0x084, - PLB0_BEAR = 0x086, - PLB0_ACR = 0x087, - PLB4A1_ACR = 0x089, -}; - -typedef struct ppc4xx_plb_t ppc4xx_plb_t; -struct ppc4xx_plb_t { - uint32_t acr; - uint32_t bear; - uint32_t besr; -}; - -static uint32_t dcr_read_plb (void *opaque, int dcrn) -{ - ppc4xx_plb_t *plb; - uint32_t ret; - - plb = opaque; - switch (dcrn) { - case PLB0_ACR: - ret = plb->acr; - break; - case PLB0_BEAR: - ret = plb->bear; - break; - case PLB0_BESR: - ret = plb->besr; - break; - default: - /* Avoid gcc warning */ - ret = 0; - break; - } - - return ret; -} - -static void dcr_write_plb (void *opaque, int dcrn, uint32_t val) -{ - ppc4xx_plb_t *plb; - - plb = opaque; - switch (dcrn) { - case PLB0_ACR: - /* We don't care about the actual parameters written as - * we don't manage any priorities on the bus - */ - plb->acr = val & 0xF8000000; - break; - case PLB0_BEAR: - /* Read only */ - break; - case PLB0_BESR: - /* Write-clear */ - plb->besr &= ~val; - break; - } -} - -static void ppc4xx_plb_reset (void *opaque) -{ - ppc4xx_plb_t *plb; - - plb = opaque; - plb->acr = 0x00000000; - plb->bear = 0x00000000; - plb->besr = 0x00000000; -} - -void ppc4xx_plb_init(CPUPPCState *env) -{ - ppc4xx_plb_t *plb; - - plb = g_new0(ppc4xx_plb_t, 1); - ppc_dcr_register(env, PLB3A0_ACR, plb, &dcr_read_plb, &dcr_write_plb); - ppc_dcr_register(env, PLB4A0_ACR, plb, &dcr_read_plb, &dcr_write_plb); - ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb); - ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb); - ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb); - ppc_dcr_register(env, PLB4A1_ACR, plb, &dcr_read_plb, &dcr_write_plb); - qemu_register_reset(ppc4xx_plb_reset, plb); -} - /*****************************************************************************/ /* PLB to OPB bridge */ enum { @@ -233,19 +53,11 @@ enum { POB0_BEAR = 0x0A4, }; -typedef struct ppc4xx_pob_t ppc4xx_pob_t; -struct ppc4xx_pob_t { - uint32_t bear; - uint32_t besr0; - uint32_t besr1; -}; - -static uint32_t dcr_read_pob (void *opaque, int dcrn) +static uint32_t dcr_read_pob(void *opaque, int dcrn) { - ppc4xx_pob_t *pob; + Ppc405PobState *pob = opaque; uint32_t ret; - pob = opaque; switch (dcrn) { case POB0_BEAR: ret = pob->bear; @@ -265,11 +77,10 @@ static uint32_t dcr_read_pob (void *opaque, int dcrn) return ret; } -static void dcr_write_pob (void *opaque, int dcrn, uint32_t val) +static void dcr_write_pob(void *opaque, int dcrn, uint32_t val) { - ppc4xx_pob_t *pob; + Ppc405PobState *pob = opaque; - pob = opaque; switch (dcrn) { case POB0_BEAR: /* Read only */ @@ -285,40 +96,41 @@ static void dcr_write_pob (void *opaque, int dcrn, uint32_t val) } } -static void ppc4xx_pob_reset (void *opaque) +static void ppc405_pob_reset(DeviceState *dev) { - ppc4xx_pob_t *pob; + Ppc405PobState *pob = PPC405_POB(dev); - pob = opaque; /* No error */ pob->bear = 0x00000000; pob->besr0 = 0x0000000; pob->besr1 = 0x0000000; } -static void ppc4xx_pob_init(CPUPPCState *env) +static void ppc405_pob_realize(DeviceState *dev, Error **errp) { - ppc4xx_pob_t *pob; + Ppc405PobState *pob = PPC405_POB(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); - pob = g_new0(ppc4xx_pob_t, 1); - ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob); - ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob); - ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob); - qemu_register_reset(ppc4xx_pob_reset, pob); + ppc4xx_dcr_register(dcr, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob); + ppc4xx_dcr_register(dcr, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob); + ppc4xx_dcr_register(dcr, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob); +} + +static void ppc405_pob_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_pob_realize; + dc->reset = ppc405_pob_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; } /*****************************************************************************/ /* OPB arbitrer */ -typedef struct ppc4xx_opba_t ppc4xx_opba_t; -struct ppc4xx_opba_t { - MemoryRegion io; - uint8_t cr; - uint8_t pr; -}; - static uint64_t opba_readb(void *opaque, hwaddr addr, unsigned size) { - ppc4xx_opba_t *opba = opaque; + Ppc405OpbaState *opba = opaque; uint32_t ret; switch (addr) { @@ -340,7 +152,7 @@ static uint64_t opba_readb(void *opaque, hwaddr addr, unsigned size) static void opba_writeb(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - ppc4xx_opba_t *opba = opaque; + Ppc405OpbaState *opba = opaque; trace_opba_writeb(addr, value); @@ -365,224 +177,36 @@ static const MemoryRegionOps opba_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static void ppc4xx_opba_reset (void *opaque) +static void ppc405_opba_reset(DeviceState *dev) { - ppc4xx_opba_t *opba; + Ppc405OpbaState *opba = PPC405_OPBA(dev); - opba = opaque; opba->cr = 0x00; /* No dynamic priorities - park disabled */ opba->pr = 0x11; } -static void ppc4xx_opba_init(hwaddr base) +static void ppc405_opba_realize(DeviceState *dev, Error **errp) { - ppc4xx_opba_t *opba; + Ppc405OpbaState *s = PPC405_OPBA(dev); - trace_opba_init(base); + memory_region_init_io(&s->io, OBJECT(s), &opba_ops, s, "opba", 2); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->io); +} - opba = g_new0(ppc4xx_opba_t, 1); - memory_region_init_io(&opba->io, NULL, &opba_ops, opba, "opba", 0x002); - memory_region_add_subregion(get_system_memory(), base, &opba->io); - qemu_register_reset(ppc4xx_opba_reset, opba); +static void ppc405_opba_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_opba_realize; + dc->reset = ppc405_opba_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; } /*****************************************************************************/ /* Code decompression controller */ /* XXX: TODO */ -/*****************************************************************************/ -/* Peripheral controller */ -typedef struct ppc4xx_ebc_t ppc4xx_ebc_t; -struct ppc4xx_ebc_t { - uint32_t addr; - uint32_t bcr[8]; - uint32_t bap[8]; - uint32_t bear; - uint32_t besr0; - uint32_t besr1; - uint32_t cfg; -}; - -enum { - EBC0_CFGADDR = 0x012, - EBC0_CFGDATA = 0x013, -}; - -static uint32_t dcr_read_ebc (void *opaque, int dcrn) -{ - ppc4xx_ebc_t *ebc; - uint32_t ret; - - ebc = opaque; - switch (dcrn) { - case EBC0_CFGADDR: - ret = ebc->addr; - break; - case EBC0_CFGDATA: - switch (ebc->addr) { - case 0x00: /* B0CR */ - ret = ebc->bcr[0]; - break; - case 0x01: /* B1CR */ - ret = ebc->bcr[1]; - break; - case 0x02: /* B2CR */ - ret = ebc->bcr[2]; - break; - case 0x03: /* B3CR */ - ret = ebc->bcr[3]; - break; - case 0x04: /* B4CR */ - ret = ebc->bcr[4]; - break; - case 0x05: /* B5CR */ - ret = ebc->bcr[5]; - break; - case 0x06: /* B6CR */ - ret = ebc->bcr[6]; - break; - case 0x07: /* B7CR */ - ret = ebc->bcr[7]; - break; - case 0x10: /* B0AP */ - ret = ebc->bap[0]; - break; - case 0x11: /* B1AP */ - ret = ebc->bap[1]; - break; - case 0x12: /* B2AP */ - ret = ebc->bap[2]; - break; - case 0x13: /* B3AP */ - ret = ebc->bap[3]; - break; - case 0x14: /* B4AP */ - ret = ebc->bap[4]; - break; - case 0x15: /* B5AP */ - ret = ebc->bap[5]; - break; - case 0x16: /* B6AP */ - ret = ebc->bap[6]; - break; - case 0x17: /* B7AP */ - ret = ebc->bap[7]; - break; - case 0x20: /* BEAR */ - ret = ebc->bear; - break; - case 0x21: /* BESR0 */ - ret = ebc->besr0; - break; - case 0x22: /* BESR1 */ - ret = ebc->besr1; - break; - case 0x23: /* CFG */ - ret = ebc->cfg; - break; - default: - ret = 0x00000000; - break; - } - break; - default: - ret = 0x00000000; - break; - } - - return ret; -} - -static void dcr_write_ebc (void *opaque, int dcrn, uint32_t val) -{ - ppc4xx_ebc_t *ebc; - - ebc = opaque; - switch (dcrn) { - case EBC0_CFGADDR: - ebc->addr = val; - break; - case EBC0_CFGDATA: - switch (ebc->addr) { - case 0x00: /* B0CR */ - break; - case 0x01: /* B1CR */ - break; - case 0x02: /* B2CR */ - break; - case 0x03: /* B3CR */ - break; - case 0x04: /* B4CR */ - break; - case 0x05: /* B5CR */ - break; - case 0x06: /* B6CR */ - break; - case 0x07: /* B7CR */ - break; - case 0x10: /* B0AP */ - break; - case 0x11: /* B1AP */ - break; - case 0x12: /* B2AP */ - break; - case 0x13: /* B3AP */ - break; - case 0x14: /* B4AP */ - break; - case 0x15: /* B5AP */ - break; - case 0x16: /* B6AP */ - break; - case 0x17: /* B7AP */ - break; - case 0x20: /* BEAR */ - break; - case 0x21: /* BESR0 */ - break; - case 0x22: /* BESR1 */ - break; - case 0x23: /* CFG */ - break; - default: - break; - } - break; - default: - break; - } -} - -static void ebc_reset (void *opaque) -{ - ppc4xx_ebc_t *ebc; - int i; - - ebc = opaque; - ebc->addr = 0x00000000; - ebc->bap[0] = 0x7F8FFE80; - ebc->bcr[0] = 0xFFE28000; - for (i = 0; i < 8; i++) { - ebc->bap[i] = 0x00000000; - ebc->bcr[i] = 0x00000000; - } - ebc->besr0 = 0x00000000; - ebc->besr1 = 0x00000000; - ebc->cfg = 0x80400000; -} - -void ppc405_ebc_init(CPUPPCState *env) -{ - ppc4xx_ebc_t *ebc; - - ebc = g_new0(ppc4xx_ebc_t, 1); - qemu_register_reset(&ebc_reset, ebc); - ppc_dcr_register(env, EBC0_CFGADDR, - ebc, &dcr_read_ebc, &dcr_write_ebc); - ppc_dcr_register(env, EBC0_CFGDATA, - ebc, &dcr_read_ebc, &dcr_write_ebc); -} - /*****************************************************************************/ /* DMA controller */ enum { @@ -612,35 +236,20 @@ enum { DMA0_POL = 0x126, }; -typedef struct ppc405_dma_t ppc405_dma_t; -struct ppc405_dma_t { - qemu_irq irqs[4]; - uint32_t cr[4]; - uint32_t ct[4]; - uint32_t da[4]; - uint32_t sa[4]; - uint32_t sg[4]; - uint32_t sr; - uint32_t sgc; - uint32_t slp; - uint32_t pol; -}; - -static uint32_t dcr_read_dma (void *opaque, int dcrn) +static uint32_t dcr_read_dma(void *opaque, int dcrn) { return 0; } -static void dcr_write_dma (void *opaque, int dcrn, uint32_t val) +static void dcr_write_dma(void *opaque, int dcrn, uint32_t val) { } -static void ppc405_dma_reset (void *opaque) +static void ppc405_dma_reset(DeviceState *dev) { - ppc405_dma_t *dma; + Ppc405DmaState *dma = PPC405_DMA(dev); int i; - dma = opaque; for (i = 0; i < 4; i++) { dma->cr[i] = 0x00000000; dma->ct[i] = 0x00000000; @@ -654,81 +263,54 @@ static void ppc405_dma_reset (void *opaque) dma->pol = 0x00000000; } -static void ppc405_dma_init(CPUPPCState *env, qemu_irq irqs[4]) +static void ppc405_dma_realize(DeviceState *dev, Error **errp) { - ppc405_dma_t *dma; + Ppc405DmaState *dma = PPC405_DMA(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + int i; - dma = g_new0(ppc405_dma_t, 1); - memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq)); - qemu_register_reset(&ppc405_dma_reset, dma); - ppc_dcr_register(env, DMA0_CR0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CT0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_DA0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SA0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SG0, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CR1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CT1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_DA1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SA1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SG1, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CR2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CT2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_DA2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SA2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SG2, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CR3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_CT3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_DA3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SA3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SG3, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SR, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SGC, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_SLP, - dma, &dcr_read_dma, &dcr_write_dma); - ppc_dcr_register(env, DMA0_POL, - dma, &dcr_read_dma, &dcr_write_dma); + for (i = 0; i < ARRAY_SIZE(dma->irqs); i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dma), &dma->irqs[i]); + } + + ppc4xx_dcr_register(dcr, DMA0_CR0, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_CT0, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_DA0, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SA0, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SG0, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_CR1, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_CT1, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_DA1, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SA1, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SG1, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_CR2, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_CT2, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_DA2, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SA2, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SG2, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_CR3, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_CT3, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_DA3, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SA3, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SG3, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SR, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SGC, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_SLP, dma, &dcr_read_dma, &dcr_write_dma); + ppc4xx_dcr_register(dcr, DMA0_POL, dma, &dcr_read_dma, &dcr_write_dma); +} + +static void ppc405_dma_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_dma_realize; + dc->reset = ppc405_dma_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; } /*****************************************************************************/ /* GPIO */ -typedef struct ppc405_gpio_t ppc405_gpio_t; -struct ppc405_gpio_t { - MemoryRegion io; - uint32_t or; - uint32_t tcr; - uint32_t osrh; - uint32_t osrl; - uint32_t tsrh; - uint32_t tsrl; - uint32_t odr; - uint32_t ir; - uint32_t rr1; - uint32_t isr1h; - uint32_t isr1l; -}; - static uint64_t ppc405_gpio_read(void *opaque, hwaddr addr, unsigned size) { trace_ppc405_gpio_read(addr, size); @@ -747,20 +329,22 @@ static const MemoryRegionOps ppc405_gpio_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void ppc405_gpio_reset (void *opaque) +static void ppc405_gpio_realize(DeviceState *dev, Error **errp) { + Ppc405GpioState *s = PPC405_GPIO(dev); + + memory_region_init_io(&s->io, OBJECT(s), &ppc405_gpio_ops, s, "gpio", + 0x38); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->io); } -static void ppc405_gpio_init(hwaddr base) +static void ppc405_gpio_class_init(ObjectClass *oc, void *data) { - ppc405_gpio_t *gpio; + DeviceClass *dc = DEVICE_CLASS(oc); - trace_ppc405_gpio_init(base); - - gpio = g_new0(ppc405_gpio_t, 1); - memory_region_init_io(&gpio->io, NULL, &ppc405_gpio_ops, gpio, "pgio", 0x038); - memory_region_add_subregion(get_system_memory(), base, &gpio->io); - qemu_register_reset(&ppc405_gpio_reset, gpio); + dc->realize = ppc405_gpio_realize; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; } /*****************************************************************************/ @@ -772,20 +356,9 @@ enum { OCM0_DSACNTL = 0x01B, }; -typedef struct ppc405_ocm_t ppc405_ocm_t; -struct ppc405_ocm_t { - MemoryRegion ram; - MemoryRegion isarc_ram; - MemoryRegion dsarc_ram; - uint32_t isarc; - uint32_t isacntl; - uint32_t dsarc; - uint32_t dsacntl; -}; - -static void ocm_update_mappings (ppc405_ocm_t *ocm, - uint32_t isarc, uint32_t isacntl, - uint32_t dsarc, uint32_t dsacntl) +static void ocm_update_mappings(Ppc405OcmState *ocm, + uint32_t isarc, uint32_t isacntl, + uint32_t dsarc, uint32_t dsacntl) { trace_ocm_update_mappings(isarc, isacntl, dsarc, dsacntl, ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl); @@ -827,12 +400,11 @@ static void ocm_update_mappings (ppc405_ocm_t *ocm, } } -static uint32_t dcr_read_ocm (void *opaque, int dcrn) +static uint32_t dcr_read_ocm(void *opaque, int dcrn) { - ppc405_ocm_t *ocm; + Ppc405OcmState *ocm = opaque; uint32_t ret; - ocm = opaque; switch (dcrn) { case OCM0_ISARC: ret = ocm->isarc; @@ -854,12 +426,11 @@ static uint32_t dcr_read_ocm (void *opaque, int dcrn) return ret; } -static void dcr_write_ocm (void *opaque, int dcrn, uint32_t val) +static void dcr_write_ocm(void *opaque, int dcrn, uint32_t val) { - ppc405_ocm_t *ocm; + Ppc405OcmState *ocm = opaque; uint32_t isarc, dsarc, isacntl, dsacntl; - ocm = opaque; isarc = ocm->isarc; dsarc = ocm->dsarc; isacntl = ocm->isacntl; @@ -885,12 +456,11 @@ static void dcr_write_ocm (void *opaque, int dcrn, uint32_t val) ocm->dsacntl = dsacntl; } -static void ocm_reset (void *opaque) +static void ppc405_ocm_reset(DeviceState *dev) { - ppc405_ocm_t *ocm; + Ppc405OcmState *ocm = PPC405_OCM(dev); uint32_t isarc, dsarc, isacntl, dsacntl; - ocm = opaque; isarc = 0x00000000; isacntl = 0x00000000; dsarc = 0x00000000; @@ -902,57 +472,47 @@ static void ocm_reset (void *opaque) ocm->dsacntl = dsacntl; } -static void ppc405_ocm_init(CPUPPCState *env) +static void ppc405_ocm_realize(DeviceState *dev, Error **errp) { - ppc405_ocm_t *ocm; + Ppc405OcmState *ocm = PPC405_OCM(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); - ocm = g_new0(ppc405_ocm_t, 1); /* XXX: Size is 4096 or 0x04000000 */ - memory_region_init_ram(&ocm->isarc_ram, NULL, "ppc405.ocm", 4 * KiB, + memory_region_init_ram(&ocm->isarc_ram, OBJECT(ocm), "ppc405.ocm", 4 * KiB, &error_fatal); - memory_region_init_alias(&ocm->dsarc_ram, NULL, "ppc405.dsarc", + memory_region_init_alias(&ocm->dsarc_ram, OBJECT(ocm), "ppc405.dsarc", &ocm->isarc_ram, 0, 4 * KiB); - qemu_register_reset(&ocm_reset, ocm); - ppc_dcr_register(env, OCM0_ISARC, - ocm, &dcr_read_ocm, &dcr_write_ocm); - ppc_dcr_register(env, OCM0_ISACNTL, - ocm, &dcr_read_ocm, &dcr_write_ocm); - ppc_dcr_register(env, OCM0_DSARC, - ocm, &dcr_read_ocm, &dcr_write_ocm); - ppc_dcr_register(env, OCM0_DSACNTL, - ocm, &dcr_read_ocm, &dcr_write_ocm); + + ppc4xx_dcr_register(dcr, OCM0_ISARC, ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc4xx_dcr_register(dcr, OCM0_ISACNTL, ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc4xx_dcr_register(dcr, OCM0_DSARC, ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc4xx_dcr_register(dcr, OCM0_DSACNTL, ocm, &dcr_read_ocm, &dcr_write_ocm); +} + +static void ppc405_ocm_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_ocm_realize; + dc->reset = ppc405_ocm_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; } /*****************************************************************************/ /* General purpose timers */ -typedef struct ppc4xx_gpt_t ppc4xx_gpt_t; -struct ppc4xx_gpt_t { - MemoryRegion iomem; - int64_t tb_offset; - uint32_t tb_freq; - QEMUTimer *timer; - qemu_irq irqs[5]; - uint32_t oe; - uint32_t ol; - uint32_t im; - uint32_t is; - uint32_t ie; - uint32_t comp[5]; - uint32_t mask[5]; -}; - -static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n) +static int ppc4xx_gpt_compare(Ppc405GptState *gpt, int n) { /* XXX: TODO */ return 0; } -static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level) +static void ppc4xx_gpt_set_output(Ppc405GptState *gpt, int n, int level) { /* XXX: TODO */ } -static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt) +static void ppc4xx_gpt_set_outputs(Ppc405GptState *gpt) { uint32_t mask; int i; @@ -973,29 +533,30 @@ static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt) } } -static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) +static void ppc4xx_gpt_set_irqs(Ppc405GptState *gpt) { uint32_t mask; int i; mask = 0x00008000; for (i = 0; i < 5; i++) { - if (gpt->is & gpt->im & mask) + if (gpt->is & gpt->im & mask) { qemu_irq_raise(gpt->irqs[i]); - else + } else { qemu_irq_lower(gpt->irqs[i]); + } mask = mask >> 1; } } -static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt) +static void ppc4xx_gpt_compute_timer(Ppc405GptState *gpt) { /* XXX: TODO */ } static uint64_t ppc4xx_gpt_read(void *opaque, hwaddr addr, unsigned size) { - ppc4xx_gpt_t *gpt = opaque; + Ppc405GptState *gpt = opaque; uint32_t ret; int idx; @@ -1049,7 +610,7 @@ static uint64_t ppc4xx_gpt_read(void *opaque, hwaddr addr, unsigned size) static void ppc4xx_gpt_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - ppc4xx_gpt_t *gpt = opaque; + Ppc405GptState *gpt = opaque; int idx; trace_ppc4xx_gpt_write(addr, size, value); @@ -1113,22 +674,20 @@ static const MemoryRegionOps gpt_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void ppc4xx_gpt_cb (void *opaque) +static void ppc4xx_gpt_cb(void *opaque) { - ppc4xx_gpt_t *gpt; + Ppc405GptState *gpt = opaque; - gpt = opaque; ppc4xx_gpt_set_irqs(gpt); ppc4xx_gpt_set_outputs(gpt); ppc4xx_gpt_compute_timer(gpt); } -static void ppc4xx_gpt_reset (void *opaque) +static void ppc405_gpt_reset(DeviceState *dev) { - ppc4xx_gpt_t *gpt; + Ppc405GptState *gpt = PPC405_GPT(dev); int i; - gpt = opaque; timer_del(gpt->timer); gpt->oe = 0x00000000; gpt->ol = 0x00000000; @@ -1141,21 +700,37 @@ static void ppc4xx_gpt_reset (void *opaque) } } -static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5]) +static void ppc405_gpt_realize(DeviceState *dev, Error **errp) { - ppc4xx_gpt_t *gpt; + Ppc405GptState *s = PPC405_GPT(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); int i; - trace_ppc4xx_gpt_init(base); + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &ppc4xx_gpt_cb, s); + memory_region_init_io(&s->iomem, OBJECT(s), &gpt_ops, s, "gpt", 0xd4); + sysbus_init_mmio(sbd, &s->iomem); - gpt = g_new0(ppc4xx_gpt_t, 1); - for (i = 0; i < 5; i++) { - gpt->irqs[i] = irqs[i]; + for (i = 0; i < ARRAY_SIZE(s->irqs); i++) { + sysbus_init_irq(sbd, &s->irqs[i]); } - gpt->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &ppc4xx_gpt_cb, gpt); - memory_region_init_io(&gpt->iomem, NULL, &gpt_ops, gpt, "gpt", 0x0d4); - memory_region_add_subregion(get_system_memory(), base, &gpt->iomem); - qemu_register_reset(ppc4xx_gpt_reset, gpt); +} + +static void ppc405_gpt_finalize(Object *obj) +{ + /* timer will be NULL if the GPT wasn't realized */ + if (PPC405_GPT(obj)->timer) { + timer_del(PPC405_GPT(obj)->timer); + } +} + +static void ppc405_gpt_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_gpt_realize; + dc->reset = ppc405_gpt_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; } /*****************************************************************************/ @@ -1177,36 +752,7 @@ enum { #endif }; -enum { - PPC405EP_CPU_CLK = 0, - PPC405EP_PLB_CLK = 1, - PPC405EP_OPB_CLK = 2, - PPC405EP_EBC_CLK = 3, - PPC405EP_MAL_CLK = 4, - PPC405EP_PCI_CLK = 5, - PPC405EP_UART0_CLK = 6, - PPC405EP_UART1_CLK = 7, - PPC405EP_CLK_NB = 8, -}; - -typedef struct ppc405ep_cpc_t ppc405ep_cpc_t; -struct ppc405ep_cpc_t { - uint32_t sysclk; - clk_setup_t clk_setup[PPC405EP_CLK_NB]; - uint32_t boot; - uint32_t epctl; - uint32_t pllmr[2]; - uint32_t ucr; - uint32_t srr; - uint32_t jtagid; - uint32_t pci; - /* Clock and power management */ - uint32_t er; - uint32_t fr; - uint32_t sr; -}; - -static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) +static void ppc405ep_compute_clocks(Ppc405CpcState *cpc) { uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk; uint32_t UART0_clk, UART1_clk; @@ -1299,12 +845,11 @@ static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk); } -static uint32_t dcr_read_epcpc (void *opaque, int dcrn) +static uint32_t dcr_read_epcpc(void *opaque, int dcrn) { - ppc405ep_cpc_t *cpc; + Ppc405CpcState *cpc = opaque; uint32_t ret; - cpc = opaque; switch (dcrn) { case PPC405EP_CPC0_BOOT: ret = cpc->boot; @@ -1339,11 +884,10 @@ static uint32_t dcr_read_epcpc (void *opaque, int dcrn) return ret; } -static void dcr_write_epcpc (void *opaque, int dcrn, uint32_t val) +static void dcr_write_epcpc(void *opaque, int dcrn, uint32_t val) { - ppc405ep_cpc_t *cpc; + Ppc405CpcState *cpc = opaque; - cpc = opaque; switch (dcrn) { case PPC405EP_CPC0_BOOT: /* Read-only register */ @@ -1376,9 +920,9 @@ static void dcr_write_epcpc (void *opaque, int dcrn, uint32_t val) } } -static void ppc405ep_cpc_reset (void *opaque) +static void ppc405_cpc_reset(DeviceState *dev) { - ppc405ep_cpc_t *cpc = opaque; + Ppc405CpcState *cpc = PPC405_CPC(dev); cpc->boot = 0x00000010; /* Boot from PCI - IIC EEPROM disabled */ cpc->epctl = 0x00000000; @@ -1390,143 +934,291 @@ static void ppc405ep_cpc_reset (void *opaque) cpc->er = 0x00000000; cpc->fr = 0x00000000; cpc->sr = 0x00000000; + cpc->jtagid = 0x20267049; ppc405ep_compute_clocks(cpc); } /* XXX: sysclk should be between 25 and 100 MHz */ -static void ppc405ep_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[8], - uint32_t sysclk) +static void ppc405_cpc_realize(DeviceState *dev, Error **errp) { - ppc405ep_cpc_t *cpc; + Ppc405CpcState *cpc = PPC405_CPC(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); - cpc = g_new0(ppc405ep_cpc_t, 1); - memcpy(cpc->clk_setup, clk_setup, - PPC405EP_CLK_NB * sizeof(clk_setup_t)); - cpc->jtagid = 0x20267049; - cpc->sysclk = sysclk; - qemu_register_reset(&ppc405ep_cpc_reset, cpc); - ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); -#if 0 - ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); - ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc, - &dcr_read_epcpc, &dcr_write_epcpc); -#endif + assert(dcr->cpu); + cpc->clk_setup[PPC405EP_CPU_CLK].cb = + ppc_40x_timers_init(&dcr->cpu->env, cpc->sysclk, PPC_INTERRUPT_PIT); + cpc->clk_setup[PPC405EP_CPU_CLK].opaque = &dcr->cpu->env; + + ppc4xx_dcr_register(dcr, PPC405EP_CPC0_BOOT, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc4xx_dcr_register(dcr, PPC405EP_CPC0_EPCTL, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc4xx_dcr_register(dcr, PPC405EP_CPC0_PLLMR0, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc4xx_dcr_register(dcr, PPC405EP_CPC0_PLLMR1, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc4xx_dcr_register(dcr, PPC405EP_CPC0_UCR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc4xx_dcr_register(dcr, PPC405EP_CPC0_SRR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc4xx_dcr_register(dcr, PPC405EP_CPC0_JTAGID, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc4xx_dcr_register(dcr, PPC405EP_CPC0_PCI, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); } -PowerPCCPU *ppc405ep_init(MemoryRegion *address_space_mem, - MemoryRegion ram_memories[2], - hwaddr ram_bases[2], - hwaddr ram_sizes[2], - uint32_t sysclk, DeviceState **uicdevp, - int do_init) +static Property ppc405_cpc_properties[] = { + DEFINE_PROP_UINT32("sys-clk", Ppc405CpcState, sysclk, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ppc405_cpc_class_init(ObjectClass *oc, void *data) { - clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup; - qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4]; - PowerPCCPU *cpu; + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_cpc_realize; + dc->reset = ppc405_cpc_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; + device_class_set_props(dc, ppc405_cpc_properties); +} + +/* PPC405_SOC */ + +static void ppc405_soc_instance_init(Object *obj) +{ + Ppc405SoCState *s = PPC405_SOC(obj); + + object_initialize_child(obj, "cpu", &s->cpu, + POWERPC_CPU_TYPE_NAME("405ep")); + + object_initialize_child(obj, "uic", &s->uic, TYPE_PPC_UIC); + + object_initialize_child(obj, "cpc", &s->cpc, TYPE_PPC405_CPC); + object_property_add_alias(obj, "sys-clk", OBJECT(&s->cpc), "sys-clk"); + + object_initialize_child(obj, "gpt", &s->gpt, TYPE_PPC405_GPT); + + object_initialize_child(obj, "ocm", &s->ocm, TYPE_PPC405_OCM); + + object_initialize_child(obj, "gpio", &s->gpio, TYPE_PPC405_GPIO); + + object_initialize_child(obj, "dma", &s->dma, TYPE_PPC405_DMA); + + object_initialize_child(obj, "i2c", &s->i2c, TYPE_PPC4xx_I2C); + + object_initialize_child(obj, "ebc", &s->ebc, TYPE_PPC4xx_EBC); + + object_initialize_child(obj, "opba", &s->opba, TYPE_PPC405_OPBA); + + object_initialize_child(obj, "pob", &s->pob, TYPE_PPC405_POB); + + object_initialize_child(obj, "plb", &s->plb, TYPE_PPC4xx_PLB); + + object_initialize_child(obj, "mal", &s->mal, TYPE_PPC4xx_MAL); +} + +static void ppc405_reset(void *opaque) +{ + cpu_reset(CPU(opaque)); +} + +static void ppc405_soc_realize(DeviceState *dev, Error **errp) +{ + Ppc405SoCState *s = PPC405_SOC(dev); CPUPPCState *env; - DeviceState *uicdev; - SysBusDevice *uicsbd; + SysBusDevice *sbd; + int i; - memset(clk_setup, 0, sizeof(clk_setup)); /* init CPUs */ - cpu = ppc4xx_init(POWERPC_CPU_TYPE_NAME("405ep"), - &clk_setup[PPC405EP_CPU_CLK], - &tlb_clk_setup, sysclk); - env = &cpu->env; - clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; - clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; - /* Internal devices init */ - /* Memory mapped devices registers */ + if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) { + return; + } + qemu_register_reset(ppc405_reset, &s->cpu); + + env = &s->cpu.env; + + ppc_dcr_init(env, NULL, NULL); + + /* CPU control */ + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->cpc), &s->cpu, errp)) { + return; + } + /* PLB arbitrer */ - ppc4xx_plb_init(env); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->plb), &s->cpu, errp)) { + return; + } + /* PLB to OPB bridge */ - ppc4xx_pob_init(env); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->pob), &s->cpu, errp)) { + return; + } + /* OBP arbitrer */ - ppc4xx_opba_init(0xef600600); + sbd = SYS_BUS_DEVICE(&s->opba); + if (!sysbus_realize(sbd, errp)) { + return; + } + sysbus_mmio_map(sbd, 0, 0xef600600); + /* Universal interrupt controller */ - uicdev = qdev_new(TYPE_PPC_UIC); - uicsbd = SYS_BUS_DEVICE(uicdev); - - object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu), - &error_fatal); - sysbus_realize_and_unref(uicsbd, &error_fatal); - - sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, - qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT)); - sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, - qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT)); - - *uicdevp = uicdev; + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->uic), &s->cpu, errp)) { + return; + } + sbd = SYS_BUS_DEVICE(&s->uic); + sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT, + qdev_get_gpio_in(DEVICE(&s->cpu), PPC40x_INPUT_INT)); + sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT, + qdev_get_gpio_in(DEVICE(&s->cpu), PPC40x_INPUT_CINT)); /* SDRAM controller */ /* XXX 405EP has no ECC interrupt */ - ppc4xx_sdram_init(env, qdev_get_gpio_in(uicdev, 17), 2, ram_memories, - ram_bases, ram_sizes, do_init); + s->ram_bases[0] = 0; + s->ram_sizes[0] = s->ram_size; + memory_region_init_alias(&s->ram_banks[0], OBJECT(s), + "ppc405.sdram0", s->dram_mr, + s->ram_bases[0], s->ram_sizes[0]); + + ppc4xx_sdram_init(env, qdev_get_gpio_in(DEVICE(&s->uic), 17), 1, + s->ram_banks, s->ram_bases, s->ram_sizes, + s->do_dram_init); + /* External bus controller */ - ppc405_ebc_init(env); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->ebc), &s->cpu, errp)) { + return; + } + /* DMA controller */ - dma_irqs[0] = qdev_get_gpio_in(uicdev, 5); - dma_irqs[1] = qdev_get_gpio_in(uicdev, 6); - dma_irqs[2] = qdev_get_gpio_in(uicdev, 7); - dma_irqs[3] = qdev_get_gpio_in(uicdev, 8); - ppc405_dma_init(env, dma_irqs); - /* IIC controller */ - sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500, - qdev_get_gpio_in(uicdev, 2)); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->dma), &s->cpu, errp)) { + return; + } + sbd = SYS_BUS_DEVICE(&s->dma); + for (i = 0; i < ARRAY_SIZE(s->dma.irqs); i++) { + sysbus_connect_irq(sbd, i, qdev_get_gpio_in(DEVICE(&s->uic), 5 + i)); + } + + /* I2C controller */ + sbd = SYS_BUS_DEVICE(&s->i2c); + if (!sysbus_realize(sbd, errp)) { + return; + } + sysbus_mmio_map(sbd, 0, 0xef600500); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(DEVICE(&s->uic), 2)); + /* GPIO */ - ppc405_gpio_init(0xef600700); + sbd = SYS_BUS_DEVICE(&s->gpio); + if (!sysbus_realize(sbd, errp)) { + return; + } + sysbus_mmio_map(sbd, 0, 0xef600700); + /* Serial ports */ if (serial_hd(0) != NULL) { - serial_mm_init(address_space_mem, 0xef600300, 0, - qdev_get_gpio_in(uicdev, 0), + serial_mm_init(get_system_memory(), 0xef600300, 0, + qdev_get_gpio_in(DEVICE(&s->uic), 0), PPC_SERIAL_MM_BAUDBASE, serial_hd(0), DEVICE_BIG_ENDIAN); } if (serial_hd(1) != NULL) { - serial_mm_init(address_space_mem, 0xef600400, 0, - qdev_get_gpio_in(uicdev, 1), + serial_mm_init(get_system_memory(), 0xef600400, 0, + qdev_get_gpio_in(DEVICE(&s->uic), 1), PPC_SERIAL_MM_BAUDBASE, serial_hd(1), DEVICE_BIG_ENDIAN); } + /* OCM */ - ppc405_ocm_init(env); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->ocm), &s->cpu, errp)) { + return; + } + /* GPT */ - gpt_irqs[0] = qdev_get_gpio_in(uicdev, 19); - gpt_irqs[1] = qdev_get_gpio_in(uicdev, 20); - gpt_irqs[2] = qdev_get_gpio_in(uicdev, 21); - gpt_irqs[3] = qdev_get_gpio_in(uicdev, 22); - gpt_irqs[4] = qdev_get_gpio_in(uicdev, 23); - ppc4xx_gpt_init(0xef600000, gpt_irqs); - /* PCI */ - /* Uses UIC IRQs 3, 16, 18 */ + sbd = SYS_BUS_DEVICE(&s->gpt); + if (!sysbus_realize(sbd, errp)) { + return; + } + sysbus_mmio_map(sbd, 0, 0xef600000); + for (i = 0; i < ARRAY_SIZE(s->gpt.irqs); i++) { + sysbus_connect_irq(sbd, i, qdev_get_gpio_in(DEVICE(&s->uic), 19 + i)); + } + /* MAL */ - mal_irqs[0] = qdev_get_gpio_in(uicdev, 11); - mal_irqs[1] = qdev_get_gpio_in(uicdev, 12); - mal_irqs[2] = qdev_get_gpio_in(uicdev, 13); - mal_irqs[3] = qdev_get_gpio_in(uicdev, 14); - ppc4xx_mal_init(env, 4, 2, mal_irqs); + object_property_set_int(OBJECT(&s->mal), "txc-num", 4, &error_abort); + object_property_set_int(OBJECT(&s->mal), "rxc-num", 2, &error_abort); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->mal), &s->cpu, errp)) { + return; + } + sbd = SYS_BUS_DEVICE(&s->mal); + for (i = 0; i < ARRAY_SIZE(s->mal.irqs); i++) { + sysbus_connect_irq(sbd, i, qdev_get_gpio_in(DEVICE(&s->uic), 11 + i)); + } + /* Ethernet */ /* Uses UIC IRQs 9, 15, 17 */ - /* CPU control */ - ppc405ep_cpc_init(env, clk_setup, sysclk); - - return cpu; } + +static Property ppc405_soc_properties[] = { + DEFINE_PROP_LINK("dram", Ppc405SoCState, dram_mr, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_BOOL("dram-init", Ppc405SoCState, do_dram_init, 0), + DEFINE_PROP_UINT64("ram-size", Ppc405SoCState, ram_size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ppc405_soc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_soc_realize; + /* Reason: only works as part of a ppc405 board/machine */ + dc->user_creatable = false; + device_class_set_props(dc, ppc405_soc_properties); +} + +static const TypeInfo ppc405_types[] = { + { + .name = TYPE_PPC405_POB, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc405PobState), + .class_init = ppc405_pob_class_init, + }, { + .name = TYPE_PPC405_OPBA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Ppc405OpbaState), + .class_init = ppc405_opba_class_init, + }, { + .name = TYPE_PPC405_DMA, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc405DmaState), + .class_init = ppc405_dma_class_init, + }, { + .name = TYPE_PPC405_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Ppc405GpioState), + .class_init = ppc405_gpio_class_init, + }, { + .name = TYPE_PPC405_OCM, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc405OcmState), + .class_init = ppc405_ocm_class_init, + }, { + .name = TYPE_PPC405_GPT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Ppc405GptState), + .instance_finalize = ppc405_gpt_finalize, + .class_init = ppc405_gpt_class_init, + }, { + .name = TYPE_PPC405_CPC, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc405CpcState), + .class_init = ppc405_cpc_class_init, + }, { + .name = TYPE_PPC405_SOC, + .parent = TYPE_DEVICE, + .instance_size = sizeof(Ppc405SoCState), + .instance_init = ppc405_soc_instance_init, + .class_init = ppc405_soc_class_init, + } +}; + +DEFINE_TYPES(ppc405_types) diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 873f930c77..ea945a1c99 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -84,27 +84,30 @@ static int bamboo_load_device_tree(hwaddr addr, ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, sizeof(mem_reg_property)); - if (ret < 0) + if (ret < 0) { fprintf(stderr, "couldn't set /memory/reg\n"); - + } ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_base); - if (ret < 0) + if (ret < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); - + } ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", (initrd_base + initrd_size)); - if (ret < 0) + if (ret < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); - + } ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); - if (ret < 0) + if (ret < 0) { fprintf(stderr, "couldn't set /chosen/bootargs\n"); + } - /* Copy data from the host device tree into the guest. Since the guest can + /* + * Copy data from the host device tree into the guest. Since the guest can * directly access the timebase without host involvement, we must expose - * the correct frequencies. */ + * the correct frequencies. + */ if (kvm_enabled()) { tb_freq = kvmppc_get_tbfreq(); clock_freq = kvmppc_get_clockfreq(); @@ -193,12 +196,9 @@ static void bamboo_init(MachineState *machine) /* interrupt controller */ uicdev = qdev_new(TYPE_PPC_UIC); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uicdev), cpu, &error_fatal); + object_unref(OBJECT(uicdev)); uicsbd = SYS_BUS_DEVICE(uicdev); - - object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu), - &error_fatal); - sysbus_realize_and_unref(uicsbd, &error_fatal); - sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT)); sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, @@ -249,8 +249,10 @@ static void bamboo_init(MachineState *machine) if (pcibus) { /* Register network interfaces. */ for (i = 0; i < nb_nics; i++) { - /* There are no PCI NICs on the Bamboo board, but there are - * PCI slots, so we can pick whatever default model we want. */ + /* + * There are no PCI NICs on the Bamboo board, but there are + * PCI slots, so we can pick whatever default model we want. + */ pci_nic_init_nofail(&nd_table[i], pcibus, "e1000", NULL); } } diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index a1ecf6dd1c..53e981ddf4 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -904,14 +904,17 @@ static void dcr_write_dma(void *opaque, int dcrn, uint32_t val) int width, i, sidx, didx; uint8_t *rptr, *wptr; hwaddr rlen, wlen; + hwaddr xferlen; sidx = didx = 0; width = 1 << ((val & DMA0_CR_PW) >> 25); + xferlen = count * width; + wlen = rlen = xferlen; rptr = cpu_physical_memory_map(dma->ch[chnl].sa, &rlen, false); wptr = cpu_physical_memory_map(dma->ch[chnl].da, &wlen, true); - if (rptr && wptr) { + if (rptr && rlen == xferlen && wptr && wlen == xferlen) { if (!(val & DMA0_CR_DEC) && val & DMA0_CR_SAI && val & DMA0_CR_DAI) { /* optimise common case */ @@ -1025,7 +1028,8 @@ void ppc4xx_dma_init(CPUPPCState *env, int dcr_base) /*****************************************************************************/ /* PCI Express controller */ -/* FIXME: This is not complete and does not work, only implemented partially +/* + * FIXME: This is not complete and does not work, only implemented partially * to allow firmware and guests to find an empty bus. Cards should use PCI. */ #include "hw/pci/pcie_host.h" diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 737c0896b4..ce38ae65e6 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -29,7 +29,6 @@ #include "hw/irq.h" #include "hw/ppc/ppc.h" #include "hw/ppc/ppc4xx.h" -#include "hw/intc/ppc-uic.h" #include "hw/qdev-properties.h" #include "qemu/log.h" #include "exec/address-spaces.h" @@ -37,38 +36,6 @@ #include "qapi/error.h" #include "trace.h" -static void ppc4xx_reset(void *opaque) -{ - PowerPCCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -/*****************************************************************************/ -/* Generic PowerPC 4xx processor instantiation */ -PowerPCCPU *ppc4xx_init(const char *cpu_type, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - - /* init CPUs */ - cpu = POWERPC_CPU(cpu_create(cpu_type)); - env = &cpu->env; - - cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ - cpu_clk->opaque = env; - /* Set time-base frequency to sysclk */ - tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT); - tb_clk->opaque = env; - ppc_dcr_init(env, NULL, NULL); - /* Register qemu callbacks */ - qemu_register_reset(ppc4xx_reset, cpu); - - return cpu; -} - /*****************************************************************************/ /* SDRAM controller */ typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; @@ -98,12 +65,12 @@ enum { SDRAM0_CFGDATA = 0x011, }; -/* XXX: TOFIX: some patches have made this code become inconsistent: +/* + * XXX: TOFIX: some patches have made this code become inconsistent: * there are type inconsistencies, mixing hwaddr, target_ulong * and uint32_t */ -static uint32_t sdram_bcr (hwaddr ram_base, - hwaddr ram_size) +static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) { uint32_t bcr; @@ -146,16 +113,17 @@ static inline hwaddr sdram_base(uint32_t bcr) return bcr & 0xFF800000; } -static target_ulong sdram_size (uint32_t bcr) +static target_ulong sdram_size(uint32_t bcr) { target_ulong size; int sh; sh = (bcr >> 17) & 0x7; - if (sh == 7) + if (sh == 7) { size = -1; - else + } else { size = (4 * MiB) << sh; + } return size; } @@ -175,7 +143,7 @@ static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i, } sdram->bcr[i] = bcr & 0xFFDEE001; if (enabled && (bcr & 0x00000001)) { - trace_ppc4xx_sdram_unmap(sdram_base(bcr), sdram_size(bcr)); + trace_ppc4xx_sdram_map(sdram_base(bcr), sdram_size(bcr)); memory_region_init(&sdram->containers[i], NULL, "sdram-containers", sdram_size(bcr)); memory_region_add_subregion(&sdram->containers[i], 0, @@ -186,7 +154,7 @@ static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i, } } -static void sdram_map_bcr (ppc4xx_sdram_t *sdram) +static void sdram_map_bcr(ppc4xx_sdram_t *sdram) { int i; @@ -200,7 +168,7 @@ static void sdram_map_bcr (ppc4xx_sdram_t *sdram) } } -static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) +static void sdram_unmap_bcr(ppc4xx_sdram_t *sdram) { int i; @@ -212,7 +180,7 @@ static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) } } -static uint32_t dcr_read_sdram (void *opaque, int dcrn) +static uint32_t dcr_read_sdram(void *opaque, int dcrn) { ppc4xx_sdram_t *sdram; uint32_t ret; @@ -280,7 +248,7 @@ static uint32_t dcr_read_sdram (void *opaque, int dcrn) return ret; } -static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) +static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) { ppc4xx_sdram_t *sdram; @@ -313,10 +281,11 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) sdram_unmap_bcr(sdram); sdram->status |= 0x80000000; } - if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) + if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) { sdram->status |= 0x40000000; - else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) + } else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) { sdram->status &= ~0x40000000; + } sdram->cfg = val; break; case 0x24: /* SDRAM_STATUS */ @@ -348,10 +317,11 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) break; case 0x98: /* SDRAM_ECCESR */ val &= 0xFFF0F000; - if (sdram->eccesr == 0 && val != 0) + if (sdram->eccesr == 0 && val != 0) { qemu_irq_raise(sdram->irq); - else if (sdram->eccesr != 0 && val == 0) + } else if (sdram->eccesr != 0 && val == 0) { qemu_irq_lower(sdram->irq); + } sdram->eccesr = val; break; default: /* Error */ @@ -361,7 +331,7 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val) } } -static void sdram_reset (void *opaque) +static void sdram_reset(void *opaque) { ppc4xx_sdram_t *sdram; @@ -381,11 +351,11 @@ static void sdram_reset (void *opaque) sdram->cfg = 0x00800000; } -void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, - MemoryRegion *ram_memories, - hwaddr *ram_bases, - hwaddr *ram_sizes, - int do_init) +void ppc4xx_sdram_init(CPUPPCState *env, qemu_irq irq, int nbanks, + MemoryRegion *ram_memories, + hwaddr *ram_bases, + hwaddr *ram_sizes, + int do_init) { ppc4xx_sdram_t *sdram; @@ -404,8 +374,9 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, sdram, &dcr_read_sdram, &dcr_write_sdram); ppc_dcr_register(env, SDRAM0_CFGDATA, sdram, &dcr_read_sdram, &dcr_write_sdram); - if (do_init) + if (do_init) { sdram_map_bcr(sdram); + } } /* @@ -462,7 +433,7 @@ void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, } error_report("at most %d bank%s of %s MiB each supported", nr_banks, nr_banks == 1 ? "" : "s", s->str); - error_printf("Possible valid RAM size: %" PRIi64 " MiB \n", + error_printf("Possible valid RAM size: %" PRIi64 " MiB\n", used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB); g_string_free(s, true); @@ -491,32 +462,10 @@ enum { MAL0_RCBS1 = 0x1E1, }; -typedef struct ppc4xx_mal_t ppc4xx_mal_t; -struct ppc4xx_mal_t { - qemu_irq irqs[4]; - uint32_t cfg; - uint32_t esr; - uint32_t ier; - uint32_t txcasr; - uint32_t txcarr; - uint32_t txeobisr; - uint32_t txdeir; - uint32_t rxcasr; - uint32_t rxcarr; - uint32_t rxeobisr; - uint32_t rxdeir; - uint32_t *txctpr; - uint32_t *rxctpr; - uint32_t *rcbs; - uint8_t txcnum; - uint8_t rxcnum; -}; - -static void ppc4xx_mal_reset(void *opaque) +static void ppc4xx_mal_reset(DeviceState *dev) { - ppc4xx_mal_t *mal; + Ppc4xxMalState *mal = PPC4xx_MAL(dev); - mal = opaque; mal->cfg = 0x0007C000; mal->esr = 0x00000000; mal->ier = 0x00000000; @@ -530,10 +479,9 @@ static void ppc4xx_mal_reset(void *opaque) static uint32_t dcr_read_mal(void *opaque, int dcrn) { - ppc4xx_mal_t *mal; + Ppc4xxMalState *mal = opaque; uint32_t ret; - mal = opaque; switch (dcrn) { case MAL0_CFG: ret = mal->cfg; @@ -587,13 +535,12 @@ static uint32_t dcr_read_mal(void *opaque, int dcrn) static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) { - ppc4xx_mal_t *mal; + Ppc4xxMalState *mal = opaque; - mal = opaque; switch (dcrn) { case MAL0_CFG: if (val & 0x80000000) { - ppc4xx_mal_reset(mal); + ppc4xx_mal_reset(DEVICE(mal)); } mal->cfg = val & 0x00FFC087; break; @@ -644,55 +591,404 @@ static void dcr_write_mal(void *opaque, int dcrn, uint32_t val) } } -void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, - qemu_irq irqs[4]) +static void ppc4xx_mal_realize(DeviceState *dev, Error **errp) { - ppc4xx_mal_t *mal; + Ppc4xxMalState *mal = PPC4xx_MAL(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); int i; - assert(txcnum <= 32 && rxcnum <= 32); - mal = g_malloc0(sizeof(*mal)); - mal->txcnum = txcnum; - mal->rxcnum = rxcnum; - mal->txctpr = g_new0(uint32_t, txcnum); - mal->rxctpr = g_new0(uint32_t, rxcnum); - mal->rcbs = g_new0(uint32_t, rxcnum); - for (i = 0; i < 4; i++) { - mal->irqs[i] = irqs[i]; + if (mal->txcnum > 32 || mal->rxcnum > 32) { + error_setg(errp, "invalid TXC/RXC number"); + return; } - qemu_register_reset(&ppc4xx_mal_reset, mal); - ppc_dcr_register(env, MAL0_CFG, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_ESR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_IER, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCASR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXCARR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXEOBISR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_TXDEIR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCASR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXCARR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXEOBISR, - mal, &dcr_read_mal, &dcr_write_mal); - ppc_dcr_register(env, MAL0_RXDEIR, - mal, &dcr_read_mal, &dcr_write_mal); - for (i = 0; i < txcnum; i++) { - ppc_dcr_register(env, MAL0_TXCTP0R + i, - mal, &dcr_read_mal, &dcr_write_mal); + + mal->txctpr = g_new0(uint32_t, mal->txcnum); + mal->rxctpr = g_new0(uint32_t, mal->rxcnum); + mal->rcbs = g_new0(uint32_t, mal->rxcnum); + + for (i = 0; i < ARRAY_SIZE(mal->irqs); i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &mal->irqs[i]); } - for (i = 0; i < rxcnum; i++) { - ppc_dcr_register(env, MAL0_RXCTP0R + i, - mal, &dcr_read_mal, &dcr_write_mal); + + ppc4xx_dcr_register(dcr, MAL0_CFG, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_ESR, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_IER, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_TXCASR, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_TXCARR, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_TXEOBISR, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_TXDEIR, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_RXCASR, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_RXCARR, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_RXEOBISR, mal, &dcr_read_mal, &dcr_write_mal); + ppc4xx_dcr_register(dcr, MAL0_RXDEIR, mal, &dcr_read_mal, &dcr_write_mal); + for (i = 0; i < mal->txcnum; i++) { + ppc4xx_dcr_register(dcr, MAL0_TXCTP0R + i, + mal, &dcr_read_mal, &dcr_write_mal); } - for (i = 0; i < rxcnum; i++) { - ppc_dcr_register(env, MAL0_RCBS0 + i, - mal, &dcr_read_mal, &dcr_write_mal); + for (i = 0; i < mal->rxcnum; i++) { + ppc4xx_dcr_register(dcr, MAL0_RXCTP0R + i, + mal, &dcr_read_mal, &dcr_write_mal); + } + for (i = 0; i < mal->rxcnum; i++) { + ppc4xx_dcr_register(dcr, MAL0_RCBS0 + i, + mal, &dcr_read_mal, &dcr_write_mal); } } + +static void ppc4xx_mal_finalize(Object *obj) +{ + Ppc4xxMalState *mal = PPC4xx_MAL(obj); + + g_free(mal->rcbs); + g_free(mal->rxctpr); + g_free(mal->txctpr); +} + +static Property ppc4xx_mal_properties[] = { + DEFINE_PROP_UINT8("txc-num", Ppc4xxMalState, txcnum, 0), + DEFINE_PROP_UINT8("rxc-num", Ppc4xxMalState, rxcnum, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ppc4xx_mal_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc4xx_mal_realize; + dc->reset = ppc4xx_mal_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; + device_class_set_props(dc, ppc4xx_mal_properties); +} + +/*****************************************************************************/ +/* Peripheral local bus arbitrer */ +enum { + PLB3A0_ACR = 0x077, + PLB4A0_ACR = 0x081, + PLB0_BESR = 0x084, + PLB0_BEAR = 0x086, + PLB0_ACR = 0x087, + PLB4A1_ACR = 0x089, +}; + +static uint32_t dcr_read_plb(void *opaque, int dcrn) +{ + Ppc4xxPlbState *plb = opaque; + uint32_t ret; + + switch (dcrn) { + case PLB0_ACR: + ret = plb->acr; + break; + case PLB0_BEAR: + ret = plb->bear; + break; + case PLB0_BESR: + ret = plb->besr; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_plb(void *opaque, int dcrn, uint32_t val) +{ + Ppc4xxPlbState *plb = opaque; + + switch (dcrn) { + case PLB0_ACR: + /* + * We don't care about the actual parameters written as + * we don't manage any priorities on the bus + */ + plb->acr = val & 0xF8000000; + break; + case PLB0_BEAR: + /* Read only */ + break; + case PLB0_BESR: + /* Write-clear */ + plb->besr &= ~val; + break; + } +} + +static void ppc405_plb_reset(DeviceState *dev) +{ + Ppc4xxPlbState *plb = PPC4xx_PLB(dev); + + plb->acr = 0x00000000; + plb->bear = 0x00000000; + plb->besr = 0x00000000; +} + +static void ppc405_plb_realize(DeviceState *dev, Error **errp) +{ + Ppc4xxPlbState *plb = PPC4xx_PLB(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + + ppc4xx_dcr_register(dcr, PLB3A0_ACR, plb, &dcr_read_plb, &dcr_write_plb); + ppc4xx_dcr_register(dcr, PLB4A0_ACR, plb, &dcr_read_plb, &dcr_write_plb); + ppc4xx_dcr_register(dcr, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb); + ppc4xx_dcr_register(dcr, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb); + ppc4xx_dcr_register(dcr, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb); + ppc4xx_dcr_register(dcr, PLB4A1_ACR, plb, &dcr_read_plb, &dcr_write_plb); +} + +static void ppc405_plb_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_plb_realize; + dc->reset = ppc405_plb_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; +} + +/*****************************************************************************/ +/* Peripheral controller */ +enum { + EBC0_CFGADDR = 0x012, + EBC0_CFGDATA = 0x013, +}; + +static uint32_t dcr_read_ebc(void *opaque, int dcrn) +{ + Ppc4xxEbcState *ebc = opaque; + uint32_t ret; + + switch (dcrn) { + case EBC0_CFGADDR: + ret = ebc->addr; + break; + case EBC0_CFGDATA: + switch (ebc->addr) { + case 0x00: /* B0CR */ + ret = ebc->bcr[0]; + break; + case 0x01: /* B1CR */ + ret = ebc->bcr[1]; + break; + case 0x02: /* B2CR */ + ret = ebc->bcr[2]; + break; + case 0x03: /* B3CR */ + ret = ebc->bcr[3]; + break; + case 0x04: /* B4CR */ + ret = ebc->bcr[4]; + break; + case 0x05: /* B5CR */ + ret = ebc->bcr[5]; + break; + case 0x06: /* B6CR */ + ret = ebc->bcr[6]; + break; + case 0x07: /* B7CR */ + ret = ebc->bcr[7]; + break; + case 0x10: /* B0AP */ + ret = ebc->bap[0]; + break; + case 0x11: /* B1AP */ + ret = ebc->bap[1]; + break; + case 0x12: /* B2AP */ + ret = ebc->bap[2]; + break; + case 0x13: /* B3AP */ + ret = ebc->bap[3]; + break; + case 0x14: /* B4AP */ + ret = ebc->bap[4]; + break; + case 0x15: /* B5AP */ + ret = ebc->bap[5]; + break; + case 0x16: /* B6AP */ + ret = ebc->bap[6]; + break; + case 0x17: /* B7AP */ + ret = ebc->bap[7]; + break; + case 0x20: /* BEAR */ + ret = ebc->bear; + break; + case 0x21: /* BESR0 */ + ret = ebc->besr0; + break; + case 0x22: /* BESR1 */ + ret = ebc->besr1; + break; + case 0x23: /* CFG */ + ret = ebc->cfg; + break; + default: + ret = 0x00000000; + break; + } + break; + default: + ret = 0x00000000; + break; + } + + return ret; +} + +static void dcr_write_ebc(void *opaque, int dcrn, uint32_t val) +{ + Ppc4xxEbcState *ebc = opaque; + + switch (dcrn) { + case EBC0_CFGADDR: + ebc->addr = val; + break; + case EBC0_CFGDATA: + switch (ebc->addr) { + case 0x00: /* B0CR */ + break; + case 0x01: /* B1CR */ + break; + case 0x02: /* B2CR */ + break; + case 0x03: /* B3CR */ + break; + case 0x04: /* B4CR */ + break; + case 0x05: /* B5CR */ + break; + case 0x06: /* B6CR */ + break; + case 0x07: /* B7CR */ + break; + case 0x10: /* B0AP */ + break; + case 0x11: /* B1AP */ + break; + case 0x12: /* B2AP */ + break; + case 0x13: /* B3AP */ + break; + case 0x14: /* B4AP */ + break; + case 0x15: /* B5AP */ + break; + case 0x16: /* B6AP */ + break; + case 0x17: /* B7AP */ + break; + case 0x20: /* BEAR */ + break; + case 0x21: /* BESR0 */ + break; + case 0x22: /* BESR1 */ + break; + case 0x23: /* CFG */ + break; + default: + break; + } + break; + default: + break; + } +} + +static void ppc405_ebc_reset(DeviceState *dev) +{ + Ppc4xxEbcState *ebc = PPC4xx_EBC(dev); + int i; + + ebc->addr = 0x00000000; + ebc->bap[0] = 0x7F8FFE80; + ebc->bcr[0] = 0xFFE28000; + for (i = 0; i < 8; i++) { + ebc->bap[i] = 0x00000000; + ebc->bcr[i] = 0x00000000; + } + ebc->besr0 = 0x00000000; + ebc->besr1 = 0x00000000; + ebc->cfg = 0x80400000; +} + +static void ppc405_ebc_realize(DeviceState *dev, Error **errp) +{ + Ppc4xxEbcState *ebc = PPC4xx_EBC(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + + ppc4xx_dcr_register(dcr, EBC0_CFGADDR, ebc, &dcr_read_ebc, &dcr_write_ebc); + ppc4xx_dcr_register(dcr, EBC0_CFGDATA, ebc, &dcr_read_ebc, &dcr_write_ebc); +} + +static void ppc405_ebc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc405_ebc_realize; + dc->reset = ppc405_ebc_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; +} + +/* PPC4xx_DCR_DEVICE */ + +void ppc4xx_dcr_register(Ppc4xxDcrDeviceState *dev, int dcrn, void *opaque, + dcr_read_cb dcr_read, dcr_write_cb dcr_write) +{ + assert(dev->cpu); + ppc_dcr_register(&dev->cpu->env, dcrn, opaque, dcr_read, dcr_write); +} + +bool ppc4xx_dcr_realize(Ppc4xxDcrDeviceState *dev, PowerPCCPU *cpu, + Error **errp) +{ + object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_abort); + return sysbus_realize(SYS_BUS_DEVICE(dev), errp); +} + +static Property ppc4xx_dcr_properties[] = { + DEFINE_PROP_LINK("cpu", Ppc4xxDcrDeviceState, cpu, TYPE_POWERPC_CPU, + PowerPCCPU *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ppc4xx_dcr_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + device_class_set_props(dc, ppc4xx_dcr_properties); +} + +static const TypeInfo ppc4xx_types[] = { + { + .name = TYPE_PPC4xx_MAL, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc4xxMalState), + .instance_finalize = ppc4xx_mal_finalize, + .class_init = ppc4xx_mal_class_init, + }, { + .name = TYPE_PPC4xx_PLB, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc4xxPlbState), + .class_init = ppc405_plb_class_init, + }, { + .name = TYPE_PPC4xx_EBC, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc4xxEbcState), + .class_init = ppc405_ebc_class_init, + }, { + .name = TYPE_PPC4xx_DCR_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Ppc4xxDcrDeviceState), + .class_init = ppc4xx_dcr_class_init, + .abstract = true, + } +}; + +DEFINE_TYPES(ppc4xx_types) diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c index 5df97e6d15..8642b96455 100644 --- a/hw/ppc/ppc4xx_pci.c +++ b/hw/ppc/ppc4xx_pci.c @@ -16,8 +16,10 @@ * Authors: Hollis Blanchard */ -/* This file implements emulation of the 32-bit PCI controller found in some - * 4xx SoCs, such as the 440EP. */ +/* + * This file implements emulation of the 32-bit PCI controller found in some + * 4xx SoCs, such as the 440EP. + */ #include "qemu/osdep.h" #include "qemu/log.h" @@ -65,8 +67,10 @@ struct PPC4xxPCIState { #define PCIC0_CFGADDR 0x0 #define PCIC0_CFGDATA 0x4 -/* PLB Memory Map (PMM) registers specify which PLB addresses are translated to - * PCI accesses. */ +/* + * PLB Memory Map (PMM) registers specify which PLB addresses are translated to + * PCI accesses. + */ #define PCIL0_PMM0LA 0x0 #define PCIL0_PMM0MA 0x4 #define PCIL0_PMM0PCILA 0x8 @@ -80,8 +84,10 @@ struct PPC4xxPCIState { #define PCIL0_PMM2PCILA 0x28 #define PCIL0_PMM2PCIHA 0x2c -/* PCI Target Map (PTM) registers specify which PCI addresses are translated to - * PLB accesses. */ +/* + * PCI Target Map (PTM) registers specify which PCI addresses are translated to + * PLB accesses. + */ #define PCIL0_PTM1MS 0x30 #define PCIL0_PTM1LA 0x34 #define PCIL0_PTM2MS 0x38 @@ -96,9 +102,10 @@ static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset, { struct PPC4xxPCIState *pci = opaque; - /* We ignore all target attempts at PCI configuration, effectively - * assuming a bidirectional 1:1 mapping of PLB and PCI space. */ - + /* + * We ignore all target attempts at PCI configuration, effectively + * assuming a bidirectional 1:1 mapping of PLB and PCI space. + */ switch (offset) { case PCIL0_PMM0LA: pci->pmm[0].la = value; @@ -243,8 +250,10 @@ static void ppc4xx_pci_reset(void *opaque) memset(pci->ptm, 0, sizeof(pci->ptm)); } -/* On Bamboo, all pins from each slot are tied to a single board IRQ. This - * may need further refactoring for other boards. */ +/* + * On Bamboo, all pins from each slot are tied to a single board IRQ. + * This may need further refactoring for other boards. + */ static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num) { int slot = PCI_SLOT(pci_dev->devfn); diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 7e8da657c2..850bb3b817 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -25,7 +25,6 @@ #include "elf.h" #include "exec/memory.h" #include "ppc440.h" -#include "ppc405.h" #include "hw/block/flash.h" #include "sysemu/sysemu.h" #include "sysemu/reset.h" @@ -280,7 +279,6 @@ static void sam460ex_init(MachineState *machine) hwaddr ram_sizes[SDRAM_NR_BANKS] = {0}; MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1); DeviceState *uic[4]; - qemu_irq mal_irqs[4]; int i; PCIBus *pci_bus; PowerPCCPU *cpu; @@ -309,11 +307,12 @@ static void sam460ex_init(MachineState *machine) ppc_dcr_init(env, NULL, NULL); /* PLB arbitrer */ - ppc4xx_plb_init(env); + dev = qdev_new(TYPE_PPC4xx_PLB); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal); + object_unref(OBJECT(dev)); /* interrupt controllers */ for (i = 0; i < ARRAY_SIZE(uic); i++) { - SysBusDevice *sbd; /* * UICs 1, 2 and 3 are cascaded through UIC 0. * input_ints[n] is the interrupt number on UIC 0 which @@ -325,22 +324,20 @@ static void sam460ex_init(MachineState *machine) const int input_ints[] = { -1, 30, 10, 16 }; uic[i] = qdev_new(TYPE_PPC_UIC); - sbd = SYS_BUS_DEVICE(uic[i]); - qdev_prop_set_uint32(uic[i], "dcr-base", 0xc0 + i * 0x10); - object_property_set_link(OBJECT(uic[i]), "cpu", OBJECT(cpu), - &error_fatal); - sysbus_realize_and_unref(sbd, &error_fatal); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uic[i]), cpu, &error_fatal); + object_unref(OBJECT(uic[i])); + sbdev = SYS_BUS_DEVICE(uic[i]); if (i == 0) { - sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT, + sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_INT, qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT)); - sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT, + sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_CINT, qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT)); } else { - sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT, + sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_INT, qdev_get_gpio_in(uic[0], input_ints[i])); - sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT, + sysbus_connect_irq(sbdev, PPCUIC_OUTPUT_CINT, qdev_get_gpio_in(uic[0], input_ints[i] + 1)); } } @@ -371,7 +368,9 @@ static void sam460ex_init(MachineState *machine) qdev_get_gpio_in(uic[0], 3)); /* External bus controller */ - ppc405_ebc_init(env); + dev = qdev_new(TYPE_PPC4xx_EBC); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal); + object_unref(OBJECT(dev)); /* CPR */ ppc4xx_cpr_init(env); @@ -383,10 +382,15 @@ static void sam460ex_init(MachineState *machine) ppc4xx_sdr_init(env); /* MAL */ - for (i = 0; i < ARRAY_SIZE(mal_irqs); i++) { - mal_irqs[0] = qdev_get_gpio_in(uic[2], 3 + i); + dev = qdev_new(TYPE_PPC4xx_MAL); + qdev_prop_set_uint32(dev, "txc-num", 4); + qdev_prop_set_uint32(dev, "rxc-num", 16); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal); + object_unref(OBJECT(dev)); + sbdev = SYS_BUS_DEVICE(dev); + for (i = 0; i < ARRAY_SIZE(PPC4xx_MAL(dev)->irqs); i++) { + sysbus_connect_irq(sbdev, i, qdev_get_gpio_in(uic[2], 3 + i)); } - ppc4xx_mal_init(env, 4, 16, mal_irqs); /* DMA */ ppc4xx_dma_init(env, 0x200); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index bc9ba6e6dc..8bbaf4f8a4 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -177,8 +177,8 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, int smt_threads) { int i, ret = 0; - uint32_t servers_prop[smt_threads]; - uint32_t gservers_prop[smt_threads * 2]; + g_autofree uint32_t *servers_prop = g_new(uint32_t, smt_threads); + g_autofree uint32_t *gservers_prop = g_new(uint32_t, smt_threads * 2); int index = spapr_get_vcpu_id(cpu); if (cpu->compat_pvr) { @@ -196,12 +196,12 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, gservers_prop[i*2 + 1] = 0; } ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", - servers_prop, sizeof(servers_prop)); + servers_prop, sizeof(*servers_prop) * smt_threads); if (ret < 0) { return ret; } ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s", - gservers_prop, sizeof(gservers_prop)); + gservers_prop, sizeof(*gservers_prop) * smt_threads * 2); return ret; } @@ -1522,7 +1522,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize) void spapr_free_hpt(SpaprMachineState *spapr) { - g_free(spapr->htab); + qemu_vfree(spapr->htab); spapr->htab = NULL; spapr->htab_shift = 0; close_htab_fd(spapr); @@ -4731,14 +4731,25 @@ static void spapr_machine_latest_class_options(MachineClass *mc) type_init(spapr_machine_register_##suffix) /* - * pseries-7.1 + * pseries-7.2 */ -static void spapr_machine_7_1_class_options(MachineClass *mc) +static void spapr_machine_7_2_class_options(MachineClass *mc) { /* Defaults for the latest behaviour inherited from the base class */ } -DEFINE_SPAPR_MACHINE(7_1, "7.1", true); +DEFINE_SPAPR_MACHINE(7_2, "7.2", true); + +/* + * pseries-7.1 + */ +static void spapr_machine_7_1_class_options(MachineClass *mc) +{ + spapr_machine_7_2_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len); +} + +DEFINE_SPAPR_MACHINE(7_1, "7.1", false); /* * pseries-7.0 diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index c4c97da5de..04a64cada3 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -447,9 +447,15 @@ static int flush_worker_cb(void *opaque) { SpaprNVDIMMDeviceFlushState *state = opaque; SpaprDrc *drc = spapr_drc_by_index(state->drcidx); - PCDIMMDevice *dimm = PC_DIMM(drc->dev); - HostMemoryBackend *backend = MEMORY_BACKEND(dimm->hostmem); - int backend_fd = memory_region_get_fd(&backend->mr); + PCDIMMDevice *dimm; + HostMemoryBackend *backend; + int backend_fd; + + g_assert(drc != NULL); + + dimm = PC_DIMM(drc->dev); + backend = MEMORY_BACKEND(dimm->hostmem); + backend_fd = memory_region_get_fd(&backend->mr); if (object_property_get_bool(OBJECT(backend), "pmem", NULL)) { MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem); @@ -475,7 +481,11 @@ static void spapr_nvdimm_flush_completion_cb(void *opaque, int hcall_ret) { SpaprNVDIMMDeviceFlushState *state = opaque; SpaprDrc *drc = spapr_drc_by_index(state->drcidx); - SpaprNVDIMMDevice *s_nvdimm = SPAPR_NVDIMM(drc->dev); + SpaprNVDIMMDevice *s_nvdimm; + + g_assert(drc != NULL); + + s_nvdimm = SPAPR_NVDIMM(drc->dev); state->hcall_ret = hcall_ret; QLIST_REMOVE(state, node); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 67e9d468aa..57c8a4f085 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -800,6 +800,7 @@ static char *spapr_phb_vfio_get_loc_code(SpaprPhbState *sphb, PCIDevice *pdev) } /* Construct and read from host device tree the loc-code */ + g_free(path); path = g_strdup_printf("/proc/device-tree%s/ibm,loc-code", devspec); if (!g_file_get_contents(path, &buf, NULL, NULL)) { return NULL; diff --git a/hw/ppc/spapr_pci_nvlink2.c b/hw/ppc/spapr_pci_nvlink2.c index 63b476c8f7..2a8a11be1d 100644 --- a/hw/ppc/spapr_pci_nvlink2.c +++ b/hw/ppc/spapr_pci_nvlink2.c @@ -397,7 +397,7 @@ void spapr_phb_nvgpu_populate_pcidev_dt(PCIDevice *dev, void *fdt, int offset, continue; } if (dev == nvslot->gpdev) { - uint32_t npus[nvslot->linknum]; + g_autofree uint32_t *npus = g_new(uint32_t, nvslot->linknum); for (j = 0; j < nvslot->linknum; ++j) { PCIDevice *npdev = nvslot->links[j].npdev; diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 5c0a215cad..a07d5aca0f 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -95,6 +95,17 @@ vof_write(uint32_t ih, unsigned cb, const char *msg) "ih=0x%x [%u] \"%s\"" vof_avail(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64 vof_claimed(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64 +# pnv_sbe.c +pnv_sbe_xscom_ctrl_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64 +pnv_sbe_xscom_ctrl_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64 +pnv_sbe_xscom_mbox_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64 +pnv_sbe_xscom_mbox_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64 +pnv_sbe_reg_set_host_doorbell(uint64_t val) "val 0x%" PRIx64 +pnv_sbe_cmd_timer_start(uint64_t ns) "ns 0x%" PRIu64 +pnv_sbe_cmd_timer_stop(void) "" +pnv_sbe_cmd_timer_expired(void) "" +pnv_sbe_msg_recv(uint16_t cmd, uint16_t seq, uint16_t ctrl_flags) "cmd 0x%" PRIx16 " seq %"PRIu16 " ctrl_flags 0x%" PRIx16 + # ppc.c ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)" ppc_tb_load(uint64_t tb) "tb 0x%016" PRIx64 @@ -150,11 +161,9 @@ ppc440_pcix_reg_write(uint64_t addr, uint32_t val, uint32_t size) "addr 0x%" PRI # ppc405_boards.c opba_readb(uint64_t addr, uint32_t val) "addr 0x%" PRIx64 " = 0x%" PRIx32 opba_writeb(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " = 0x%" PRIx64 -opba_init(uint64_t addr) "offet 0x%" PRIx64 ppc405_gpio_read(uint64_t addr, uint32_t size) "addr 0x%" PRIx64 " size %d" ppc405_gpio_write(uint64_t addr, uint32_t size, uint64_t val) "addr 0x%" PRIx64 " size %d = 0x%" PRIx64 -ppc405_gpio_init(uint64_t addr) "offet 0x%" PRIx64 ocm_update_mappings(uint32_t isarc, uint32_t isacntl, uint32_t dsarc, uint32_t dsacntl, uint32_t ocm_isarc, uint32_t ocm_isacntl, uint32_t ocm_dsarc, uint32_t ocm_dsacntl) "OCM update ISA 0x%08" PRIx32 " 0x%08" PRIx32 " (0x%08" PRIx32" 0x%08" PRIx32 ") DSA 0x%08" PRIx32 " 0x%08" PRIx32" (0x%08" PRIx32 " 0x%08" PRIx32 ")" ocm_map(const char* prefix, uint32_t isarc) "OCM map %s 0x%08" PRIx32 @@ -162,7 +171,6 @@ ocm_unmap(const char* prefix, uint32_t isarc) "OCM unmap %s 0x%08" PRIx32 ppc4xx_gpt_read(uint64_t addr, uint32_t size) "addr 0x%" PRIx64 " size %d" ppc4xx_gpt_write(uint64_t addr, uint32_t size, uint64_t val) "addr 0x%" PRIx64 " size %d = 0x%" PRIx64 -ppc4xx_gpt_init(uint64_t addr) "offet 0x%" PRIx64 ppc405ep_clocks_compute(const char *param, uint32_t param2, uint32_t val) "%s 0x%1" PRIx32 " %d" ppc405ep_clocks_setup(const char *trace) "%s" diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 53b126ff48..493ea0c19f 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -104,12 +104,9 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk) /* interrupt controller */ uicdev = qdev_new(TYPE_PPC_UIC); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uicdev), cpu, &error_fatal); + object_unref(OBJECT(uicdev)); uicsbd = SYS_BUS_DEVICE(uicdev); - - object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu), - &error_fatal); - sysbus_realize_and_unref(uicsbd, &error_fatal); - sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT)); sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, diff --git a/hw/remote/iommu.c b/hw/remote/iommu.c index fd723d91f3..1391dd712c 100644 --- a/hw/remote/iommu.c +++ b/hw/remote/iommu.c @@ -47,7 +47,7 @@ static AddressSpace *remote_iommu_find_add_as(PCIBus *pci_bus, elem = g_hash_table_lookup(iommu->elem_by_devfn, INT2VOIDP(devfn)); if (!elem) { - elem = g_malloc0(sizeof(RemoteIommuElem)); + elem = g_new0(RemoteIommuElem, 1); g_hash_table_insert(iommu->elem_by_devfn, INT2VOIDP(devfn), elem); } diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 06b4fc5ac3..1ae7596873 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -286,7 +286,7 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts hwaddr start_addr, hwaddr rom_base, hwaddr rom_size, uint64_t kernel_entry, - uint64_t fdt_load_addr, void *fdt) + uint64_t fdt_load_addr) { int i; uint32_t start_addr_hi32 = 0x00000000; @@ -326,8 +326,6 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts rom_base, &address_space_memory); riscv_rom_copy_firmware_info(machine, rom_base, rom_size, sizeof(reset_vec), kernel_entry); - - return; } void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 10a5d0e501..a821263d4f 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -100,8 +100,11 @@ static const MemMapEntry microchip_pfsoc_memmap[] = { [MICROCHIP_PFSOC_L2LIM] = { 0x8000000, 0x2000000 }, [MICROCHIP_PFSOC_PLIC] = { 0xc000000, 0x4000000 }, [MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 }, + [MICROCHIP_PFSOC_WDOG0] = { 0x20001000, 0x1000 }, [MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 }, + [MICROCHIP_PFSOC_AXISW] = { 0x20004000, 0x1000 }, [MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 }, + [MICROCHIP_PFSOC_FMETER] = { 0x20006000, 0x1000 }, [MICROCHIP_PFSOC_DDR_SGMII_PHY] = { 0x20007000, 0x1000 }, [MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 }, [MICROCHIP_PFSOC_DDR_CFG] = { 0x20080000, 0x40000 }, @@ -109,19 +112,28 @@ static const MemMapEntry microchip_pfsoc_memmap[] = { [MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 }, [MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 }, [MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 }, + [MICROCHIP_PFSOC_WDOG1] = { 0x20101000, 0x1000 }, + [MICROCHIP_PFSOC_WDOG2] = { 0x20103000, 0x1000 }, + [MICROCHIP_PFSOC_WDOG3] = { 0x20105000, 0x1000 }, + [MICROCHIP_PFSOC_WDOG4] = { 0x20106000, 0x1000 }, [MICROCHIP_PFSOC_SPI0] = { 0x20108000, 0x1000 }, [MICROCHIP_PFSOC_SPI1] = { 0x20109000, 0x1000 }, + [MICROCHIP_PFSOC_I2C0] = { 0x2010a000, 0x1000 }, [MICROCHIP_PFSOC_I2C1] = { 0x2010b000, 0x1000 }, + [MICROCHIP_PFSOC_CAN0] = { 0x2010c000, 0x1000 }, + [MICROCHIP_PFSOC_CAN1] = { 0x2010d000, 0x1000 }, [MICROCHIP_PFSOC_GEM0] = { 0x20110000, 0x2000 }, [MICROCHIP_PFSOC_GEM1] = { 0x20112000, 0x2000 }, [MICROCHIP_PFSOC_GPIO0] = { 0x20120000, 0x1000 }, [MICROCHIP_PFSOC_GPIO1] = { 0x20121000, 0x1000 }, [MICROCHIP_PFSOC_GPIO2] = { 0x20122000, 0x1000 }, + [MICROCHIP_PFSOC_RTC] = { 0x20124000, 0x1000 }, [MICROCHIP_PFSOC_ENVM_CFG] = { 0x20200000, 0x1000 }, [MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 }, + [MICROCHIP_PFSOC_USB] = { 0x20201000, 0x1000 }, [MICROCHIP_PFSOC_QSPI_XIP] = { 0x21000000, 0x1000000 }, [MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 }, - [MICROCHIP_PFSOC_EMMC_SD_MUX] = { 0x4f000000, 0x4 }, + [MICROCHIP_PFSOC_FABRIC_FIC3] = { 0x40000000, 0x20000000 }, [MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 }, [MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 }, [MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 }, @@ -292,11 +304,21 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysreg), 0, memmap[MICROCHIP_PFSOC_SYSREG].base); + /* AXISW */ + create_unimplemented_device("microchip.pfsoc.axisw", + memmap[MICROCHIP_PFSOC_AXISW].base, + memmap[MICROCHIP_PFSOC_AXISW].size); + /* MPUCFG */ create_unimplemented_device("microchip.pfsoc.mpucfg", memmap[MICROCHIP_PFSOC_MPUCFG].base, memmap[MICROCHIP_PFSOC_MPUCFG].size); + /* FMETER */ + create_unimplemented_device("microchip.pfsoc.fmeter", + memmap[MICROCHIP_PFSOC_FMETER].base, + memmap[MICROCHIP_PFSOC_FMETER].size); + /* DDR SGMII PHY */ sysbus_realize(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), errp); sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_sgmii_phy), 0, @@ -336,6 +358,23 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART4_IRQ), serial_hd(4)); + /* Watchdogs */ + create_unimplemented_device("microchip.pfsoc.watchdog0", + memmap[MICROCHIP_PFSOC_WDOG0].base, + memmap[MICROCHIP_PFSOC_WDOG0].size); + create_unimplemented_device("microchip.pfsoc.watchdog1", + memmap[MICROCHIP_PFSOC_WDOG1].base, + memmap[MICROCHIP_PFSOC_WDOG1].size); + create_unimplemented_device("microchip.pfsoc.watchdog2", + memmap[MICROCHIP_PFSOC_WDOG2].base, + memmap[MICROCHIP_PFSOC_WDOG2].size); + create_unimplemented_device("microchip.pfsoc.watchdog3", + memmap[MICROCHIP_PFSOC_WDOG3].base, + memmap[MICROCHIP_PFSOC_WDOG3].size); + create_unimplemented_device("microchip.pfsoc.watchdog4", + memmap[MICROCHIP_PFSOC_WDOG4].base, + memmap[MICROCHIP_PFSOC_WDOG4].size); + /* SPI */ create_unimplemented_device("microchip.pfsoc.spi0", memmap[MICROCHIP_PFSOC_SPI0].base, @@ -344,11 +383,27 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) memmap[MICROCHIP_PFSOC_SPI1].base, memmap[MICROCHIP_PFSOC_SPI1].size); - /* I2C1 */ + /* I2C */ + create_unimplemented_device("microchip.pfsoc.i2c0", + memmap[MICROCHIP_PFSOC_I2C0].base, + memmap[MICROCHIP_PFSOC_I2C0].size); create_unimplemented_device("microchip.pfsoc.i2c1", memmap[MICROCHIP_PFSOC_I2C1].base, memmap[MICROCHIP_PFSOC_I2C1].size); + /* CAN */ + create_unimplemented_device("microchip.pfsoc.can0", + memmap[MICROCHIP_PFSOC_CAN0].base, + memmap[MICROCHIP_PFSOC_CAN0].size); + create_unimplemented_device("microchip.pfsoc.can1", + memmap[MICROCHIP_PFSOC_CAN1].base, + memmap[MICROCHIP_PFSOC_CAN1].size); + + /* USB */ + create_unimplemented_device("microchip.pfsoc.usb", + memmap[MICROCHIP_PFSOC_USB].base, + memmap[MICROCHIP_PFSOC_USB].size); + /* GEMs */ nd = &nd_table[0]; @@ -402,10 +457,10 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->ioscb), 0, memmap[MICROCHIP_PFSOC_IOSCB].base); - /* eMMC/SD mux */ - create_unimplemented_device("microchip.pfsoc.emmc_sd_mux", - memmap[MICROCHIP_PFSOC_EMMC_SD_MUX].base, - memmap[MICROCHIP_PFSOC_EMMC_SD_MUX].size); + /* FPGA Fabric */ + create_unimplemented_device("microchip.pfsoc.fabricfic3", + memmap[MICROCHIP_PFSOC_FABRIC_FIC3].base, + memmap[MICROCHIP_PFSOC_FABRIC_FIC3].size); /* QSPI Flash */ memory_region_init_rom(qspi_xip_mem, OBJECT(dev), @@ -583,7 +638,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr, memmap[MICROCHIP_PFSOC_ENVM_DATA].base, memmap[MICROCHIP_PFSOC_ENVM_DATA].size, - kernel_entry, fdt_load_addr, machine->fdt); + kernel_entry, fdt_load_addr); } } diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 4495a2c039..be7ff1eea0 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -29,9 +29,9 @@ #include "sysemu/sysemu.h" static const MemMapEntry ibex_memmap[] = { - [IBEX_DEV_ROM] = { 0x00008000, 16 * KiB }, - [IBEX_DEV_RAM] = { 0x10000000, 0x10000 }, - [IBEX_DEV_FLASH] = { 0x20000000, 0x80000 }, + [IBEX_DEV_ROM] = { 0x00008000, 0x8000 }, + [IBEX_DEV_RAM] = { 0x10000000, 0x20000 }, + [IBEX_DEV_FLASH] = { 0x20000000, 0x100000 }, [IBEX_DEV_UART] = { 0x40000000, 0x1000 }, [IBEX_DEV_GPIO] = { 0x40040000, 0x1000 }, [IBEX_DEV_SPI_DEVICE] = { 0x40050000, 0x1000 }, @@ -40,6 +40,7 @@ static const MemMapEntry ibex_memmap[] = { [IBEX_DEV_TIMER] = { 0x40100000, 0x1000 }, [IBEX_DEV_SENSOR_CTRL] = { 0x40110000, 0x1000 }, [IBEX_DEV_OTP_CTRL] = { 0x40130000, 0x4000 }, + [IBEX_DEV_LC_CTRL] = { 0x40140000, 0x1000 }, [IBEX_DEV_USBDEV] = { 0x40150000, 0x1000 }, [IBEX_DEV_SPI_HOST0] = { 0x40300000, 0x1000 }, [IBEX_DEV_SPI_HOST1] = { 0x40310000, 0x1000 }, @@ -141,7 +142,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, &error_abort); - object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8080, &error_abort); + object_property_set_int(OBJECT(&s->cpus), "resetvec", s->resetvec, + &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal); /* Boot ROM */ @@ -253,6 +255,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memmap[IBEX_DEV_SENSOR_CTRL].base, memmap[IBEX_DEV_SENSOR_CTRL].size); create_unimplemented_device("riscv.lowrisc.ibex.otp_ctrl", memmap[IBEX_DEV_OTP_CTRL].base, memmap[IBEX_DEV_OTP_CTRL].size); + create_unimplemented_device("riscv.lowrisc.ibex.lc_ctrl", + memmap[IBEX_DEV_LC_CTRL].base, memmap[IBEX_DEV_LC_CTRL].size); create_unimplemented_device("riscv.lowrisc.ibex.pwrmgr", memmap[IBEX_DEV_PWRMGR].base, memmap[IBEX_DEV_PWRMGR].size); create_unimplemented_device("riscv.lowrisc.ibex.rstmgr", @@ -293,10 +297,16 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memmap[IBEX_DEV_PERI].base, memmap[IBEX_DEV_PERI].size); } +static Property lowrisc_ibex_soc_props[] = { + DEFINE_PROP_UINT32("resetvec", LowRISCIbexSoCState, resetvec, 0x20000400), + DEFINE_PROP_END_OF_LIST() +}; + static void lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, lowrisc_ibex_soc_props); dc->realize = lowrisc_ibex_soc_realize; /* Reason: Uses serial_hds in realize function, thus can't be used twice */ dc->user_creatable = false; diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c index 90e2cf609f..e43cc9445c 100644 --- a/hw/riscv/shakti_c.c +++ b/hw/riscv/shakti_c.c @@ -66,8 +66,7 @@ static void shakti_c_machine_state_init(MachineState *mstate) riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus, shakti_c_memmap[SHAKTI_C_RAM].base, shakti_c_memmap[SHAKTI_C_ROM].base, - shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0, - NULL); + shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0); if (mstate->firmware) { riscv_load_firmware(mstate->firmware, shakti_c_memmap[SHAKTI_C_RAM].base, diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index e41b6aa9f0..5ba34543c8 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -308,7 +308,7 @@ static void spike_board_init(MachineState *machine) riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base, memmap[SPIKE_MROM].base, memmap[SPIKE_MROM].size, kernel_entry, - fdt_load_addr, s->fdt); + fdt_load_addr); /* initialize HTIF using symbols found in load_kernel */ htif_mm_init(system_memory, mask_rom, diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index bc424dd2f5..befa9d2c26 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "hw/boards.h" #include "hw/loader.h" @@ -29,6 +30,7 @@ #include "hw/char/serial.h" #include "target/riscv/cpu.h" #include "hw/core/sysbus-fdt.h" +#include "target/riscv/pmu.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/virt.h" #include "hw/riscv/boot.h" @@ -259,17 +261,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, qemu_fdt_add_subnode(mc->fdt, intc_name); qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle", intc_phandles[cpu]); - if (riscv_feature(&s->soc[socket].harts[cpu].env, - RISCV_FEATURE_AIA)) { - static const char * const compat[2] = { - "riscv,cpu-intc-aia", "riscv,cpu-intc" - }; - qemu_fdt_setprop_string_array(mc->fdt, intc_name, "compatible", - (char **)&compat, ARRAY_SIZE(compat)); - } else { - qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible", - "riscv,cpu-intc"); - } + qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible", + "riscv,cpu-intc"); qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1); @@ -465,6 +458,8 @@ static void create_fdt_socket_plic(RISCVVirtState *s, qemu_fdt_add_subnode(mc->fdt, plic_name); qemu_fdt_setprop_cell(mc->fdt, plic_name, "#interrupt-cells", FDT_PLIC_INT_CELLS); + qemu_fdt_setprop_cell(mc->fdt, plic_name, + "#address-cells", FDT_PLIC_ADDR_CELLS); qemu_fdt_setprop_string_array(mc->fdt, plic_name, "compatible", (char **)&plic_compat, ARRAY_SIZE(plic_compat)); @@ -714,6 +709,20 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, aplic_phandles[socket] = aplic_s_phandle; } +static void create_fdt_pmu(RISCVVirtState *s) +{ + char *pmu_name; + MachineState *mc = MACHINE(s); + RISCVCPU hart = s->soc[0].harts[0]; + + pmu_name = g_strdup_printf("/soc/pmu"); + qemu_fdt_add_subnode(mc->fdt, pmu_name); + qemu_fdt_setprop_string(mc->fdt, pmu_name, "compatible", "riscv,pmu"); + riscv_pmu_generate_fdt_node(mc->fdt, hart.cfg.pmu_num, pmu_name); + + g_free(pmu_name); +} + static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, bool is_32_bit, uint32_t *phandle, uint32_t *irq_mmio_phandle, @@ -894,7 +903,7 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, test_phandle = qemu_fdt_get_phandle(mc->fdt, name); g_free(name); - name = g_strdup_printf("/soc/reboot"); + name = g_strdup_printf("/reboot"); qemu_fdt_add_subnode(mc->fdt, name); qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot"); qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle); @@ -902,7 +911,7 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET); g_free(name); - name = g_strdup_printf("/soc/poweroff"); + name = g_strdup_printf("/poweroff"); qemu_fdt_add_subnode(mc->fdt, name); qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff"); qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle); @@ -917,7 +926,7 @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, char *name; MachineState *mc = MACHINE(s); - name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base); + name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base); qemu_fdt_add_subnode(mc->fdt, name); qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a"); qemu_fdt_setprop_cells(mc->fdt, name, "reg", @@ -998,6 +1007,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, MachineState *mc = MACHINE(s); uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1; uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; + uint8_t rng_seed[32]; if (mc->dtb) { mc->fdt = load_device_tree(mc->dtb, &s->fdt_size); @@ -1041,11 +1051,16 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, create_fdt_flash(s, memmap); create_fdt_fw_cfg(s, memmap); + create_fdt_pmu(s); update_bootargs: if (cmdline && *cmdline) { qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline); } + + /* Pass seed to RNG */ + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + qemu_fdt_setprop(mc->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); } static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, @@ -1299,7 +1314,7 @@ static void virt_machine_done(Notifier *notifier, void *data) riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr, virt_memmap[VIRT_MROM].base, virt_memmap[VIRT_MROM].size, kernel_entry, - fdt_load_addr, machine->fdt); + fdt_load_addr); /* * Only direct boot kernel is currently supported for KVM VM, diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be31..19a56402a0 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -216,14 +216,25 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) return 0; } -static const MemoryRegionOps goldfish_rtc_ops = { - .read = goldfish_rtc_read, - .write = goldfish_rtc_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } +static const MemoryRegionOps goldfish_rtc_ops[2] = { + [false] = { + .read = goldfish_rtc_read, + .write = goldfish_rtc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } + }, + [true] = { + .read = goldfish_rtc_read, + .write = goldfish_rtc_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } + }, }; static const VMStateDescription goldfish_rtc_vmstate = { @@ -265,7 +276,8 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) SysBusDevice *dev = SYS_BUS_DEVICE(d); GoldfishRTCState *s = GOLDFISH_RTC(d); - memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_rtc_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), + &goldfish_rtc_ops[s->big_endian], s, "goldfish_rtc", 0x24); sysbus_init_mmio(dev, &s->iomem); @@ -274,10 +286,17 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); } +static Property goldfish_rtc_properties[] = { + DEFINE_PROP_BOOL("big-endian", GoldfishRTCState, big_endian, + false), + DEFINE_PROP_END_OF_LIST(), +}; + static void goldfish_rtc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + device_class_set_props(dc, goldfish_rtc_properties); dc->realize = goldfish_rtc_realize; dc->reset = goldfish_rtc_reset; dc->vmsd = &goldfish_rtc_vmstate; diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build index feefe0717e..f291016fee 100644 --- a/hw/s390x/meson.build +++ b/hw/s390x/meson.build @@ -23,6 +23,7 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files( 's390-skeys-kvm.c', 's390-stattrib-kvm.c', 'pv.c', + 's390-pci-kvm.c', )) s390x_ss.add(when: 'CONFIG_TCG', if_true: files( 'tod-tcg.c', diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 2fc8bb9c23..e2d86d96e7 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -57,7 +57,7 @@ IOInstEnding s390_ccw_store(SubchDev *sch) /* * This code is called for both virtual and passthrough devices, - * but only applies to to the latter. This ugly check makes that + * but only applies to the latter. This ugly check makes that * distinction for us. */ if (object_dynamic_cast(OBJECT(sch->driver_data), TYPE_S390_CCW)) { diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 4b2bdd94b3..977e7daa15 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -16,6 +16,7 @@ #include "qapi/visitor.h" #include "hw/s390x/s390-pci-bus.h" #include "hw/s390x/s390-pci-inst.h" +#include "hw/s390x/s390-pci-kvm.h" #include "hw/s390x/s390-pci-vfio.h" #include "hw/pci/pci_bus.h" #include "hw/qdev-properties.h" @@ -189,7 +190,10 @@ void s390_pci_sclp_deconfigure(SCCB *sccb) rc = SCLP_RC_NO_ACTION_REQUIRED; break; default: - if (pbdev->summary_ind) { + if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) { + /* Interpreted devices were using interrupt forwarding */ + s390_pci_kvm_aif_disable(pbdev); + } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { @@ -744,13 +748,14 @@ static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn) object_unref(OBJECT(iommu)); } -S390PCIGroup *s390_group_create(int id) +S390PCIGroup *s390_group_create(int id, int host_id) { S390PCIGroup *group; S390pciState *s = s390_get_phb(); group = g_new0(S390PCIGroup, 1); group->id = id; + group->host_id = host_id; QTAILQ_INSERT_TAIL(&s->zpci_groups, group, link); return group; } @@ -768,12 +773,25 @@ S390PCIGroup *s390_group_find(int id) return NULL; } +S390PCIGroup *s390_group_find_host_sim(int host_id) +{ + S390PCIGroup *group; + S390pciState *s = s390_get_phb(); + + QTAILQ_FOREACH(group, &s->zpci_groups, link) { + if (group->id >= ZPCI_SIM_GRP_START && group->host_id == host_id) { + return group; + } + } + return NULL; +} + static void s390_pci_init_default_group(void) { S390PCIGroup *group; ClpRspQueryPciGrp *resgrp; - group = s390_group_create(ZPCI_DEFAULT_FN_GRP); + group = s390_group_create(ZPCI_DEFAULT_FN_GRP, ZPCI_DEFAULT_FN_GRP); resgrp = &group->zpci_group; resgrp->fr = 1; resgrp->dasm = 0; @@ -821,6 +839,7 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp) NULL, g_free); s->zpci_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, NULL); s->bus_no = 0; + s->next_sim_grp = ZPCI_SIM_GRP_START; QTAILQ_INIT(&s->pending_sei); QTAILQ_INIT(&s->zpci_devs); QTAILQ_INIT(&s->zpci_dma_limit); @@ -880,6 +899,10 @@ static int s390_pci_msix_init(S390PCIBusDevice *pbdev) static void s390_pci_msix_free(S390PCIBusDevice *pbdev) { + if (pbdev->msix.entries == 0) { + return; + } + memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->msix_notify_mr); object_unparent(OBJECT(&pbdev->msix_notify_mr)); } @@ -971,12 +994,51 @@ static void s390_pci_update_subordinate(PCIDevice *dev, uint32_t nr) } } +static int s390_pci_interp_plug(S390pciState *s, S390PCIBusDevice *pbdev) +{ + uint32_t idx, fh; + + if (!s390_pci_get_host_fh(pbdev, &fh)) { + return -EPERM; + } + + /* + * The host device is already in an enabled state, but we always present + * the initial device state to the guest as disabled (ZPCI_FS_DISABLED). + * Therefore, mask off the enable bit from the passthrough handle until + * the guest issues a CLP SET PCI FN later to enable the device. + */ + pbdev->fh = fh & ~FH_MASK_ENABLE; + + /* Next, see if the idx is already in-use */ + idx = pbdev->fh & FH_MASK_INDEX; + if (pbdev->idx != idx) { + if (s390_pci_find_dev_by_idx(s, idx)) { + return -EINVAL; + } + /* + * Update the idx entry with the passed through idx + * If the relinquished idx is lower than next_idx, use it + * to replace next_idx + */ + g_hash_table_remove(s->zpci_table, &pbdev->idx); + if (idx < s->next_idx) { + s->next_idx = idx; + } + pbdev->idx = idx; + g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev); + } + + return 0; +} + static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev); PCIDevice *pdev = NULL; S390PCIBusDevice *pbdev = NULL; + int rc; if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { PCIBridge *pb = PCI_BRIDGE(dev); @@ -1022,15 +1084,41 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, set_pbdev_info(pbdev); if (object_dynamic_cast(OBJECT(dev), "vfio-pci")) { - pbdev->fh |= FH_SHM_VFIO; + /* + * By default, interpretation is always requested; if the available + * facilities indicate it is not available, fallback to the + * interception model. + */ + if (pbdev->interp) { + if (s390_pci_kvm_interp_allowed()) { + rc = s390_pci_interp_plug(s, pbdev); + if (rc) { + error_setg(errp, "Plug failed for zPCI device in " + "interpretation mode: %d", rc); + return; + } + } else { + DPRINTF("zPCI interpretation facilities missing.\n"); + pbdev->interp = false; + pbdev->forwarding_assist = false; + } + } pbdev->iommu->dma_limit = s390_pci_start_dma_count(s, pbdev); /* Fill in CLP information passed via the vfio region */ s390_pci_get_clp_info(pbdev); + if (!pbdev->interp) { + /* Do vfio passthrough but intercept for I/O */ + pbdev->fh |= FH_SHM_VFIO; + pbdev->forwarding_assist = false; + } } else { pbdev->fh |= FH_SHM_EMUL; + /* Always intercept emulated devices */ + pbdev->interp = false; + pbdev->forwarding_assist = false; } - if (s390_pci_msix_init(pbdev)) { + if (s390_pci_msix_init(pbdev) && !pbdev->interp) { error_setg(errp, "MSI-X support is mandatory " "in the S390 architecture"); return; @@ -1177,7 +1265,10 @@ static void s390_pcihost_reset(DeviceState *dev) /* Process all pending unplug requests */ QTAILQ_FOREACH_SAFE(pbdev, &s->zpci_devs, link, next) { if (pbdev->unplug_requested) { - if (pbdev->summary_ind) { + if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) { + /* Interpreted devices were using interrupt forwarding */ + s390_pci_kvm_aif_disable(pbdev); + } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { @@ -1315,7 +1406,10 @@ static void s390_pci_device_reset(DeviceState *dev) break; } - if (pbdev->summary_ind) { + if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) { + /* Interpreted devices were using interrupt forwarding */ + s390_pci_kvm_aif_disable(pbdev); + } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { @@ -1360,6 +1454,9 @@ static Property s390_pci_device_properties[] = { DEFINE_PROP_UINT16("uid", S390PCIBusDevice, uid, UID_UNDEFINED), DEFINE_PROP_S390_PCI_FID("fid", S390PCIBusDevice, fid), DEFINE_PROP_STRING("target", S390PCIBusDevice, target), + DEFINE_PROP_BOOL("interpret", S390PCIBusDevice, interp, true), + DEFINE_PROP_BOOL("forwarding-assist", S390PCIBusDevice, forwarding_assist, + true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 6d400d4147..20a9bcc7af 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -18,6 +18,8 @@ #include "sysemu/hw_accel.h" #include "hw/s390x/s390-pci-inst.h" #include "hw/s390x/s390-pci-bus.h" +#include "hw/s390x/s390-pci-kvm.h" +#include "hw/s390x/s390-pci-vfio.h" #include "hw/s390x/tod.h" #ifndef DEBUG_S390PCI_INST @@ -246,6 +248,20 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) goto out; } + /* + * Take this opportunity to make sure we still have an accurate + * host fh. It's possible part of the handle changed while the + * device was disabled to the guest (e.g. vfio hot reset for + * ISM during plug) + */ + if (pbdev->interp) { + /* Take this opportunity to make sure we are sync'd with host */ + if (!s390_pci_get_host_fh(pbdev, &pbdev->fh) || + !(pbdev->fh & FH_MASK_ENABLE)) { + stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH); + goto out; + } + } pbdev->fh |= FH_MASK_ENABLE; pbdev->state = ZPCI_FS_ENABLED; stl_p(&ressetpci->fh, pbdev->fh); @@ -1050,6 +1066,32 @@ static void fmb_update(void *opaque) timer_mod(pbdev->fmb_timer, t + pbdev->pci_group->zpci_group.mui); } +static int mpcifc_reg_int_interp(S390PCIBusDevice *pbdev, ZpciFib *fib) +{ + int rc; + + rc = s390_pci_kvm_aif_enable(pbdev, fib, pbdev->forwarding_assist); + if (rc) { + DPRINTF("Failed to enable interrupt forwarding\n"); + return rc; + } + + return 0; +} + +static int mpcifc_dereg_int_interp(S390PCIBusDevice *pbdev, ZpciFib *fib) +{ + int rc; + + rc = s390_pci_kvm_aif_disable(pbdev); + if (rc) { + DPRINTF("Failed to disable interrupt forwarding\n"); + return rc; + } + + return 0; +} + int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra) { @@ -1104,7 +1146,12 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, switch (oc) { case ZPCI_MOD_FC_REG_INT: - if (pbdev->summary_ind) { + if (pbdev->interp) { + if (mpcifc_reg_int_interp(pbdev, &fib)) { + cc = ZPCI_PCI_LS_ERR; + s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); + } + } else if (pbdev->summary_ind) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else if (reg_irqs(env, pbdev, fib)) { @@ -1113,7 +1160,12 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, } break; case ZPCI_MOD_FC_DEREG_INT: - if (!pbdev->summary_ind) { + if (pbdev->interp) { + if (mpcifc_dereg_int_interp(pbdev, &fib)) { + cc = ZPCI_PCI_LS_ERR; + s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); + } + } else if (!pbdev->summary_ind) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { diff --git a/hw/s390x/s390-pci-kvm.c b/hw/s390x/s390-pci-kvm.c new file mode 100644 index 0000000000..5eb7fd12e2 --- /dev/null +++ b/hw/s390x/s390-pci-kvm.c @@ -0,0 +1,54 @@ +/* + * s390 zPCI KVM interfaces + * + * Copyright 2022 IBM Corp. + * Author(s): Matthew Rosato + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "qemu/osdep.h" + +#include + +#include "kvm/kvm_s390x.h" +#include "hw/s390x/pv.h" +#include "hw/s390x/s390-pci-bus.h" +#include "hw/s390x/s390-pci-kvm.h" +#include "hw/s390x/s390-pci-inst.h" +#include "cpu_models.h" + +bool s390_pci_kvm_interp_allowed(void) +{ + return (kvm_s390_get_zpci_op() && !s390_is_pv() && + !object_property_get_bool(OBJECT(qdev_get_machine()), + "zpcii-disable", NULL)); +} + +int s390_pci_kvm_aif_enable(S390PCIBusDevice *pbdev, ZpciFib *fib, bool assist) +{ + struct kvm_s390_zpci_op args = { + .fh = pbdev->fh, + .op = KVM_S390_ZPCIOP_REG_AEN, + .u.reg_aen.ibv = fib->aibv, + .u.reg_aen.sb = fib->aisb, + .u.reg_aen.noi = FIB_DATA_NOI(fib->data), + .u.reg_aen.isc = FIB_DATA_ISC(fib->data), + .u.reg_aen.sbo = FIB_DATA_AISBO(fib->data), + .u.reg_aen.flags = (assist) ? 0 : KVM_S390_ZPCIOP_REGAEN_HOST + }; + + return kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args); +} + +int s390_pci_kvm_aif_disable(S390PCIBusDevice *pbdev) +{ + struct kvm_s390_zpci_op args = { + .fh = pbdev->fh, + .op = KVM_S390_ZPCIOP_DEREG_AEN + }; + + return kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args); +} diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c index 6f80a47e29..2aefa508a0 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -124,18 +124,44 @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev, pbdev->zpci_fn.pft = 0; } +static bool get_host_fh(S390PCIBusDevice *pbdev, struct vfio_device_info *info, + uint32_t *fh) +{ + struct vfio_info_cap_header *hdr; + struct vfio_device_info_cap_zpci_base *cap; + VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); + + hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_BASE); + + /* Can only get the host fh with version 2 or greater */ + if (hdr == NULL || hdr->version < 2) { + trace_s390_pci_clp_cap(vpci->vbasedev.name, + VFIO_DEVICE_INFO_CAP_ZPCI_BASE); + return false; + } + cap = (void *) hdr; + + *fh = cap->fh; + return true; +} + static void s390_pci_read_group(S390PCIBusDevice *pbdev, struct vfio_device_info *info) { struct vfio_info_cap_header *hdr; struct vfio_device_info_cap_zpci_group *cap; + S390pciState *s = s390_get_phb(); ClpRspQueryPciGrp *resgrp; VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); + uint8_t start_gid = pbdev->zpci_fn.pfgid; hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_GROUP); - /* If capability not provided, just use the default group */ - if (hdr == NULL) { + /* + * If capability not provided or the underlying hostdev is simulated, just + * use the default group. + */ + if (hdr == NULL || pbdev->zpci_fn.pfgid >= ZPCI_SIM_GRP_START) { trace_s390_pci_clp_cap(vpci->vbasedev.name, VFIO_DEVICE_INFO_CAP_ZPCI_GROUP); pbdev->zpci_fn.pfgid = ZPCI_DEFAULT_FN_GRP; @@ -144,11 +170,40 @@ static void s390_pci_read_group(S390PCIBusDevice *pbdev, } cap = (void *) hdr; + /* + * For an intercept device, let's use an existing simulated group if one + * one was already created for other intercept devices in this group. + * If not, create a new simulated group if any are still available. + * If all else fails, just fall back on the default group. + */ + if (!pbdev->interp) { + pbdev->pci_group = s390_group_find_host_sim(pbdev->zpci_fn.pfgid); + if (pbdev->pci_group) { + /* Use existing simulated group */ + pbdev->zpci_fn.pfgid = pbdev->pci_group->id; + return; + } else { + if (s->next_sim_grp == ZPCI_DEFAULT_FN_GRP) { + /* All out of simulated groups, use default */ + trace_s390_pci_clp_cap(vpci->vbasedev.name, + VFIO_DEVICE_INFO_CAP_ZPCI_GROUP); + pbdev->zpci_fn.pfgid = ZPCI_DEFAULT_FN_GRP; + pbdev->pci_group = s390_group_find(ZPCI_DEFAULT_FN_GRP); + return; + } else { + /* We can assign a new simulated group */ + pbdev->zpci_fn.pfgid = s->next_sim_grp; + s->next_sim_grp++; + /* Fall through to create the new sim group using CLP info */ + } + } + } + /* See if the PCI group is already defined, create if not */ pbdev->pci_group = s390_group_find(pbdev->zpci_fn.pfgid); if (!pbdev->pci_group) { - pbdev->pci_group = s390_group_create(pbdev->zpci_fn.pfgid); + pbdev->pci_group = s390_group_create(pbdev->zpci_fn.pfgid, start_gid); resgrp = &pbdev->pci_group->zpci_group; if (cap->flags & VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH) { @@ -158,7 +213,11 @@ static void s390_pci_read_group(S390PCIBusDevice *pbdev, resgrp->msia = cap->msi_addr; resgrp->mui = cap->mui; resgrp->i = cap->noi; - resgrp->maxstbl = cap->maxstbl; + if (pbdev->interp && hdr->version >= 2) { + resgrp->maxstbl = cap->imaxstbl; + } else { + resgrp->maxstbl = cap->maxstbl; + } resgrp->version = cap->version; resgrp->dtsm = ZPCI_DTSM; } @@ -217,25 +276,13 @@ static void s390_pci_read_pfip(S390PCIBusDevice *pbdev, memcpy(pbdev->zpci_fn.pfip, cap->pfip, CLP_PFIP_NR_SEGMENTS); } -/* - * This function will issue the VFIO_DEVICE_GET_INFO ioctl and look for - * capabilities that contain information about CLP features provided by the - * underlying host. - * On entry, defaults have already been placed into the guest CLP response - * buffers. On exit, defaults will have been overwritten for any CLP features - * found in the capability chain; defaults will remain for any CLP features not - * found in the chain. - */ -void s390_pci_get_clp_info(S390PCIBusDevice *pbdev) +static struct vfio_device_info *get_device_info(S390PCIBusDevice *pbdev, + uint32_t argsz) { - g_autofree struct vfio_device_info *info = NULL; + struct vfio_device_info *info = g_malloc0(argsz); VFIOPCIDevice *vfio_pci; - uint32_t argsz; int fd; - argsz = sizeof(*info); - info = g_malloc0(argsz); - vfio_pci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); fd = vfio_pci->vbasedev.fd; @@ -250,7 +297,8 @@ retry: if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) { trace_s390_pci_clp_dev_info(vfio_pci->vbasedev.name); - return; + g_free(info); + return NULL; } if (info->argsz > argsz) { @@ -259,6 +307,47 @@ retry: goto retry; } + return info; +} + +/* + * Get the host function handle from the vfio CLP capabilities chain. Returns + * true if a fh value was placed into the provided buffer. Returns false + * if a fh could not be obtained (ioctl failed or capabilitiy version does + * not include the fh) + */ +bool s390_pci_get_host_fh(S390PCIBusDevice *pbdev, uint32_t *fh) +{ + g_autofree struct vfio_device_info *info = NULL; + + assert(fh); + + info = get_device_info(pbdev, sizeof(*info)); + if (!info) { + return false; + } + + return get_host_fh(pbdev, info, fh); +} + +/* + * This function will issue the VFIO_DEVICE_GET_INFO ioctl and look for + * capabilities that contain information about CLP features provided by the + * underlying host. + * On entry, defaults have already been placed into the guest CLP response + * buffers. On exit, defaults will have been overwritten for any CLP features + * found in the capability chain; defaults will remain for any CLP features not + * found in the chain. + */ +void s390_pci_get_clp_info(S390PCIBusDevice *pbdev) +{ + g_autofree struct vfio_device_info *info = NULL; + + info = get_device_info(pbdev, sizeof(*info)); + if (!info) { + return; + } + /* * Find the CLP features provided and fill in the guest CLP responses. * Always call s390_pci_read_base first as information from this could diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index cc3097bfee..03855c7231 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -645,6 +645,21 @@ static inline void machine_set_dea_key_wrap(Object *obj, bool value, ms->dea_key_wrap = value; } +static inline bool machine_get_zpcii_disable(Object *obj, Error **errp) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + + return ms->zpcii_disable; +} + +static inline void machine_set_zpcii_disable(Object *obj, bool value, + Error **errp) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + + ms->zpcii_disable = value; +} + static S390CcwMachineClass *current_mc; /* @@ -740,6 +755,13 @@ static inline void s390_machine_initfn(Object *obj) "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted" " to upper case) to pass to machine loader, boot manager," " and guest kernel"); + + object_property_add_bool(obj, "zpcii-disable", + machine_get_zpcii_disable, + machine_set_zpcii_disable); + object_property_set_description(obj, "zpcii-disable", + "disable zPCI interpretation facilties"); + object_property_set_bool(obj, "zpcii-disable", false, NULL); } static const TypeInfo ccw_machine_info = { @@ -792,14 +814,32 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +static void ccw_machine_7_2_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_7_2_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE(7_2, "7.2", true); + static void ccw_machine_7_1_instance_options(MachineState *machine) { + static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V7_1 }; + S390CcwMachineState *ms = S390_CCW_MACHINE(machine); + + ccw_machine_7_2_instance_options(machine); + s390_cpudef_featoff_greater(16, 1, S390_FEAT_PAIE); + s390_set_qemu_cpu_model(0x8561, 15, 1, qemu_cpu_feat); + ms->zpcii_disable = true; } static void ccw_machine_7_1_class_options(MachineClass *mc) { + ccw_machine_7_2_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len); } -DEFINE_CCW_MACHINE(7_1, "7.1", true); +DEFINE_CCW_MACHINE(7_1, "7.1", false); static void ccw_machine_7_0_instance_options(MachineState *machine) { diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 2d3c649567..2ff18ce500 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -292,7 +292,7 @@ static void do_command_phase(ESPState *s) esp_fifo_pop_buf(&s->cmdfifo, buf, cmdlen); current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, s->lun); - s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, s); + s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, cmdlen, s); datalen = scsi_req_enqueue(s->current_req); s->ti_size = datalen; fifo8_reset(&s->cmdfifo); @@ -939,6 +939,11 @@ static void esp_soft_reset(ESPState *s) esp_hard_reset(s); } +static void esp_bus_reset(ESPState *s) +{ + qbus_reset_all(BUS(&s->bus)); +} + static void parent_esp_reset(ESPState *s, int irq, int level) { if (level) { @@ -1067,6 +1072,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) break; case CMD_BUSRESET: trace_esp_mem_writeb_cmd_bus_reset(val); + esp_bus_reset(s); if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { s->rregs[ESP_RINTR] |= INTR_RST; esp_raise_irq(s); diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index ad5f5e5f39..05a43ec807 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -864,7 +864,7 @@ static void lsi_do_command(LSIState *s) s->current = g_new0(lsi_request, 1); s->current->tag = s->select_tag; s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf, - s->current); + s->dbc, s->current); n = scsi_req_enqueue(s->current->req); if (n) { diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index d5dfb412ba..7082456d65 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1062,7 +1062,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */ info->vpd_page83[0] = 0x7f; megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data)); - cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd); + cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, sizeof(cmdbuf), cmd); if (!cmd->req) { trace_megasas_dcmd_req_alloc_failed(cmd->index, "PD get info std inquiry"); @@ -1080,7 +1080,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun, return MFI_STAT_INVALID_STATUS; } else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) { megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83)); - cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd); + cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, sizeof(cmdbuf), cmd); if (!cmd->req) { trace_megasas_dcmd_req_alloc_failed(cmd->index, "PD get info vpd inquiry"); @@ -1268,7 +1268,7 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, cmd->iov_buf = g_malloc0(dcmd_size); info = cmd->iov_buf; megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83)); - cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd); + cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, sizeof(cdb), cmd); if (!cmd->req) { trace_megasas_dcmd_req_alloc_failed(cmd->index, "LD get info vpd inquiry"); @@ -1748,7 +1748,7 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd, return MFI_STAT_SCSI_DONE_WITH_ERROR; } - cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cmd); + cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cdb_len, cmd); if (!cmd->req) { trace_megasas_scsi_req_alloc_failed( mfi_frame_desc(frame_cmd), target_id, lun_id); @@ -1823,7 +1823,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd) megasas_encode_lba(cdb, lba_start, lba_count, is_write); cmd->req = scsi_req_new(sdev, cmd->index, - lun_id, cdb, cmd); + lun_id, cdb, cdb_len, cmd); if (!cmd->req) { trace_megasas_scsi_req_alloc_failed( mfi_frame_desc(frame_cmd), target_id, lun_id); diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 706cf0df3a..a90c2546f1 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -324,7 +324,8 @@ static int mptsas_process_scsi_io_request(MPTSASState *s, } req->sreq = scsi_req_new(sdev, scsi_io->MsgContext, - scsi_io->LUN[1], scsi_io->CDB, req); + scsi_io->LUN[1], scsi_io->CDB, + scsi_io->CDBLength, req); if (req->sreq->cmd.xfer > scsi_io->DataLength) { goto overrun; diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index b2e2bc3c96..4403717c4a 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -102,15 +102,15 @@ static void scsi_device_unrealize(SCSIDevice *s) } int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, - void *hba_private) + size_t buf_len, void *hba_private) { SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); int rc; assert(cmd->len == 0); - rc = scsi_req_parse_cdb(dev, cmd, buf); + rc = scsi_req_parse_cdb(dev, cmd, buf, buf_len); if (bus->info->parse_cdb) { - rc = bus->info->parse_cdb(dev, cmd, buf, hba_private); + rc = bus->info->parse_cdb(dev, cmd, buf, buf_len, hba_private); } return rc; } @@ -703,7 +703,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, } SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, - uint8_t *buf, void *hba_private) + uint8_t *buf, size_t buf_len, void *hba_private) { SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); const SCSIReqOps *ops; @@ -712,6 +712,11 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, SCSICommand cmd = { .len = 0 }; int ret; + if (buf_len == 0) { + trace_scsi_req_parse_bad(d->id, lun, tag, 0); + goto invalid_opcode; + } + if ((d->unit_attention.key == UNIT_ATTENTION || bus->unit_attention.key == UNIT_ATTENTION) && (buf[0] != INQUIRY && @@ -734,13 +739,14 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, } if (ops != NULL || !sc->parse_cdb) { - ret = scsi_req_parse_cdb(d, &cmd, buf); + ret = scsi_req_parse_cdb(d, &cmd, buf, buf_len); } else { - ret = sc->parse_cdb(d, &cmd, buf, hba_private); + ret = sc->parse_cdb(d, &cmd, buf, buf_len, hba_private); } if (ret != 0) { trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]); +invalid_opcode: req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private); } else { assert(cmd.len != 0); @@ -1308,14 +1314,15 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) } } -int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf) +int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, + size_t buf_len) { int rc; int len; cmd->lba = -1; len = scsi_cdb_length(buf); - if (len < 0) { + if (len < 0 || len > buf_len) { return -1; } @@ -1713,7 +1720,11 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size, qemu_get_buffer(f, buf, sizeof(buf)); qemu_get_be32s(f, &tag); qemu_get_be32s(f, &lun); - req = scsi_req_new(s, tag, lun, buf, NULL); + /* + * A too-short CDB would have been rejected by scsi_req_new, so just use + * SCSI_CMD_BUF_SIZE as the CDB length. + */ + req = scsi_req_new(s, tag, lun, buf, sizeof(buf), NULL); req->retry = (sbyte == 1); if (bus->info->load_request) { req->hba_private = bus->info->load_request(f, req); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index f5cdb9ad4b..399e1787ea 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1591,7 +1591,7 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) int cmd = r->req.cmd.buf[0]; int len = r->req.cmd.xfer; int hdr_len = (cmd == MODE_SELECT ? 4 : 8); - int bd_len; + int bd_len, bs; int pass; if ((r->req.cmd.buf[1] & 0x11) != 0x10) { @@ -1617,9 +1617,19 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) } /* Allow changing the block size */ - if (bd_len && p[6] != (s->qdev.blocksize >> 8)) { - s->qdev.blocksize = p[6] << 8; - trace_scsi_disk_mode_select_set_blocksize(s->qdev.blocksize); + if (bd_len) { + bs = p[5] << 16 | p[6] << 8 | p[7]; + + /* + * Since the existing code only checks/updates bits 8-15 of the block + * size, restrict ourselves to the same requirement for now to ensure + * that a block size set by a block descriptor and then read back by + * a subsequent SCSI command will be the same + */ + if (bs && !(bs & ~0xff00) && bs != s->qdev.blocksize) { + s->qdev.blocksize = bs; + trace_scsi_disk_mode_select_set_blocksize(s->qdev.blocksize); + } } len -= bd_len; @@ -1849,7 +1859,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf); WriteSameCBData *data; uint8_t *buf; - int i; + int i, l; /* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1. */ if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) { @@ -1891,8 +1901,9 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) data->iov.iov_len); qemu_iovec_init_external(&data->qiov, &data->iov, 1); - for (i = 0; i < data->iov.iov_len; i += s->qdev.blocksize) { - memcpy(&buf[i], inbuf, s->qdev.blocksize); + for (i = 0; i < data->iov.iov_len; i += l) { + l = MIN(s->qdev.blocksize, data->iov.iov_len - i); + memcpy(&buf[i], inbuf, l); } scsi_req_ref(&r->req); @@ -3019,14 +3030,15 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, } static int scsi_block_parse_cdb(SCSIDevice *d, SCSICommand *cmd, - uint8_t *buf, void *hba_private) + uint8_t *buf, size_t buf_len, + void *hba_private) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); if (scsi_block_is_passthrough(s, buf)) { - return scsi_bus_parse_cdb(&s->qdev, cmd, buf, hba_private); + return scsi_bus_parse_cdb(&s->qdev, cmd, buf, buf_len, hba_private); } else { - return scsi_req_parse_cdb(&s->qdev, cmd, buf); + return scsi_req_parse_cdb(&s->qdev, cmd, buf, buf_len); } } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index ada24d7486..92cce20a4d 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -147,6 +147,18 @@ static int execute_command(BlockBackend *blk, return 0; } +static uint64_t calculate_max_transfer(SCSIDevice *s) +{ + uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk); + uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk); + + assert(max_transfer); + max_transfer = MIN_NON_ZERO(max_transfer, + max_iov * qemu_real_host_page_size()); + + return max_transfer / s->blocksize; +} + static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len) { uint8_t page, page_idx; @@ -179,12 +191,7 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len) (r->req.cmd.buf[1] & 0x01)) { page = r->req.cmd.buf[2]; if (page == 0xb0) { - uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk); - uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk); - - assert(max_transfer); - max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size()) - / s->blocksize; + uint64_t max_transfer = calculate_max_transfer(s); stl_be_p(&r->buf[8], max_transfer); /* Also take care of the opt xfer len. */ stl_be_p(&r->buf[12], @@ -230,7 +237,7 @@ static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s) uint8_t buf[64]; SCSIBlockLimits bl = { - .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize + .max_io_sectors = calculate_max_transfer(s), }; memset(r->buf, 0, r->buflen); @@ -784,9 +791,10 @@ static Property scsi_generic_properties[] = { }; static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, - uint8_t *buf, void *hba_private) + uint8_t *buf, size_t buf_len, + void *hba_private) { - return scsi_bus_parse_cdb(dev, cmd, buf, hba_private); + return scsi_bus_parse_cdb(dev, cmd, buf, buf_len, hba_private); } static void scsi_generic_class_initfn(ObjectClass *klass, void *data) diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index e320ccaa23..0a8cbf5a4b 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -783,6 +783,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) union srp_iu *srp = &req_iu(req)->srp; SCSIDevice *sdev; int n, lun; + size_t cdb_len = sizeof (srp->cmd.cdb) + (srp->cmd.add_cdb_len & ~3); if ((srp->cmd.lun == 0 || be64_to_cpu(srp->cmd.lun) == SRP_REPORT_LUNS_WLUN) && srp->cmd.cdb[0] == REPORT_LUNS) { @@ -801,7 +802,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) } return 1; } - req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req); + req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, cdb_len, req); n = scsi_req_enqueue(req->sreq); trace_spapr_vscsi_queue_cmd(req->qtag, srp->cmd.cdb[0], diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 3059068175..bdf337a7a2 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -120,7 +120,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) start = false; } - if (vsc->dev.started == start) { + if (vhost_dev_is_started(&vsc->dev) == start) { return; } @@ -147,7 +147,7 @@ static int vhost_scsi_pre_save(void *opaque) /* At this point, backend must be stopped, otherwise * it might keep writing to memory. */ - assert(!vsc->dev.started); + assert(!vhost_dev_is_started(&vsc->dev)); return 0; } diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 1b2f7eed98..bc37317d55 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -49,7 +49,7 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running; - if (vsc->dev.started == start) { + if (vhost_dev_is_started(&vsc->dev) == start) { return; } diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 8bb6e6acfc..20bb91766e 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -136,6 +136,14 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) memory_region_transaction_commit(); + /* + * These fields are visible to the IOThread so we rely on implicit barriers + * in aio_context_acquire() on the write side and aio_notify_accept() on + * the read side. + */ + s->dataplane_starting = false; + s->dataplane_started = true; + aio_context_acquire(s->ctx); virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx); virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx); @@ -143,9 +151,6 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) for (i = 0; i < vs->conf.num_queues; i++) { virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx); } - - s->dataplane_starting = false; - s->dataplane_started = true; aio_context_release(s->ctx); return 0; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 4141dddd51..41f2a56301 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -622,7 +622,8 @@ static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid) } static int virtio_scsi_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, - uint8_t *buf, void *hba_private) + uint8_t *buf, size_t buf_len, + void *hba_private) { VirtIOSCSIReq *req = hba_private; @@ -696,7 +697,7 @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) virtio_scsi_ctx_check(s, d); req->sreq = scsi_req_new(d, req->req.cmd.tag, virtio_scsi_get_lun(req->req.cmd.lun), - req->req.cmd.cdb, req); + req->req.cmd.cdb, vs->cdb_size, req); if (req->sreq->cmd.mode != SCSI_XFER_NONE && (req->sreq->cmd.mode != req->mode || diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 4d9969f3b1..91e2f858ab 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -730,7 +730,7 @@ pvscsi_process_request_descriptor(PVSCSIState *s, r->sg.elemAddr = descr->dataAddr; } - r->sreq = scsi_req_new(d, descr->context, r->lun, descr->cdb, r); + r->sreq = scsi_req_new(d, descr->context, r->lun, descr->cdb, descr->cdbLen, r); if (r->sreq->cmd.mode == SCSI_XFER_FROM_DEV && (descr->flags & PVSCSI_FLAG_CMD_DIR_TODEVICE)) { r->cmp.hostStatus = BTSTAT_BADMSG; diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 60349ee402..51437ca09f 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -111,6 +111,13 @@ static struct { .processor_id = 0, }; +struct type8_instance { + const char *internal_reference, *external_reference; + uint8_t connector_type, port_type; + QTAILQ_ENTRY(type8_instance) next; +}; +static QTAILQ_HEAD(, type8_instance) type8 = QTAILQ_HEAD_INITIALIZER(type8); + static struct { size_t nvalues; char **values; @@ -337,6 +344,29 @@ static const QemuOptDesc qemu_smbios_type4_opts[] = { { /* end of list */ } }; +static const QemuOptDesc qemu_smbios_type8_opts[] = { + { + .name = "internal_reference", + .type = QEMU_OPT_STRING, + .help = "internal reference designator", + }, + { + .name = "external_reference", + .type = QEMU_OPT_STRING, + .help = "external reference designator", + }, + { + .name = "connector_type", + .type = QEMU_OPT_NUMBER, + .help = "connector type", + }, + { + .name = "port_type", + .type = QEMU_OPT_NUMBER, + .help = "port type", + }, +}; + static const QemuOptDesc qemu_smbios_type11_opts[] = { { .name = "value", @@ -718,6 +748,26 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) smbios_type4_count++; } +static void smbios_build_type_8_table(void) +{ + unsigned instance = 0; + struct type8_instance *t8; + + QTAILQ_FOREACH(t8, &type8, next) { + SMBIOS_BUILD_TABLE_PRE(8, T0_BASE + instance, true); + + SMBIOS_TABLE_SET_STR(8, internal_reference_str, t8->internal_reference); + SMBIOS_TABLE_SET_STR(8, external_reference_str, t8->external_reference); + /* most vendors seem to set this to None */ + t->internal_connector_type = 0x0; + t->external_connector_type = t8->connector_type; + t->port_type = t8->port_type; + + SMBIOS_BUILD_TABLE_POST; + instance++; + } +} + static void smbios_build_type_11_table(void) { char count_str[128]; @@ -1030,6 +1080,7 @@ void smbios_get_tables(MachineState *ms, smbios_build_type_4_table(ms, i); } + smbios_build_type_8_table(); smbios_build_type_11_table(); #define MAX_DIMM_SZ (16 * GiB) @@ -1205,13 +1256,15 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) return; } - if (test_bit(header->type, have_fields_bitmap)) { - error_setg(errp, - "can't load type %d struct, fields already specified!", - header->type); - return; + if (header->type <= SMBIOS_MAX_TYPE) { + if (test_bit(header->type, have_fields_bitmap)) { + error_setg(errp, + "can't load type %d struct, fields already specified!", + header->type); + return; + } + set_bit(header->type, have_binfile_bitmap); } - set_bit(header->type, have_binfile_bitmap); if (header->type == 4) { smbios_type4_count++; @@ -1346,6 +1399,18 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) UINT16_MAX); } return; + case 8: + if (!qemu_opts_validate(opts, qemu_smbios_type8_opts, errp)) { + return; + } + struct type8_instance *t; + t = g_new0(struct type8_instance, 1); + save_opt(&t->internal_reference, opts, "internal_reference"); + save_opt(&t->external_reference, opts, "external_reference"); + t->connector_type = qemu_opt_get_number(opts, "connector_type", 0); + t->port_type = qemu_opt_get_number(opts, "port_type", 0); + QTAILQ_INSERT_TAIL(&type8, t, next); + return; case 11: if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, errp)) { return; diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c index d14580b409..94d7da9cc2 100644 --- a/hw/ssi/ibex_spi_host.c +++ b/hw/ssi/ibex_spi_host.c @@ -93,7 +93,7 @@ REG32(ERROR_STATUS, 0x30) FIELD(ERROR_STATUS, CMDINVAL, 3, 1) FIELD(ERROR_STATUS, CSIDINVAL, 4, 1) FIELD(ERROR_STATUS, ACCESSINVAL, 5, 1) -REG32(EVENT_ENABLE, 0x30) +REG32(EVENT_ENABLE, 0x34) FIELD(EVENT_ENABLE, RXFULL, 0, 1) FIELD(EVENT_ENABLE, TXEMPTY, 1, 1) FIELD(EVENT_ENABLE, RXWM, 2, 1) @@ -172,7 +172,7 @@ static void ibex_spi_host_irq(IbexSPIHostState *s) & R_INTR_STATE_SPI_EVENT_MASK; int err_irq = 0, event_irq = 0; - /* Error IRQ enabled and Error IRQ Cleared*/ + /* Error IRQ enabled and Error IRQ Cleared */ if (error_en && !err_pending) { /* Event enabled, Interrupt Test Error */ if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_ERROR_MASK) { @@ -434,7 +434,7 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr, case IBEX_SPI_HOST_TXDATA: /* * This is a hardware `feature` where - * the first word written TXDATA after init is omitted entirely + * the first word written to TXDATA after init is omitted entirely */ if (s->init_status) { s->init_status = false; @@ -487,7 +487,7 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr, break; case IBEX_SPI_HOST_ERROR_STATUS: /* - * Indicates that any errors that have occurred. + * Indicates any errors that have occurred. * When an error occurs, the corresponding bit must be cleared * here before issuing any further commands */ diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c index 8c2ca364da..d8b8e4e1f6 100644 --- a/hw/timer/ibex_timer.c +++ b/hw/timer/ibex_timer.c @@ -60,8 +60,6 @@ static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) static void ibex_timer_update_irqs(IbexTimerState *s) { - CPUState *cs = qemu_get_cpu(0); - RISCVCPU *cpu = RISCV_CPU(cs); uint64_t value = s->timer_compare_lower0 | ((uint64_t)s->timer_compare_upper0 << 32); uint64_t next, diff; @@ -73,9 +71,9 @@ static void ibex_timer_update_irqs(IbexTimerState *s) } /* Update the CPUs mtimecmp */ - cpu->env.timecmp = value; + s->mtimecmp = value; - if (cpu->env.timecmp <= now) { + if (s->mtimecmp <= now) { /* * If the mtimecmp was in the past raise the interrupt now. */ @@ -91,7 +89,7 @@ static void ibex_timer_update_irqs(IbexTimerState *s) qemu_irq_lower(s->m_timer_irq); qemu_set_irq(s->irq, false); - diff = cpu->env.timecmp - now; + diff = s->mtimecmp - now; next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(diff, NANOSECONDS_PER_SECOND, @@ -99,9 +97,9 @@ static void ibex_timer_update_irqs(IbexTimerState *s) if (next < qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { /* We overflowed the timer, just set it as large as we can */ - timer_mod(cpu->env.timer, 0x7FFFFFFFFFFFFFFF); + timer_mod(s->mtimer, 0x7FFFFFFFFFFFFFFF); } else { - timer_mod(cpu->env.timer, next); + timer_mod(s->mtimer, next); } } @@ -120,11 +118,9 @@ static void ibex_timer_reset(DeviceState *dev) { IbexTimerState *s = IBEX_TIMER(dev); - CPUState *cpu = qemu_get_cpu(0); - CPURISCVState *env = cpu->env_ptr; - env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + s->mtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &ibex_timer_cb, s); - env->timecmp = 0; + s->mtimecmp = 0; s->timer_ctrl = 0x00000000; s->timer_cfg0 = 0x00010000; diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 67db594c48..ea930da545 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -26,6 +26,7 @@ #include "sysemu/tpm_backend.h" #include "sysemu/tpm_util.h" #include "sysemu/reset.h" +#include "sysemu/xen.h" #include "tpm_prop.h" #include "tpm_ppi.h" #include "trace.h" @@ -308,7 +309,11 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp) TPM_PPI_ADDR_BASE, OBJECT(s)); } - qemu_register_reset(tpm_crb_reset, dev); + if (xen_enabled()) { + tpm_crb_reset(dev); + } else { + qemu_register_reset(tpm_crb_reset, dev); + } } static void tpm_crb_class_init(ObjectClass *klass, void *data) diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 6c49c16015..ac1adca543 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -91,6 +91,8 @@ enum usbstring_idx { #define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43 #define USB_CDC_GET_ETHERNET_STATISTIC 0x44 +#define USB_CDC_NETWORK_CONNECTION 0x00 + #define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ #define STATUS_BYTECOUNT 16 /* 8 byte header + data */ @@ -640,6 +642,8 @@ struct USBNetState { uint16_t filter; uint32_t vendorid; + uint16_t connection; + unsigned int out_ptr; uint8_t out_buf[2048]; @@ -647,6 +651,7 @@ struct USBNetState { uint8_t in_buf[2048]; USBEndpoint *intr; + USBEndpoint *bulk_in; char usbstring_mac[13]; NICState *nic; @@ -1121,6 +1126,12 @@ static void usb_net_handle_control(USBDevice *dev, USBPacket *p, #endif break; + case ClassInterfaceOutRequest | USB_CDC_SET_ETHERNET_PACKET_FILTER: + if (is_rndis(s)) { + goto fail; + } + break; + default: fail: fprintf(stderr, "usbnet: failed control transaction: " @@ -1133,18 +1144,28 @@ static void usb_net_handle_control(USBDevice *dev, USBPacket *p, static void usb_net_handle_statusin(USBNetState *s, USBPacket *p) { - le32 buf[2]; + le32 rbuf[2]; + uint16_t ebuf[4]; if (p->iov.size < 8) { p->status = USB_RET_STALL; return; } - buf[0] = cpu_to_le32(1); - buf[1] = cpu_to_le32(0); - usb_packet_copy(p, buf, 8); - if (!s->rndis_resp.tqh_first) { - p->status = USB_RET_NAK; + if (is_rndis(s)) { + rbuf[0] = cpu_to_le32(1); + rbuf[1] = cpu_to_le32(0); + usb_packet_copy(p, rbuf, 8); + if (!s->rndis_resp.tqh_first) { + p->status = USB_RET_NAK; + } + } else { + ebuf[0] = + cpu_to_be16(ClassInterfaceRequest | USB_CDC_NETWORK_CONNECTION); + ebuf[1] = cpu_to_le16(s->connection); + ebuf[2] = cpu_to_le16(1); + ebuf[3] = cpu_to_le16(0); + usb_packet_copy(p, ebuf, 8); } #ifdef TRAFFIC_DEBUG @@ -1204,7 +1225,7 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) s->out_ptr += sz; if (!is_rndis(s)) { - if (p->iov.size < 64) { + if (p->iov.size % 64 || p->iov.size == 0) { qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr); s->out_ptr = 0; } @@ -1317,6 +1338,7 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz memcpy(in_buf, buf, size); s->in_len = total_size; s->in_ptr = 0; + usb_wakeup(s->bulk_in, 0); return size; } @@ -1358,7 +1380,9 @@ static void usb_net_realize(USBDevice *dev, Error **errp) s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */; s->filter = 0; s->vendorid = 0x1234; + s->connection = 1; /* Connected */ s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); + s->bulk_in = usb_ep_get(dev, USB_TOKEN_IN, 2); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index dca62d544f..e3bcffb3e0 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -177,6 +177,37 @@ static const USBDesc desc = { .str = desc_strings, }; +static void usb_msd_packet_complete(MSDState *s) +{ + USBPacket *p = s->packet; + + /* + * Set s->packet to NULL before calling usb_packet_complete + * because another request may be issued before + * usb_packet_complete returns. + */ + trace_usb_msd_packet_complete(); + s->packet = NULL; + usb_packet_complete(&s->dev, p); +} + +static void usb_msd_fatal_error(MSDState *s) +{ + trace_usb_msd_fatal_error(); + + if (s->packet) { + s->packet->status = USB_RET_STALL; + usb_msd_packet_complete(s); + } + + /* + * Guest messed up up device state with illegal requests. Go + * ignore any requests until the guests resets the device (and + * brings it into a known state that way). + */ + s->needs_reset = true; +} + static void usb_msd_copy_data(MSDState *s, USBPacket *p) { uint32_t len; @@ -208,24 +239,16 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p) memset(&s->csw, 0, sizeof(s->csw)); } -static void usb_msd_packet_complete(MSDState *s) -{ - USBPacket *p = s->packet; - - /* Set s->packet to NULL before calling usb_packet_complete - because another request may be issued before - usb_packet_complete returns. */ - trace_usb_msd_packet_complete(); - s->packet = NULL; - usb_packet_complete(&s->dev, p); -} - void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); USBPacket *p = s->packet; - assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); + if ((s->mode == USB_MSDM_DATAOUT) != (req->cmd.mode == SCSI_XFER_TO_DEV)) { + usb_msd_fatal_error(s); + return; + } + s->scsi_len = len; s->scsi_off = 0; if (p) { @@ -315,6 +338,8 @@ void usb_msd_handle_reset(USBDevice *dev) memset(&s->csw, 0, sizeof(s->csw)); s->mode = USB_MSDM_CBW; + + s->needs_reset = false; } static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, @@ -380,6 +405,11 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) SCSIDevice *scsi_dev; uint32_t len; + if (s->needs_reset) { + p->status = USB_RET_STALL; + return; + } + switch (p->pid) { case USB_TOKEN_OUT: if (devep != 2) @@ -415,7 +445,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) cbw.cmd_len, s->data_len); assert(le32_to_cpu(s->csw.residue) == 0); s->scsi_len = 0; - s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL); + s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, cbw.cmd_len, NULL); if (s->commandlog) { scsi_req_print(s->req); } diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index c9f295e7e4..5192b062d6 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -71,7 +71,7 @@ typedef struct { uint8_t reserved_2; uint64_t lun; uint8_t cdb[16]; - uint8_t add_cdb[1]; /* not supported by QEMU */ + uint8_t add_cdb[1]; } QEMU_PACKED uas_iu_command; typedef struct { @@ -699,6 +699,7 @@ static void usb_uas_command(UASDevice *uas, uas_iu *iu) UASRequest *req; uint32_t len; uint16_t tag = be16_to_cpu(iu->hdr.tag); + size_t cdb_len = sizeof(iu->command.cdb) + iu->command.add_cdb_length; if (iu->command.add_cdb_length > 0) { qemu_log_mask(LOG_UNIMP, "additional adb length not yet supported\n"); @@ -729,7 +730,7 @@ static void usb_uas_command(UASDevice *uas, uas_iu *iu) req->req = scsi_req_new(req->dev, req->tag, usb_uas_get_lun(req->lun), - iu->command.cdb, req); + iu->command.cdb, cdb_len, req); if (uas->requestlog) { scsi_req_print(req->req); } diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 895b29fb86..9d68036d23 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -571,6 +571,11 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed) addr = ed->head & OHCI_DPTR_MASK; + if (addr == 0) { + ohci_die(ohci); + return 1; + } + if (ohci_read_iso_td(ohci, addr, &iso_td)) { trace_usb_ohci_iso_td_read_failed(addr); ohci_die(ohci); @@ -805,13 +810,14 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed) return 1; } +#define HEX_CHAR_PER_LINE 16 + static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) { bool print16; bool printall; - const int width = 16; int i; - char tmp[3 * width + 1]; + char tmp[3 * HEX_CHAR_PER_LINE + 1]; char *p = tmp; print16 = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_SHORT); @@ -822,7 +828,7 @@ static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) } for (i = 0; ; i++) { - if (i && (!(i % width) || (i == len))) { + if (i && (!(i % HEX_CHAR_PER_LINE) || (i == len))) { if (!printall) { trace_usb_ohci_td_pkt_short(msg, tmp); break; @@ -858,6 +864,11 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) int completion; addr = ed->head & OHCI_DPTR_MASK; + if (addr == 0) { + ohci_die(ohci); + return 1; + } + /* See if this TD has already been submitted to the device. */ completion = (addr == ohci->async_td); if (completion && !ohci->async_complete) { diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 296cc6c8e6..8299f35e66 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" +#include "qemu/log.h" #include "qemu/module.h" #include "qemu/queue.h" #include "migration/vmstate.h" @@ -462,6 +463,12 @@ static void xhci_mfwrap_timer(void *opaque) xhci_mfwrap_update(xhci); } +static void xhci_die(XHCIState *xhci) +{ + xhci->usbsts |= USBSTS_HCE; + DPRINTF("xhci: asserted controller error\n"); +} + static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high) { if (sizeof(dma_addr_t) == 4) { @@ -487,7 +494,14 @@ static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr, assert((len % sizeof(uint32_t)) == 0); - dma_memory_read(xhci->as, addr, buf, len, MEMTXATTRS_UNSPECIFIED); + if (dma_memory_read(xhci->as, addr, buf, len, + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", + __func__); + memset(buf, 0xff, len); + xhci_die(xhci); + return; + } for (i = 0; i < (len / sizeof(uint32_t)); i++) { buf[i] = le32_to_cpu(buf[i]); @@ -495,7 +509,7 @@ static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr, } static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr, - uint32_t *buf, size_t len) + const uint32_t *buf, size_t len) { int i; uint32_t tmp[5]; @@ -507,7 +521,13 @@ static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr, for (i = 0; i < n; i++) { tmp[i] = cpu_to_le32(buf[i]); } - dma_memory_write(xhci->as, addr, tmp, len, MEMTXATTRS_UNSPECIFIED); + if (dma_memory_write(xhci->as, addr, tmp, len, + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", + __func__); + xhci_die(xhci); + return; + } } static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) @@ -592,12 +612,6 @@ static inline int xhci_running(XHCIState *xhci) return !(xhci->usbsts & USBSTS_HCH); } -static void xhci_die(XHCIState *xhci) -{ - xhci->usbsts |= USBSTS_HCE; - DPRINTF("xhci: asserted controller error\n"); -} - static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) { XHCIInterrupter *intr = &xhci->intr[v]; @@ -618,7 +632,12 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) ev_trb.status, ev_trb.control); addr = intr->er_start + TRB_SIZE*intr->er_ep_idx; - dma_memory_write(xhci->as, addr, &ev_trb, TRB_SIZE, MEMTXATTRS_UNSPECIFIED); + if (dma_memory_write(xhci->as, addr, &ev_trb, TRB_SIZE, + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", + __func__); + xhci_die(xhci); + } intr->er_ep_idx++; if (intr->er_ep_idx >= intr->er_size) { @@ -679,8 +698,12 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, while (1) { TRBType type; - dma_memory_read(xhci->as, ring->dequeue, trb, TRB_SIZE, - MEMTXATTRS_UNSPECIFIED); + if (dma_memory_read(xhci->as, ring->dequeue, trb, TRB_SIZE, + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", + __func__); + return 0; + } trb->addr = ring->dequeue; trb->ccs = ring->ccs; le64_to_cpus(&trb->parameter); @@ -725,10 +748,14 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) bool control_td_set = 0; uint32_t link_cnt = 0; - while (1) { + do { TRBType type; - dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE, - MEMTXATTRS_UNSPECIFIED); + if (dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE, + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", + __func__); + return -1; + } le64_to_cpus(&trb.parameter); le32_to_cpus(&trb.status); le32_to_cpus(&trb.control); @@ -762,7 +789,17 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) if (!control_td_set && !(trb.control & TRB_TR_CH)) { return length; } - } + + /* + * According to the xHCI spec, Transfer Ring segments should have + * a maximum size of 64 kB (see chapter "6 Data Structures") + */ + } while (length < TRB_LINK_LIMIT * 65536 / TRB_SIZE); + + qemu_log_mask(LOG_GUEST_ERROR, "%s: exceeded maximum tranfer ring size!\n", + __func__); + + return -1; } static void xhci_er_reset(XHCIState *xhci, int v) @@ -783,8 +820,14 @@ static void xhci_er_reset(XHCIState *xhci, int v) xhci_die(xhci); return; } - dma_memory_read(xhci->as, erstba, &seg, sizeof(seg), - MEMTXATTRS_UNSPECIFIED); + if (dma_memory_read(xhci->as, erstba, &seg, sizeof(seg), + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", + __func__); + xhci_die(xhci); + return; + } + le32_to_cpus(&seg.addr_low); le32_to_cpus(&seg.addr_high); le32_to_cpus(&seg.size); @@ -977,7 +1020,9 @@ static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx, } sctx = epctx->pstreams + streamid; } else { - FIXME("secondary streams not implemented yet"); + fprintf(stderr, "xhci: FIXME: secondary streams not implemented yet"); + *cc_error = CC_INVALID_STREAM_TYPE_ERROR; + return NULL; } if (sctx->sct == -1) { @@ -2400,8 +2445,12 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) /* TODO: actually implement real values here */ bw_ctx[0] = 0; memset(&bw_ctx[1], 80, xhci->numports); /* 80% */ - dma_memory_write(xhci->as, ctx, bw_ctx, sizeof(bw_ctx), - MEMTXATTRS_UNSPECIFIED); + if (dma_memory_write(xhci->as, ctx, bw_ctx, sizeof(bw_ctx), + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory write failed!\n", + __func__); + return CC_TRB_ERROR; + } return CC_SUCCESS; } diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 914ca71668..b65269892c 100644 --- a/hw/usb/trace-events +++ b/hw/usb/trace-events @@ -263,6 +263,7 @@ usb_msd_packet_complete(void) "" usb_msd_cmd_submit(unsigned lun, unsigned tag, unsigned flags, unsigned len, unsigned data_len) "lun %u, tag 0x%x, flags 0x%08x, len %d, data-len %d" usb_msd_cmd_complete(unsigned status, unsigned tag) "status %d, tag 0x%x" usb_msd_cmd_cancel(unsigned tag) "tag 0x%x" +usb_msd_fatal_error(void) "" # dev-uas.c usb_uas_reset(int addr) "dev %d" diff --git a/hw/usb/u2f.h b/hw/usb/u2f.h index db30f3586b..a408a82927 100644 --- a/hw/usb/u2f.h +++ b/hw/usb/u2f.h @@ -74,7 +74,7 @@ typedef struct U2FKeyState { /* * API to be used by the U2F key device variants (i.e. hw/u2f-*.c) - * to interact with the the U2F key base device (i.e. hw/u2f.c) + * to interact with the U2F key base device (i.e. hw/u2f.c) */ void u2f_send_to_guest(U2FKeyState *key, const uint8_t packet[U2FHID_PACKET_SIZE]); diff --git a/hw/vfio/common.c b/hw/vfio/common.c index ace9562a9b..6b5d8c0bf6 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -2111,29 +2111,31 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, { struct vfio_iommu_type1_info *info; - /* - * FIXME: This assumes that a Type1 IOMMU can map any 64-bit - * IOVA whatsoever. That's not actually true, but the current - * kernel interface doesn't tell us what it can map, and the - * existing Type1 IOMMUs generally support any IOVA we're - * going to actually try in practice. - */ ret = vfio_get_iommu_info(container, &info); - - if (ret || !(info->flags & VFIO_IOMMU_INFO_PGSIZES)) { - /* Assume 4k IOVA page size */ - info->iova_pgsizes = 4096; + if (ret) { + error_setg_errno(errp, -ret, "Failed to get VFIO IOMMU info"); + goto enable_discards_exit; } - vfio_host_win_add(container, 0, (hwaddr)-1, info->iova_pgsizes); - container->pgsizes = info->iova_pgsizes; - /* The default in the kernel ("dma_entry_limit") is 65535. */ - container->dma_max_mappings = 65535; - if (!ret) { - vfio_get_info_dma_avail(info, &container->dma_max_mappings); - vfio_get_iommu_info_migration(container, info); + if (info->flags & VFIO_IOMMU_INFO_PGSIZES) { + container->pgsizes = info->iova_pgsizes; + } else { + container->pgsizes = qemu_real_host_page_size(); } + + if (!vfio_get_info_dma_avail(info, &container->dma_max_mappings)) { + container->dma_max_mappings = 65535; + } + vfio_get_iommu_info_migration(container, info); g_free(info); + + /* + * FIXME: We should parse VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE + * information to get the actual window extent rather than assume + * a 64-bit IOVA address space. + */ + vfio_host_win_add(container, 0, (hwaddr)-1, container->pgsizes); + break; } case VFIO_SPAPR_TCE_v2_IOMMU: diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index a6ad1f8945..3de4252111 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -806,6 +806,8 @@ static int vfio_migration_init(VFIODevice *vbasedev, } vbasedev->migration = g_new0(VFIOMigration, 1); + vbasedev->migration->device_state = VFIO_DEVICE_STATE_RUNNING; + vbasedev->migration->vm_running = runstate_is_running(); ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, info->index, "migration"); diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index e9ecae1f50..cbfd8c7173 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -80,3 +80,8 @@ config VHOST_USER_FS bool default y depends on VIRTIO && VHOST_USER + +config VHOST_USER_GPIO + bool + default y + depends on VIRTIO && VHOST_USER diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index 7e8877fd64..dfed1e7af5 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -29,6 +29,8 @@ virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) +virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-user-gpio.c')) +virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_GPIO'], if_true: files('vhost-user-gpio-pci.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) @@ -60,4 +62,6 @@ virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss) specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: virtio_ss) softmmu_ss.add_all(when: 'CONFIG_VIRTIO', if_true: softmmu_virtio_ss) softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c')) +softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c')) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) +softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('virtio-stub.c')) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 20af2e7ebd..820dadc26c 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -8,6 +8,10 @@ vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size, vhost_section(const char *name) "%s" vhost_reject_section(const char *name, int d) "%s:%d" vhost_iotlb_miss(void *dev, int step) "%p step %d" +vhost_dev_cleanup(void *dev) "%p" +vhost_dev_start(void *dev, const char *name) "%p:%s" +vhost_dev_stop(void *dev, const char *name) "%p:%s" + # vhost-user.c vhost_user_postcopy_end_entry(void) "" @@ -140,3 +144,8 @@ virtio_mem_state_response(uint16_t state) "state=%" PRIu16 virtio_pmem_flush_request(void) "flush request" virtio_pmem_response(void) "flush response" virtio_pmem_flush_done(int type) "fsync return=%d" + +# virtio-gpio.c +virtio_gpio_start(void) "start" +virtio_gpio_stop(void) "stop" +virtio_gpio_set_status(uint8_t status) "0x%x" diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c index 67bf6d57ab..3d03395a77 100644 --- a/hw/virtio/vhost-iova-tree.c +++ b/hw/virtio/vhost-iova-tree.c @@ -104,7 +104,7 @@ int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map) * @iova_tree: The vhost iova tree * @map: The map to remove */ -void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map) +void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map) { iova_tree_remove(iova_tree->iova_taddr_map, map); } diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h index 6a4f24e0f9..4adfd79ff0 100644 --- a/hw/virtio/vhost-iova-tree.h +++ b/hw/virtio/vhost-iova-tree.h @@ -22,6 +22,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete); const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree, const DMAMap *map); int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map); -void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map); +void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map); #endif diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index e4956728dd..596d4434d2 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -233,9 +233,6 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq) /** * Add an element to a SVQ. * - * The caller must check that there is enough slots for the new element. It - * takes ownership of the element: In case of failure not ENOSPC, it is free. - * * Return -EINVAL if element is invalid, -ENOSPC if dev queue is full */ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, @@ -252,7 +249,6 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, ok = vhost_svq_add_split(svq, out_sg, out_num, in_sg, in_num, &qemu_head); if (unlikely(!ok)) { - g_free(elem); return -EINVAL; } @@ -293,7 +289,7 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) virtio_queue_set_notification(svq->vq, false); while (true) { - VirtQueueElement *elem; + g_autofree VirtQueueElement *elem = NULL; int r; if (svq->next_guest_avail_elem) { @@ -324,12 +320,14 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) * queue the current guest descriptor and ignore kicks * until some elements are used. */ - svq->next_guest_avail_elem = elem; + svq->next_guest_avail_elem = g_steal_pointer(&elem); } /* VQ is full or broken, just return and ignore kicks */ return; } + /* elem belongs to SVQ or external caller now */ + elem = NULL; } virtio_queue_set_notification(svq->vq, true); @@ -416,7 +414,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, return NULL; } - if (unlikely(!svq->desc_state[used_elem.id].elem)) { + if (unlikely(!svq->desc_state[used_elem.id].ndescs)) { qemu_log_mask(LOG_GUEST_ERROR, "Device %s says index %u is used, but it was not available", svq->vdev->name, used_elem.id); @@ -424,6 +422,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, } num = svq->desc_state[used_elem.id].ndescs; + svq->desc_state[used_elem.id].ndescs = 0; last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); svq->desc_next[last_used_chain] = svq->free_head; svq->free_head = used_elem.id; @@ -500,20 +499,20 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq, size_t vhost_svq_poll(VhostShadowVirtqueue *svq) { int64_t start_us = g_get_monotonic_time(); + uint32_t len; + do { - uint32_t len; - VirtQueueElement *elem = vhost_svq_get_buf(svq, &len); - if (elem) { - return len; + if (vhost_svq_more_used(svq)) { + break; } if (unlikely(g_get_monotonic_time() - start_us > 10e6)) { return 0; } - - /* Make sure we read new used_idx */ - smp_rmb(); } while (true); + + vhost_svq_get_buf(svq, &len); + return len; } /** @@ -602,13 +601,13 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) event_notifier_set_handler(svq_kick, NULL); } + event_notifier_init_fd(svq_kick, svq_kick_fd); /* * event_notifier_set_handler already checks for guest's notifications if * they arrive at the new file descriptor in the switch, so there is no * need to explicitly check for them. */ if (poll_start) { - event_notifier_init_fd(svq_kick, svq_kick_fd); event_notifier_set(svq_kick); event_notifier_set_handler(svq_kick, vhost_handle_guest_kick_notifier); } @@ -655,7 +654,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, */ void vhost_svq_stop(VhostShadowVirtqueue *svq) { - event_notifier_set_handler(&svq->svq_kick, NULL); + vhost_svq_set_svq_kick_fd(svq, VHOST_FILE_UNBIND); g_autofree VirtQueueElement *next_avail_elem = NULL; if (!svq->vq) { diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index e513e4fdda..ad0f91c607 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -20,6 +20,7 @@ #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" #include "qemu/error-report.h" +#include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user-fs.h" #include "monitor/monitor.h" #include "sysemu/sysemu.h" @@ -122,13 +123,9 @@ static void vuf_stop(VirtIODevice *vdev) static void vuf_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserFS *fs = VHOST_USER_FS(vdev); - bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + bool should_start = virtio_device_started(vdev, status); - if (!vdev->vm_running) { - should_start = false; - } - - if (fs->vhost_dev.started == should_start) { + if (vhost_dev_is_started(&fs->vhost_dev) == should_start) { return; } diff --git a/hw/virtio/vhost-user-gpio-pci.c b/hw/virtio/vhost-user-gpio-pci.c new file mode 100644 index 0000000000..b3028a24a1 --- /dev/null +++ b/hw/virtio/vhost-user-gpio-pci.c @@ -0,0 +1,69 @@ +/* + * Vhost-user gpio virtio device PCI glue + * + * Copyright (c) 2022 Viresh Kumar + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/vhost-user-gpio.h" +#include "hw/virtio/virtio-pci.h" + +struct VHostUserGPIOPCI { + VirtIOPCIProxy parent_obj; + VHostUserGPIO vdev; +}; + +typedef struct VHostUserGPIOPCI VHostUserGPIOPCI; + +#define TYPE_VHOST_USER_GPIO_PCI "vhost-user-gpio-pci-base" + +DECLARE_INSTANCE_CHECKER(VHostUserGPIOPCI, VHOST_USER_GPIO_PCI, + TYPE_VHOST_USER_GPIO_PCI) + +static void vhost_user_gpio_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserGPIOPCI *dev = VHOST_USER_GPIO_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + vpci_dev->nvectors = 1; + qdev_realize(vdev, BUS(&vpci_dev->bus), errp); +} + +static void vhost_user_gpio_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_user_gpio_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */ + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_user_gpio_pci_instance_init(Object *obj) +{ + VHostUserGPIOPCI *dev = VHOST_USER_GPIO_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_GPIO); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_gpio_pci_info = { + .base_name = TYPE_VHOST_USER_GPIO_PCI, + .non_transitional_name = "vhost-user-gpio-pci", + .instance_size = sizeof(VHostUserGPIOPCI), + .instance_init = vhost_user_gpio_pci_instance_init, + .class_init = vhost_user_gpio_pci_class_init, +}; + +static void vhost_user_gpio_pci_register(void) +{ + virtio_pci_types_register(&vhost_user_gpio_pci_info); +} + +type_init(vhost_user_gpio_pci_register); diff --git a/hw/virtio/vhost-user-gpio.c b/hw/virtio/vhost-user-gpio.c new file mode 100644 index 0000000000..8b40fe450c --- /dev/null +++ b/hw/virtio/vhost-user-gpio.c @@ -0,0 +1,411 @@ +/* + * Vhost-user GPIO virtio device + * + * Copyright (c) 2022 Viresh Kumar + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/vhost-user-gpio.h" +#include "qemu/error-report.h" +#include "standard-headers/linux/virtio_ids.h" +#include "trace.h" + +#define REALIZE_CONNECTION_RETRIES 3 + +/* Features required from VirtIO */ +static const int feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_GPIO_F_IRQ, + VHOST_INVALID_FEATURE_BIT +}; + +static void vu_gpio_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + + memcpy(config, &gpio->config, sizeof(gpio->config)); +} + +static int vu_gpio_config_notifier(struct vhost_dev *dev) +{ + VHostUserGPIO *gpio = VHOST_USER_GPIO(dev->vdev); + + memcpy(dev->vdev->config, &gpio->config, sizeof(gpio->config)); + virtio_notify_config(dev->vdev); + + return 0; +} + +const VhostDevConfigOps gpio_ops = { + .vhost_dev_config_notifier = vu_gpio_config_notifier, +}; + +static int vu_gpio_start(VirtIODevice *vdev) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + struct vhost_dev *vhost_dev = &gpio->vhost_dev; + int ret, i; + + if (!k->set_guest_notifiers) { + error_report("binding does not support guest notifiers"); + return -ENOSYS; + } + + ret = vhost_dev_enable_notifiers(vhost_dev, vdev); + if (ret < 0) { + error_report("Error enabling host notifiers: %d", ret); + return ret; + } + + ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, true); + if (ret < 0) { + error_report("Error binding guest notifier: %d", ret); + goto err_host_notifiers; + } + + /* + * Before we start up we need to ensure we have the final feature + * set needed for the vhost configuration. The backend may also + * apply backend_features when the feature set is sent. + */ + vhost_ack_features(&gpio->vhost_dev, feature_bits, vdev->guest_features); + + ret = vhost_dev_start(&gpio->vhost_dev, vdev); + if (ret < 0) { + error_report("Error starting vhost-user-gpio: %d", ret); + goto err_guest_notifiers; + } + + /* + * guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < gpio->vhost_dev.nvqs; i++) { + vhost_virtqueue_mask(&gpio->vhost_dev, vdev, i, false); + } + + /* + * As we must have VHOST_USER_F_PROTOCOL_FEATURES (because + * VHOST_USER_GET_CONFIG requires it) we need to explicitly enable + * the vrings. + */ + g_assert(vhost_dev->vhost_ops && + vhost_dev->vhost_ops->vhost_set_vring_enable); + ret = vhost_dev->vhost_ops->vhost_set_vring_enable(vhost_dev, true); + if (ret == 0) { + return 0; + } + + error_report("Failed to start vrings for vhost-user-gpio: %d", ret); + +err_guest_notifiers: + k->set_guest_notifiers(qbus->parent, gpio->vhost_dev.nvqs, false); +err_host_notifiers: + vhost_dev_disable_notifiers(&gpio->vhost_dev, vdev); + + return ret; +} + +static void vu_gpio_stop(VirtIODevice *vdev) +{ + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + struct vhost_dev *vhost_dev = &gpio->vhost_dev; + int ret; + + if (!k->set_guest_notifiers) { + return; + } + + /* + * We can call vu_gpio_stop multiple times, for example from + * vm_state_notify and the final object finalisation. Check we + * aren't already stopped before doing so. + */ + if (!vhost_dev_is_started(vhost_dev)) { + return; + } + + vhost_dev_stop(vhost_dev, vdev); + + ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + return; + } + + vhost_dev_disable_notifiers(vhost_dev, vdev); +} + +static void vu_gpio_set_status(VirtIODevice *vdev, uint8_t status) +{ + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + bool should_start = virtio_device_started(vdev, status); + + trace_virtio_gpio_set_status(status); + + if (!gpio->connected) { + return; + } + + if (vhost_dev_is_started(&gpio->vhost_dev) == should_start) { + return; + } + + if (should_start) { + if (vu_gpio_start(vdev)) { + qemu_chr_fe_disconnect(&gpio->chardev); + } + } else { + vu_gpio_stop(vdev); + } +} + +static uint64_t vu_gpio_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) +{ + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + + return vhost_get_features(&gpio->vhost_dev, feature_bits, features); +} + +static void vu_gpio_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ +} + +static void vu_gpio_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) +{ + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + + vhost_virtqueue_mask(&gpio->vhost_dev, vdev, idx, mask); +} + +static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserGPIO *gpio) +{ + virtio_delete_queue(gpio->command_vq); + virtio_delete_queue(gpio->interrupt_vq); + g_free(gpio->vhost_dev.vqs); + gpio->vhost_dev.vqs = NULL; + virtio_cleanup(vdev); + vhost_user_cleanup(&gpio->vhost_user); +} + +static int vu_gpio_connect(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + struct vhost_dev *vhost_dev = &gpio->vhost_dev; + int ret; + + if (gpio->connected) { + return 0; + } + gpio->connected = true; + + vhost_dev_set_config_notifier(vhost_dev, &gpio_ops); + gpio->vhost_user.supports_config = true; + + ret = vhost_dev_init(vhost_dev, &gpio->vhost_user, + VHOST_BACKEND_TYPE_USER, 0, errp); + if (ret < 0) { + return ret; + } + + /* restore vhost state */ + if (virtio_device_started(vdev, vdev->status)) { + vu_gpio_start(vdev); + } + + return 0; +} + +static void vu_gpio_disconnect(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + + if (!gpio->connected) { + return; + } + gpio->connected = false; + + vu_gpio_stop(vdev); + vhost_dev_cleanup(&gpio->vhost_dev); +} + +static void vu_gpio_event(void *opaque, QEMUChrEvent event) +{ + DeviceState *dev = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); + Error *local_err = NULL; + + switch (event) { + case CHR_EVENT_OPENED: + if (vu_gpio_connect(dev, &local_err) < 0) { + qemu_chr_fe_disconnect(&gpio->chardev); + return; + } + break; + case CHR_EVENT_CLOSED: + vu_gpio_disconnect(dev); + break; + case CHR_EVENT_BREAK: + case CHR_EVENT_MUX_IN: + case CHR_EVENT_MUX_OUT: + /* Ignore */ + break; + } +} + +static int vu_gpio_realize_connect(VHostUserGPIO *gpio, Error **errp) +{ + VirtIODevice *vdev = &gpio->parent_obj; + DeviceState *dev = &vdev->parent_obj; + struct vhost_dev *vhost_dev = &gpio->vhost_dev; + int ret; + + ret = qemu_chr_fe_wait_connected(&gpio->chardev, errp); + if (ret < 0) { + return ret; + } + + /* + * vu_gpio_connect() may have already connected (via the event + * callback) in which case it will just report success. + */ + ret = vu_gpio_connect(dev, errp); + if (ret < 0) { + qemu_chr_fe_disconnect(&gpio->chardev); + return ret; + } + g_assert(gpio->connected); + + ret = vhost_dev_get_config(vhost_dev, (uint8_t *)&gpio->config, + sizeof(gpio->config), errp); + + if (ret < 0) { + error_report("vhost-user-gpio: get config failed"); + + qemu_chr_fe_disconnect(&gpio->chardev); + vhost_dev_cleanup(vhost_dev); + return ret; + } + + return 0; +} + +static void vu_gpio_device_realize(DeviceState *dev, Error **errp) +{ + ERRP_GUARD(); + + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserGPIO *gpio = VHOST_USER_GPIO(dev); + int retries, ret; + + if (!gpio->chardev.chr) { + error_setg(errp, "vhost-user-gpio: chardev is mandatory"); + return; + } + + if (!vhost_user_init(&gpio->vhost_user, &gpio->chardev, errp)) { + return; + } + + virtio_init(vdev, VIRTIO_ID_GPIO, sizeof(gpio->config)); + + gpio->vhost_dev.nvqs = 2; + gpio->command_vq = virtio_add_queue(vdev, 256, vu_gpio_handle_output); + gpio->interrupt_vq = virtio_add_queue(vdev, 256, vu_gpio_handle_output); + gpio->vhost_dev.vqs = g_new0(struct vhost_virtqueue, gpio->vhost_dev.nvqs); + + gpio->connected = false; + + qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, vu_gpio_event, NULL, + dev, NULL, true); + + retries = REALIZE_CONNECTION_RETRIES; + g_assert(!*errp); + do { + if (*errp) { + error_prepend(errp, "Reconnecting after error: "); + error_report_err(*errp); + *errp = NULL; + } + ret = vu_gpio_realize_connect(gpio, errp); + } while (ret < 0 && retries--); + + if (ret < 0) { + do_vhost_user_cleanup(vdev, gpio); + } + + return; +} + +static void vu_gpio_device_unrealize(DeviceState *dev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserGPIO *gpio = VHOST_USER_GPIO(dev); + + vu_gpio_set_status(vdev, 0); + qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, NULL, NULL, NULL, NULL, + false); + vhost_dev_cleanup(&gpio->vhost_dev); + do_vhost_user_cleanup(vdev, gpio); +} + +static const VMStateDescription vu_gpio_vmstate = { + .name = "vhost-user-gpio", + .unmigratable = 1, +}; + +static Property vu_gpio_properties[] = { + DEFINE_PROP_CHR("chardev", VHostUserGPIO, chardev), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vu_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + device_class_set_props(dc, vu_gpio_properties); + dc->vmsd = &vu_gpio_vmstate; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + vdc->realize = vu_gpio_device_realize; + vdc->unrealize = vu_gpio_device_unrealize; + vdc->get_features = vu_gpio_get_features; + vdc->get_config = vu_gpio_get_config; + vdc->set_status = vu_gpio_set_status; + vdc->guest_notifier_mask = vu_gpio_guest_notifier_mask; +} + +static const TypeInfo vu_gpio_info = { + .name = TYPE_VHOST_USER_GPIO, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VHostUserGPIO), + .class_init = vu_gpio_class_init, +}; + +static void vu_gpio_register_types(void) +{ + type_register_static(&vu_gpio_info); +} + +type_init(vu_gpio_register_types) diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c index 6020eee093..bc58b6c0d1 100644 --- a/hw/virtio/vhost-user-i2c.c +++ b/hw/virtio/vhost-user-i2c.c @@ -93,13 +93,9 @@ static void vu_i2c_stop(VirtIODevice *vdev) static void vu_i2c_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserI2C *i2c = VHOST_USER_I2C(vdev); - bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + bool should_start = virtio_device_started(vdev, status); - if (!vdev->vm_running) { - should_start = false; - } - - if (i2c->vhost_dev.started == should_start) { + if (vhost_dev_is_started(&i2c->vhost_dev) == should_start) { return; } @@ -178,7 +174,7 @@ static void vu_i2c_disconnect(DeviceState *dev) } i2c->connected = false; - if (i2c->vhost_dev.started) { + if (vhost_dev_is_started(&i2c->vhost_dev)) { vu_i2c_stop(vdev); } } diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c index 3a7bf8e32d..bc1f36c5ac 100644 --- a/hw/virtio/vhost-user-rng.c +++ b/hw/virtio/vhost-user-rng.c @@ -90,13 +90,9 @@ static void vu_rng_stop(VirtIODevice *vdev) static void vu_rng_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserRNG *rng = VHOST_USER_RNG(vdev); - bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + bool should_start = virtio_device_started(vdev, status); - if (!vdev->vm_running) { - should_start = false; - } - - if (rng->vhost_dev.started == should_start) { + if (vhost_dev_is_started(&rng->vhost_dev) == should_start) { return; } @@ -164,7 +160,7 @@ static void vu_rng_disconnect(DeviceState *dev) rng->connected = false; - if (rng->vhost_dev.started) { + if (vhost_dev_is_started(&rng->vhost_dev)) { vu_rng_stop(vdev); } } diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c index 0f8ff99f85..7b67e29d83 100644 --- a/hw/virtio/vhost-user-vsock.c +++ b/hw/virtio/vhost-user-vsock.c @@ -55,13 +55,9 @@ const VhostDevConfigOps vsock_ops = { static void vuv_set_status(VirtIODevice *vdev, uint8_t status) { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); - bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + bool should_start = virtio_device_started(vdev, status); - if (!vdev->vm_running) { - should_start = false; - } - - if (vvc->vhost_dev.started == should_start) { + if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) { return; } diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 75b8df21a4..03415b6c95 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -200,7 +200,7 @@ typedef struct { VhostUserRequest request; #define VHOST_USER_VERSION_MASK (0x3) -#define VHOST_USER_REPLY_MASK (0x1<<2) +#define VHOST_USER_REPLY_MASK (0x1 << 2) #define VHOST_USER_NEED_REPLY_MASK (0x1 << 3) uint32_t flags; uint32_t size; /* the following payload size */ @@ -208,7 +208,7 @@ typedef struct { typedef union { #define VHOST_USER_VRING_IDX_MASK (0xff) -#define VHOST_USER_VRING_NOFD_MASK (0x1<<8) +#define VHOST_USER_VRING_NOFD_MASK (0x1 << 8) uint64_t u64; struct vhost_vring_state state; struct vhost_vring_addr addr; @@ -248,7 +248,8 @@ struct vhost_user { size_t region_rb_len; /* RAMBlock associated with a given region */ RAMBlock **region_rb; - /* The offset from the start of the RAMBlock to the start of the + /* + * The offset from the start of the RAMBlock to the start of the * vhost region. */ ram_addr_t *region_rb_offset; @@ -295,6 +296,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) return -EPROTO; } + trace_vhost_user_read(msg->hdr.request, msg->hdr.flags); + return 0; } @@ -544,8 +547,6 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, } } - trace_vhost_user_read(msg.hdr.request, msg.hdr.flags); - return 0; } @@ -1460,7 +1461,14 @@ static int vhost_user_set_features(struct vhost_dev *dev, */ bool log_enabled = features & (0x1ULL << VHOST_F_LOG_ALL); - return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, features, + /* + * We need to include any extra backend only feature bits that + * might be needed by our device. Currently this includes the + * VHOST_USER_F_PROTOCOL_FEATURES bit for enabling protocol + * features. + */ + return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, + features | dev->backend_features, log_enabled); } @@ -1726,7 +1734,7 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev) return 0; } - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (qemu_socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { int saved_errno = errno; error_report("socketpair() failed"); return -saved_errno; diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 3ff9ce3501..7468e44b87 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -176,6 +176,7 @@ static void vhost_vdpa_listener_commit(MemoryListener *listener) static void vhost_vdpa_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { + DMAMap mem_region = {}; struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); hwaddr iova; Int128 llend, llsize; @@ -212,13 +213,13 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, llsize = int128_sub(llend, int128_make64(iova)); if (v->shadow_vqs_enabled) { - DMAMap mem_region = { - .translated_addr = (hwaddr)(uintptr_t)vaddr, - .size = int128_get64(llsize) - 1, - .perm = IOMMU_ACCESS_FLAG(true, section->readonly), - }; + int r; - int r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region); + mem_region.translated_addr = (hwaddr)(uintptr_t)vaddr, + mem_region.size = int128_get64(llsize) - 1, + mem_region.perm = IOMMU_ACCESS_FLAG(true, section->readonly), + + r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region); if (unlikely(r != IOVA_OK)) { error_report("Can't allocate a mapping (%d)", r); goto fail; @@ -232,11 +233,16 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, vaddr, section->readonly); if (ret) { error_report("vhost vdpa map fail!"); - goto fail; + goto fail_map; } return; +fail_map: + if (v->shadow_vqs_enabled) { + vhost_iova_tree_remove(v->iova_tree, mem_region); + } + fail: /* * On the initfn path, store the first error in the container so we @@ -289,8 +295,12 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, }; result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region); + if (!result) { + /* The memory listener map wasn't mapped */ + return; + } iova = result->iova; - vhost_iova_tree_remove(v->iova_tree, result); + vhost_iova_tree_remove(v->iova_tree, *result); } vhost_vdpa_iotlb_batch_begin_once(v); ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); @@ -874,41 +884,41 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, /** * Unmap a SVQ area in the device */ -static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, - const DMAMap *needle) +static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr addr) { - const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle); + const DMAMap needle = { + .translated_addr = addr, + }; + const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, &needle); hwaddr size; int r; if (unlikely(!result)) { error_report("Unable to find SVQ address to unmap"); - return false; + return; } size = ROUND_UP(result->size, qemu_real_host_page_size()); r = vhost_vdpa_dma_unmap(v, result->iova, size); - return r == 0; + if (unlikely(r < 0)) { + error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r); + return; + } + + vhost_iova_tree_remove(v->iova_tree, *result); } -static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, +static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, const VhostShadowVirtqueue *svq) { - DMAMap needle = {}; struct vhost_vdpa *v = dev->opaque; struct vhost_vring_addr svq_addr; - bool ok; vhost_svq_get_vring_addr(svq, &svq_addr); - needle.translated_addr = svq_addr.desc_user_addr; - ok = vhost_vdpa_svq_unmap_ring(v, &needle); - if (unlikely(!ok)) { - return false; - } + vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr); - needle.translated_addr = svq_addr.used_user_addr; - return vhost_vdpa_svq_unmap_ring(v, &needle); + vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr); } /** @@ -934,7 +944,7 @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle, needle->perm == IOMMU_RO); if (unlikely(r != 0)) { error_setg_errno(errp, -r, "Cannot map region to device"); - vhost_iova_tree_remove(v->iova_tree, needle); + vhost_iova_tree_remove(v->iova_tree, *needle); } return r == 0; @@ -986,7 +996,7 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, ok = vhost_vdpa_svq_map_ring(v, &device_region, errp); if (unlikely(!ok)) { error_prepend(errp, "Cannot create vq device region: "); - vhost_vdpa_svq_unmap_ring(v, &driver_region); + vhost_vdpa_svq_unmap_ring(v, driver_region.translated_addr); } addr->used_user_addr = device_region.iova; @@ -1023,13 +1033,6 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) return true; } - if (v->migration_blocker) { - int r = migrate_add_blocker(v->migration_blocker, &err); - if (unlikely(r < 0)) { - return false; - } - } - for (i = 0; i < v->shadow_vqs->len; ++i) { VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); @@ -1072,33 +1075,21 @@ err: vhost_svq_stop(svq); } - if (v->migration_blocker) { - migrate_del_blocker(v->migration_blocker); - } - return false; } -static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev) +static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) { struct vhost_vdpa *v = dev->opaque; if (!v->shadow_vqs) { - return true; + return; } for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); - bool ok = vhost_vdpa_svq_unmap_rings(dev, svq); - if (unlikely(!ok)) { - return false; - } + vhost_vdpa_svq_unmap_rings(dev, svq); } - - if (v->migration_blocker) { - migrate_del_blocker(v->migration_blocker); - } - return true; } static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) @@ -1115,10 +1106,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) } vhost_vdpa_set_vring_ready(dev); } else { - ok = vhost_vdpa_svqs_stop(dev); - if (unlikely(!ok)) { - return -1; - } + vhost_vdpa_svqs_stop(dev); vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); } diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index 7394818e00..29b9ab4f72 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -14,6 +14,7 @@ #include "hw/virtio/virtio-access.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" +#include "hw/virtio/vhost.h" #include "hw/virtio/vhost-vsock.h" #include "qemu/iov.h" #include "monitor/monitor.h" @@ -199,7 +200,7 @@ int vhost_vsock_common_pre_save(void *opaque) * At this point, backend must be stopped, otherwise * it might keep writing to memory. */ - assert(!vvc->vhost_dev.started); + assert(!vhost_dev_is_started(&vvc->vhost_dev)); return 0; } diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 0338de892f..7dc3c73931 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -70,14 +70,10 @@ static int vhost_vsock_set_running(VirtIODevice *vdev, int start) static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status) { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); - bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + bool should_start = virtio_device_started(vdev, status); int ret; - if (!vdev->vm_running) { - should_start = false; - } - - if (vvc->vhost_dev.started == should_start) { + if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) { return; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 0827d631c0..5185c15295 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -306,7 +306,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) dev->log_size = size; } -static int vhost_dev_has_iommu(struct vhost_dev *dev) +static bool vhost_dev_has_iommu(struct vhost_dev *dev) { VirtIODevice *vdev = dev->vdev; @@ -316,8 +316,12 @@ static int vhost_dev_has_iommu(struct vhost_dev *dev) * does not have IOMMU, there's no need to enable this feature * which may cause unnecessary IOTLB miss/update transactions. */ - return virtio_bus_device_iommu_enabled(vdev) && - virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); + if (vdev) { + return virtio_bus_device_iommu_enabled(vdev) && + virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); + } else { + return false; + } } static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, @@ -1473,6 +1477,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) { int i; + trace_vhost_dev_cleanup(hdev); + for (i = 0; i < hdev->nvqs; ++i) { vhost_virtqueue_cleanup(hdev->vqs + i); } @@ -1779,6 +1785,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) /* should only be called after backend is connected */ assert(hdev->vhost_ops); + trace_vhost_dev_start(hdev, vdev->name); + vdev->vhost_started = true; hdev->started = true; hdev->vdev = vdev; @@ -1865,6 +1873,8 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) /* should only be called after backend is connected */ assert(hdev->vhost_ops); + trace_vhost_dev_stop(hdev, vdev->name); + if (hdev->vhost_ops->vhost_dev_start) { hdev->vhost_ops->vhost_dev_start(hdev, false); } diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index c1243c3f93..df4bde210b 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -710,7 +710,7 @@ virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto, uint8_t *src = NULL; uint8_t *dst = NULL; - asym_op_info = g_malloc0(sizeof(CryptoDevBackendAsymOpInfo)); + asym_op_info = g_new0(CryptoDevBackendAsymOpInfo, 1); src_len = ldl_le_p(&req->para.src_data_len); dst_len = ldl_le_p(&req->para.dst_data_len); diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 281152d338..62e07ec2e4 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -197,6 +197,32 @@ static gint interval_cmp(gconstpointer a, gconstpointer b, gpointer user_data) } } +static void virtio_iommu_notify_map_unmap(IOMMUMemoryRegion *mr, + IOMMUTLBEvent *event, + hwaddr virt_start, hwaddr virt_end) +{ + uint64_t delta = virt_end - virt_start; + + event->entry.iova = virt_start; + event->entry.addr_mask = delta; + + if (delta == UINT64_MAX) { + memory_region_notify_iommu(mr, 0, *event); + } + + while (virt_start != virt_end + 1) { + uint64_t mask = dma_aligned_pow2_mask(virt_start, virt_end, 64); + + event->entry.addr_mask = mask; + event->entry.iova = virt_start; + memory_region_notify_iommu(mr, 0, *event); + virt_start += mask + 1; + if (event->entry.perm != IOMMU_NONE) { + event->entry.translated_addr += mask + 1; + } + } +} + static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start, hwaddr virt_end, hwaddr paddr, uint32_t flags) @@ -215,19 +241,16 @@ static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start, event.type = IOMMU_NOTIFIER_MAP; event.entry.target_as = &address_space_memory; - event.entry.addr_mask = virt_end - virt_start; - event.entry.iova = virt_start; event.entry.perm = perm; event.entry.translated_addr = paddr; - memory_region_notify_iommu(mr, 0, event); + virtio_iommu_notify_map_unmap(mr, &event, virt_start, virt_end); } static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start, hwaddr virt_end) { IOMMUTLBEvent event; - uint64_t delta = virt_end - virt_start; if (!(mr->iommu_notify_flags & IOMMU_NOTIFIER_UNMAP)) { return; @@ -239,22 +262,8 @@ static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start, event.entry.target_as = &address_space_memory; event.entry.perm = IOMMU_NONE; event.entry.translated_addr = 0; - event.entry.addr_mask = delta; - event.entry.iova = virt_start; - if (delta == UINT64_MAX) { - memory_region_notify_iommu(mr, 0, event); - } - - - while (virt_start != virt_end + 1) { - uint64_t mask = dma_aligned_pow2_mask(virt_start, virt_end, 64); - - event.entry.addr_mask = mask; - event.entry.iova = virt_start; - memory_region_notify_iommu(mr, 0, event); - virt_start += mask + 1; - } + virtio_iommu_notify_map_unmap(mr, &event, virt_start, virt_end); } static gboolean virtio_iommu_notify_unmap_cb(gpointer key, gpointer value, diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 45327f0b31..a50c5a57d7 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -996,9 +996,14 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX); - /* When deassigning, pass a consistent nvqs value - * to avoid leaking notifiers. + /* + * When deassigning, pass a consistent nvqs value to avoid leaking + * notifiers. But first check we've actually been configured, exit + * early if we haven't. */ + if (!assign && !proxy->nvqs_with_notifiers) { + return 0; + } assert(assign || nvqs == proxy->nvqs_with_notifiers); proxy->nvqs_with_notifiers = nvqs; @@ -1942,7 +1947,6 @@ static void virtio_pci_reset(DeviceState *qdev) { VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev); VirtioBusState *bus = VIRTIO_BUS(&proxy->bus); - PCIDevice *dev = PCI_DEVICE(qdev); int i; virtio_bus_reset(bus); @@ -1955,6 +1959,13 @@ static void virtio_pci_reset(DeviceState *qdev) proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0; proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0; } +} + +static void virtio_pci_bus_reset(DeviceState *qdev) +{ + PCIDevice *dev = PCI_DEVICE(qdev); + + virtio_pci_reset(qdev); if (pci_is_express(dev)) { pcie_cap_deverr_reset(dev); @@ -2022,7 +2033,7 @@ static void virtio_pci_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_OTHERS; device_class_set_parent_realize(dc, virtio_pci_dc_realize, &vpciklass->parent_dc_realize); - dc->reset = virtio_pci_reset; + dc->reset = virtio_pci_bus_reset; } static const TypeInfo virtio_pci_info = { diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c new file mode 100644 index 0000000000..7ddb22cc5e --- /dev/null +++ b/hw/virtio/virtio-stub.c @@ -0,0 +1,42 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-virtio.h" + +static void *qmp_virtio_unsupported(Error **errp) +{ + error_setg(errp, "Virtio is disabled"); + return NULL; +} + +VirtioInfoList *qmp_x_query_virtio(Error **errp) +{ + return qmp_virtio_unsupported(errp); +} + +VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp) +{ + return qmp_virtio_unsupported(errp); +} + +VirtVhostQueueStatus *qmp_x_query_virtio_vhost_queue_status(const char *path, + uint16_t queue, + Error **errp) +{ + return qmp_virtio_unsupported(errp); +} + +VirtQueueStatus *qmp_x_query_virtio_queue_status(const char *path, + uint16_t queue, + Error **errp) +{ + return qmp_virtio_unsupported(errp); +} + +VirtioQueueElement *qmp_x_query_virtio_queue_element(const char *path, + uint16_t queue, + bool has_index, + uint16_t index, + Error **errp) +{ + return qmp_virtio_unsupported(errp); +} diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 5d607aeaa0..808446b4c9 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -13,12 +13,18 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qapi-commands-virtio.h" +#include "qapi/qapi-commands-qom.h" +#include "qapi/qapi-visit-virtio.h" +#include "qapi/qmp/qjson.h" #include "cpu.h" #include "trace.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" +#include "qom/object_interfaces.h" #include "hw/virtio/virtio.h" #include "migration/qemu-file-types.h" #include "qemu/atomic.h" @@ -28,6 +34,432 @@ #include "sysemu/dma.h" #include "sysemu/runstate.h" #include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/vhost_types.h" +#include "standard-headers/linux/virtio_blk.h" +#include "standard-headers/linux/virtio_console.h" +#include "standard-headers/linux/virtio_gpu.h" +#include "standard-headers/linux/virtio_net.h" +#include "standard-headers/linux/virtio_scsi.h" +#include "standard-headers/linux/virtio_i2c.h" +#include "standard-headers/linux/virtio_balloon.h" +#include "standard-headers/linux/virtio_iommu.h" +#include "standard-headers/linux/virtio_mem.h" +#include "standard-headers/linux/virtio_vsock.h" +#include CONFIG_DEVICES + +/* QAPI list of realized VirtIODevices */ +static QTAILQ_HEAD(, VirtIODevice) virtio_list; + +/* + * Maximum size of virtio device config space + */ +#define VHOST_USER_MAX_CONFIG_SIZE 256 + +#define FEATURE_ENTRY(name, desc) (qmp_virtio_feature_map_t) \ + { .virtio_bit = name, .feature_desc = desc } + +enum VhostUserProtocolFeature { + VHOST_USER_PROTOCOL_F_MQ = 0, + VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, + VHOST_USER_PROTOCOL_F_RARP = 2, + VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, + VHOST_USER_PROTOCOL_F_NET_MTU = 4, + VHOST_USER_PROTOCOL_F_SLAVE_REQ = 5, + VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, + VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, + VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, + VHOST_USER_PROTOCOL_F_CONFIG = 9, + VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10, + VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, + VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12, + VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, + VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, + VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, + VHOST_USER_PROTOCOL_F_MAX +}; + +/* Virtio transport features mapping */ +static qmp_virtio_feature_map_t virtio_transport_map[] = { + /* Virtio device transport features */ +#ifndef VIRTIO_CONFIG_NO_LEGACY + FEATURE_ENTRY(VIRTIO_F_NOTIFY_ON_EMPTY, \ + "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. " + "descs. on VQ"), + FEATURE_ENTRY(VIRTIO_F_ANY_LAYOUT, \ + "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts"), +#endif /* !VIRTIO_CONFIG_NO_LEGACY */ + FEATURE_ENTRY(VIRTIO_F_VERSION_1, \ + "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)"), + FEATURE_ENTRY(VIRTIO_F_IOMMU_PLATFORM, \ + "VIRTIO_F_IOMMU_PLATFORM: Device can be used on IOMMU platform"), + FEATURE_ENTRY(VIRTIO_F_RING_PACKED, \ + "VIRTIO_F_RING_PACKED: Device supports packed VQ layout"), + FEATURE_ENTRY(VIRTIO_F_IN_ORDER, \ + "VIRTIO_F_IN_ORDER: Device uses buffers in same order as made " + "available by driver"), + FEATURE_ENTRY(VIRTIO_F_ORDER_PLATFORM, \ + "VIRTIO_F_ORDER_PLATFORM: Memory accesses ordered by platform"), + FEATURE_ENTRY(VIRTIO_F_SR_IOV, \ + "VIRTIO_F_SR_IOV: Device supports single root I/O virtualization"), + /* Virtio ring transport features */ + FEATURE_ENTRY(VIRTIO_RING_F_INDIRECT_DESC, \ + "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported"), + FEATURE_ENTRY(VIRTIO_RING_F_EVENT_IDX, \ + "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled"), + { -1, "" } +}; + +/* Vhost-user protocol features mapping */ +static qmp_virtio_feature_map_t vhost_user_protocol_map[] = { + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_MQ, \ + "VHOST_USER_PROTOCOL_F_MQ: Multiqueue protocol supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_LOG_SHMFD, \ + "VHOST_USER_PROTOCOL_F_LOG_SHMFD: Shared log memory fd supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_RARP, \ + "VHOST_USER_PROTOCOL_F_RARP: Vhost-user back-end RARP broadcasting " + "supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_REPLY_ACK, \ + "VHOST_USER_PROTOCOL_F_REPLY_ACK: Requested operation status ack. " + "supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_NET_MTU, \ + "VHOST_USER_PROTOCOL_F_NET_MTU: Expose host MTU to guest supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_SLAVE_REQ, \ + "VHOST_USER_PROTOCOL_F_SLAVE_REQ: Socket fd for back-end initiated " + "requests supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, \ + "VHOST_USER_PROTOCOL_F_CROSS_ENDIAN: Endianness of VQs for legacy " + "devices supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CRYPTO_SESSION, \ + "VHOST_USER_PROTOCOL_F_CRYPTO_SESSION: Session creation for crypto " + "operations supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_PAGEFAULT, \ + "VHOST_USER_PROTOCOL_F_PAGEFAULT: Request servicing on userfaultfd " + "for accessed pages supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIG, \ + "VHOST_USER_PROTOCOL_F_CONFIG: Vhost-user messaging for virtio " + "device configuration space supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD, \ + "VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD: Slave fd communication " + "channel supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_HOST_NOTIFIER, \ + "VHOST_USER_PROTOCOL_F_HOST_NOTIFIER: Host notifiers for specified " + "VQs supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD, \ + "VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD: Shared inflight I/O buffers " + "supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_RESET_DEVICE, \ + "VHOST_USER_PROTOCOL_F_RESET_DEVICE: Disabling all rings and " + "resetting internal device state supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS, \ + "VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS: In-band messaging " + "supported"), + FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS, \ + "VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS: Configuration for " + "memory slots supported"), + { -1, "" } +}; + +/* virtio device configuration statuses */ +static qmp_virtio_feature_map_t virtio_config_status_map[] = { + FEATURE_ENTRY(VIRTIO_CONFIG_S_DRIVER_OK, \ + "VIRTIO_CONFIG_S_DRIVER_OK: Driver setup and ready"), + FEATURE_ENTRY(VIRTIO_CONFIG_S_FEATURES_OK, \ + "VIRTIO_CONFIG_S_FEATURES_OK: Feature negotiation complete"), + FEATURE_ENTRY(VIRTIO_CONFIG_S_DRIVER, \ + "VIRTIO_CONFIG_S_DRIVER: Guest OS compatible with device"), + FEATURE_ENTRY(VIRTIO_CONFIG_S_NEEDS_RESET, \ + "VIRTIO_CONFIG_S_NEEDS_RESET: Irrecoverable error, device needs " + "reset"), + FEATURE_ENTRY(VIRTIO_CONFIG_S_FAILED, \ + "VIRTIO_CONFIG_S_FAILED: Error in guest, device failed"), + FEATURE_ENTRY(VIRTIO_CONFIG_S_ACKNOWLEDGE, \ + "VIRTIO_CONFIG_S_ACKNOWLEDGE: Valid virtio device found"), + { -1, "" } +}; + +/* virtio-blk features mapping */ +qmp_virtio_feature_map_t virtio_blk_feature_map[] = { + FEATURE_ENTRY(VIRTIO_BLK_F_SIZE_MAX, \ + "VIRTIO_BLK_F_SIZE_MAX: Max segment size is size_max"), + FEATURE_ENTRY(VIRTIO_BLK_F_SEG_MAX, \ + "VIRTIO_BLK_F_SEG_MAX: Max segments in a request is seg_max"), + FEATURE_ENTRY(VIRTIO_BLK_F_GEOMETRY, \ + "VIRTIO_BLK_F_GEOMETRY: Legacy geometry available"), + FEATURE_ENTRY(VIRTIO_BLK_F_RO, \ + "VIRTIO_BLK_F_RO: Device is read-only"), + FEATURE_ENTRY(VIRTIO_BLK_F_BLK_SIZE, \ + "VIRTIO_BLK_F_BLK_SIZE: Block size of disk available"), + FEATURE_ENTRY(VIRTIO_BLK_F_TOPOLOGY, \ + "VIRTIO_BLK_F_TOPOLOGY: Topology information available"), + FEATURE_ENTRY(VIRTIO_BLK_F_MQ, \ + "VIRTIO_BLK_F_MQ: Multiqueue supported"), + FEATURE_ENTRY(VIRTIO_BLK_F_DISCARD, \ + "VIRTIO_BLK_F_DISCARD: Discard command supported"), + FEATURE_ENTRY(VIRTIO_BLK_F_WRITE_ZEROES, \ + "VIRTIO_BLK_F_WRITE_ZEROES: Write zeroes command supported"), +#ifndef VIRTIO_BLK_NO_LEGACY + FEATURE_ENTRY(VIRTIO_BLK_F_BARRIER, \ + "VIRTIO_BLK_F_BARRIER: Request barriers supported"), + FEATURE_ENTRY(VIRTIO_BLK_F_SCSI, \ + "VIRTIO_BLK_F_SCSI: SCSI packet commands supported"), + FEATURE_ENTRY(VIRTIO_BLK_F_FLUSH, \ + "VIRTIO_BLK_F_FLUSH: Flush command supported"), + FEATURE_ENTRY(VIRTIO_BLK_F_CONFIG_WCE, \ + "VIRTIO_BLK_F_CONFIG_WCE: Cache writeback and writethrough modes " + "supported"), +#endif /* !VIRTIO_BLK_NO_LEGACY */ + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; + +/* virtio-serial features mapping */ +qmp_virtio_feature_map_t virtio_serial_feature_map[] = { + FEATURE_ENTRY(VIRTIO_CONSOLE_F_SIZE, \ + "VIRTIO_CONSOLE_F_SIZE: Host providing console size"), + FEATURE_ENTRY(VIRTIO_CONSOLE_F_MULTIPORT, \ + "VIRTIO_CONSOLE_F_MULTIPORT: Multiple ports for device supported"), + FEATURE_ENTRY(VIRTIO_CONSOLE_F_EMERG_WRITE, \ + "VIRTIO_CONSOLE_F_EMERG_WRITE: Emergency write supported"), + { -1, "" } +}; + +/* virtio-gpu features mapping */ +qmp_virtio_feature_map_t virtio_gpu_feature_map[] = { + FEATURE_ENTRY(VIRTIO_GPU_F_VIRGL, \ + "VIRTIO_GPU_F_VIRGL: Virgl 3D mode supported"), + FEATURE_ENTRY(VIRTIO_GPU_F_EDID, \ + "VIRTIO_GPU_F_EDID: EDID metadata supported"), + FEATURE_ENTRY(VIRTIO_GPU_F_RESOURCE_UUID, \ + "VIRTIO_GPU_F_RESOURCE_UUID: Resource UUID assigning supported"), + FEATURE_ENTRY(VIRTIO_GPU_F_RESOURCE_BLOB, \ + "VIRTIO_GPU_F_RESOURCE_BLOB: Size-based blob resources supported"), + FEATURE_ENTRY(VIRTIO_GPU_F_CONTEXT_INIT, \ + "VIRTIO_GPU_F_CONTEXT_INIT: Context types and synchronization " + "timelines supported"), + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; + +/* virtio-input features mapping */ +qmp_virtio_feature_map_t virtio_input_feature_map[] = { + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; + +/* virtio-net features mapping */ +qmp_virtio_feature_map_t virtio_net_feature_map[] = { + FEATURE_ENTRY(VIRTIO_NET_F_CSUM, \ + "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum " + "supported"), + FEATURE_ENTRY(VIRTIO_NET_F_GUEST_CSUM, \ + "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial " + "checksum supported"), + FEATURE_ENTRY(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \ + "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading " + "reconfig. supported"), + FEATURE_ENTRY(VIRTIO_NET_F_MTU, \ + "VIRTIO_NET_F_MTU: Device max MTU reporting supported"), + FEATURE_ENTRY(VIRTIO_NET_F_MAC, \ + "VIRTIO_NET_F_MAC: Device has given MAC address"), + FEATURE_ENTRY(VIRTIO_NET_F_GUEST_TSO4, \ + "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4"), + FEATURE_ENTRY(VIRTIO_NET_F_GUEST_TSO6, \ + "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6"), + FEATURE_ENTRY(VIRTIO_NET_F_GUEST_ECN, \ + "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN"), + FEATURE_ENTRY(VIRTIO_NET_F_GUEST_UFO, \ + "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO"), + FEATURE_ENTRY(VIRTIO_NET_F_HOST_TSO4, \ + "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4"), + FEATURE_ENTRY(VIRTIO_NET_F_HOST_TSO6, \ + "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6"), + FEATURE_ENTRY(VIRTIO_NET_F_HOST_ECN, \ + "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN"), + FEATURE_ENTRY(VIRTIO_NET_F_HOST_UFO, \ + "VIRTIO_NET_F_HOST_UFO: Device can receive UFO"), + FEATURE_ENTRY(VIRTIO_NET_F_MRG_RXBUF, \ + "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers"), + FEATURE_ENTRY(VIRTIO_NET_F_STATUS, \ + "VIRTIO_NET_F_STATUS: Configuration status field available"), + FEATURE_ENTRY(VIRTIO_NET_F_CTRL_VQ, \ + "VIRTIO_NET_F_CTRL_VQ: Control channel available"), + FEATURE_ENTRY(VIRTIO_NET_F_CTRL_RX, \ + "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported"), + FEATURE_ENTRY(VIRTIO_NET_F_CTRL_VLAN, \ + "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported"), + FEATURE_ENTRY(VIRTIO_NET_F_CTRL_RX_EXTRA, \ + "VIRTIO_NET_F_CTRL_RX_EXTRA: Extra RX mode control supported"), + FEATURE_ENTRY(VIRTIO_NET_F_GUEST_ANNOUNCE, \ + "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets " + "supported"), + FEATURE_ENTRY(VIRTIO_NET_F_MQ, \ + "VIRTIO_NET_F_MQ: Multiqueue with automatic receive steering " + "supported"), + FEATURE_ENTRY(VIRTIO_NET_F_CTRL_MAC_ADDR, \ + "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control " + "channel"), + FEATURE_ENTRY(VIRTIO_NET_F_HASH_REPORT, \ + "VIRTIO_NET_F_HASH_REPORT: Hash reporting supported"), + FEATURE_ENTRY(VIRTIO_NET_F_RSS, \ + "VIRTIO_NET_F_RSS: RSS RX steering supported"), + FEATURE_ENTRY(VIRTIO_NET_F_RSC_EXT, \ + "VIRTIO_NET_F_RSC_EXT: Extended coalescing info supported"), + FEATURE_ENTRY(VIRTIO_NET_F_STANDBY, \ + "VIRTIO_NET_F_STANDBY: Device acting as standby for primary " + "device with same MAC addr. supported"), + FEATURE_ENTRY(VIRTIO_NET_F_SPEED_DUPLEX, \ + "VIRTIO_NET_F_SPEED_DUPLEX: Device set linkspeed and duplex"), +#ifndef VIRTIO_NET_NO_LEGACY + FEATURE_ENTRY(VIRTIO_NET_F_GSO, \ + "VIRTIO_NET_F_GSO: Handling GSO-type packets supported"), +#endif /* !VIRTIO_NET_NO_LEGACY */ + FEATURE_ENTRY(VHOST_NET_F_VIRTIO_NET_HDR, \ + "VHOST_NET_F_VIRTIO_NET_HDR: Virtio-net headers for RX and TX " + "packets supported"), + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; + +/* virtio-scsi features mapping */ +qmp_virtio_feature_map_t virtio_scsi_feature_map[] = { + FEATURE_ENTRY(VIRTIO_SCSI_F_INOUT, \ + "VIRTIO_SCSI_F_INOUT: Requests including read and writable data " + "buffers suppoted"), + FEATURE_ENTRY(VIRTIO_SCSI_F_HOTPLUG, \ + "VIRTIO_SCSI_F_HOTPLUG: Reporting and handling hot-plug events " + "supported"), + FEATURE_ENTRY(VIRTIO_SCSI_F_CHANGE, \ + "VIRTIO_SCSI_F_CHANGE: Reporting and handling LUN changes " + "supported"), + FEATURE_ENTRY(VIRTIO_SCSI_F_T10_PI, \ + "VIRTIO_SCSI_F_T10_PI: T10 info included in request header"), + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; + +/* virtio/vhost-user-fs features mapping */ +qmp_virtio_feature_map_t virtio_fs_feature_map[] = { + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; + +/* virtio/vhost-user-i2c features mapping */ +qmp_virtio_feature_map_t virtio_i2c_feature_map[] = { + FEATURE_ENTRY(VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, \ + "VIRTIO_I2C_F_ZERO_LEGNTH_REQUEST: Zero length requests supported"), + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; + +/* virtio/vhost-vsock features mapping */ +qmp_virtio_feature_map_t virtio_vsock_feature_map[] = { + FEATURE_ENTRY(VIRTIO_VSOCK_F_SEQPACKET, \ + "VIRTIO_VSOCK_F_SEQPACKET: SOCK_SEQPACKET supported"), + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; + +/* virtio-balloon features mapping */ +qmp_virtio_feature_map_t virtio_balloon_feature_map[] = { + FEATURE_ENTRY(VIRTIO_BALLOON_F_MUST_TELL_HOST, \ + "VIRTIO_BALLOON_F_MUST_TELL_HOST: Tell host before reclaiming " + "pages"), + FEATURE_ENTRY(VIRTIO_BALLOON_F_STATS_VQ, \ + "VIRTIO_BALLOON_F_STATS_VQ: Guest memory stats VQ available"), + FEATURE_ENTRY(VIRTIO_BALLOON_F_DEFLATE_ON_OOM, \ + "VIRTIO_BALLOON_F_DEFLATE_ON_OOM: Deflate balloon when guest OOM"), + FEATURE_ENTRY(VIRTIO_BALLOON_F_FREE_PAGE_HINT, \ + "VIRTIO_BALLOON_F_FREE_PAGE_HINT: VQ reporting free pages enabled"), + FEATURE_ENTRY(VIRTIO_BALLOON_F_PAGE_POISON, \ + "VIRTIO_BALLOON_F_PAGE_POISON: Guest page poisoning enabled"), + FEATURE_ENTRY(VIRTIO_BALLOON_F_REPORTING, \ + "VIRTIO_BALLOON_F_REPORTING: Page reporting VQ enabled"), + { -1, "" } +}; + +/* virtio-crypto features mapping */ +qmp_virtio_feature_map_t virtio_crypto_feature_map[] = { + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + { -1, "" } +}; + +/* virtio-iommu features mapping */ +qmp_virtio_feature_map_t virtio_iommu_feature_map[] = { + FEATURE_ENTRY(VIRTIO_IOMMU_F_INPUT_RANGE, \ + "VIRTIO_IOMMU_F_INPUT_RANGE: Range of available virtual addrs. " + "available"), + FEATURE_ENTRY(VIRTIO_IOMMU_F_DOMAIN_RANGE, \ + "VIRTIO_IOMMU_F_DOMAIN_RANGE: Number of supported domains " + "available"), + FEATURE_ENTRY(VIRTIO_IOMMU_F_MAP_UNMAP, \ + "VIRTIO_IOMMU_F_MAP_UNMAP: Map and unmap requests available"), + FEATURE_ENTRY(VIRTIO_IOMMU_F_BYPASS, \ + "VIRTIO_IOMMU_F_BYPASS: Endpoints not attached to domains are in " + "bypass mode"), + FEATURE_ENTRY(VIRTIO_IOMMU_F_PROBE, \ + "VIRTIO_IOMMU_F_PROBE: Probe requests available"), + FEATURE_ENTRY(VIRTIO_IOMMU_F_MMIO, \ + "VIRTIO_IOMMU_F_MMIO: VIRTIO_IOMMU_MAP_F_MMIO flag available"), + FEATURE_ENTRY(VIRTIO_IOMMU_F_BYPASS_CONFIG, \ + "VIRTIO_IOMMU_F_BYPASS_CONFIG: Bypass field of IOMMU config " + "available"), + { -1, "" } +}; + +/* virtio-mem features mapping */ +qmp_virtio_feature_map_t virtio_mem_feature_map[] = { +#ifndef CONFIG_ACPI + FEATURE_ENTRY(VIRTIO_MEM_F_ACPI_PXM, \ + "VIRTIO_MEM_F_ACPI_PXM: node_id is an ACPI PXM and is valid"), +#endif /* !CONFIG_ACPI */ + FEATURE_ENTRY(VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, \ + "VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE: Unplugged memory cannot be " + "accessed"), + { -1, "" } +}; + +/* virtio-rng features mapping */ +qmp_virtio_feature_map_t virtio_rng_feature_map[] = { + FEATURE_ENTRY(VHOST_F_LOG_ALL, \ + "VHOST_F_LOG_ALL: Logging write descriptors supported"), + FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ + "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " + "negotiation supported"), + { -1, "" } +}; /* * The alignment to use between consumer and producer parts of vring. @@ -391,6 +823,19 @@ static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem, address_space_cache_invalidate(&caches->used, pa, sizeof(VRingUsedElem)); } +/* Called within rcu_read_lock(). */ +static inline uint16_t vring_used_flags(VirtQueue *vq) +{ + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + hwaddr pa = offsetof(VRingUsed, flags); + + if (!caches) { + return 0; + } + + return virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); +} + /* Called within rcu_read_lock(). */ static uint16_t vring_used_idx(VirtQueue *vq) { @@ -2980,6 +3425,13 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) if (vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) { return -EINVAL; } + + if (val & (1ull << VIRTIO_F_BAD_FEATURE)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: guest driver for %s has enabled UNUSED(30) feature bit!\n", + __func__, vdev->name); + } + ret = virtio_set_features_nocheck(vdev, val); if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { /* VIRTIO_RING_F_EVENT_IDX changes the size of the caches. */ @@ -2999,11 +3451,12 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) return ret; } -size_t virtio_feature_get_config_size(const VirtIOFeature *feature_sizes, - uint64_t host_features) +size_t virtio_get_config_size(const VirtIOConfigSizeParams *params, + uint64_t host_features) { - size_t config_size = 0; - int i; + size_t config_size = params->min_size; + const VirtIOFeature *feature_sizes = params->feature_sizes; + size_t i; for (i = 0; feature_sizes[i].flags != 0; i++) { if (host_features & feature_sizes[i].flags) { @@ -3011,6 +3464,7 @@ size_t virtio_feature_get_config_size(const VirtIOFeature *feature_sizes, } } + assert(config_size <= params->max_size); return config_size; } @@ -3698,6 +4152,7 @@ static void virtio_device_realize(DeviceState *dev, Error **errp) vdev->listener.commit = virtio_memory_listener_commit; vdev->listener.name = "virtio"; memory_listener_register(&vdev->listener, vdev->dma_as); + QTAILQ_INSERT_TAIL(&virtio_list, vdev, next); } static void virtio_device_unrealize(DeviceState *dev) @@ -3712,6 +4167,7 @@ static void virtio_device_unrealize(DeviceState *dev) vdc->unrealize(dev); } + QTAILQ_REMOVE(&virtio_list, vdev, next); g_free(vdev->bus_name); vdev->bus_name = NULL; } @@ -3885,6 +4341,8 @@ static void virtio_device_class_init(ObjectClass *klass, void *data) vdc->stop_ioeventfd = virtio_device_stop_ioeventfd_impl; vdc->legacy_features |= VIRTIO_LEGACY_FEATURES; + + QTAILQ_INIT(&virtio_list); } bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev) @@ -3895,6 +4353,589 @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev) return virtio_bus_ioeventfd_enabled(vbus); } +VirtioInfoList *qmp_x_query_virtio(Error **errp) +{ + VirtioInfoList *list = NULL; + VirtioInfoList *node; + VirtIODevice *vdev; + + QTAILQ_FOREACH(vdev, &virtio_list, next) { + DeviceState *dev = DEVICE(vdev); + Error *err = NULL; + QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err); + + if (err == NULL) { + GString *is_realized = qobject_to_json_pretty(obj, true); + /* virtio device is NOT realized, remove it from list */ + if (!strncmp(is_realized->str, "false", 4)) { + QTAILQ_REMOVE(&virtio_list, vdev, next); + } else { + node = g_new0(VirtioInfoList, 1); + node->value = g_new(VirtioInfo, 1); + node->value->path = g_strdup(dev->canonical_path); + node->value->name = g_strdup(vdev->name); + QAPI_LIST_PREPEND(list, node->value); + } + g_string_free(is_realized, true); + } + qobject_unref(obj); + } + + return list; +} + +static VirtIODevice *virtio_device_find(const char *path) +{ + VirtIODevice *vdev; + + QTAILQ_FOREACH(vdev, &virtio_list, next) { + DeviceState *dev = DEVICE(vdev); + + if (strcmp(dev->canonical_path, path) != 0) { + continue; + } + + Error *err = NULL; + QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err); + if (err == NULL) { + GString *is_realized = qobject_to_json_pretty(obj, true); + /* virtio device is NOT realized, remove it from list */ + if (!strncmp(is_realized->str, "false", 4)) { + g_string_free(is_realized, true); + qobject_unref(obj); + QTAILQ_REMOVE(&virtio_list, vdev, next); + return NULL; + } + g_string_free(is_realized, true); + } else { + /* virtio device doesn't exist in QOM tree */ + QTAILQ_REMOVE(&virtio_list, vdev, next); + qobject_unref(obj); + return NULL; + } + /* device exists in QOM tree & is realized */ + qobject_unref(obj); + return vdev; + } + return NULL; +} + +#define CONVERT_FEATURES(type, map, is_status, bitmap) \ + ({ \ + type *list = NULL; \ + type *node; \ + for (i = 0; map[i].virtio_bit != -1; i++) { \ + if (is_status) { \ + bit = map[i].virtio_bit; \ + } \ + else { \ + bit = 1ULL << map[i].virtio_bit; \ + } \ + if ((bitmap & bit) == 0) { \ + continue; \ + } \ + node = g_new0(type, 1); \ + node->value = g_strdup(map[i].feature_desc); \ + node->next = list; \ + list = node; \ + bitmap ^= bit; \ + } \ + list; \ + }) + +static VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap) +{ + VirtioDeviceStatus *status; + uint8_t bit; + int i; + + status = g_new0(VirtioDeviceStatus, 1); + status->statuses = CONVERT_FEATURES(strList, virtio_config_status_map, + 1, bitmap); + status->has_unknown_statuses = bitmap != 0; + if (status->has_unknown_statuses) { + status->unknown_statuses = bitmap; + } + + return status; +} + +static VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap) +{ + VhostDeviceProtocols *vhu_protocols; + uint64_t bit; + int i; + + vhu_protocols = g_new0(VhostDeviceProtocols, 1); + vhu_protocols->protocols = + CONVERT_FEATURES(strList, + vhost_user_protocol_map, 0, bitmap); + vhu_protocols->has_unknown_protocols = bitmap != 0; + if (vhu_protocols->has_unknown_protocols) { + vhu_protocols->unknown_protocols = bitmap; + } + + return vhu_protocols; +} + +static VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, + uint64_t bitmap) +{ + VirtioDeviceFeatures *features; + uint64_t bit; + int i; + + features = g_new0(VirtioDeviceFeatures, 1); + features->has_dev_features = true; + + /* transport features */ + features->transports = CONVERT_FEATURES(strList, virtio_transport_map, 0, + bitmap); + + /* device features */ + switch (device_id) { +#ifdef CONFIG_VIRTIO_SERIAL + case VIRTIO_ID_CONSOLE: + features->dev_features = + CONVERT_FEATURES(strList, virtio_serial_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_BLK + case VIRTIO_ID_BLOCK: + features->dev_features = + CONVERT_FEATURES(strList, virtio_blk_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_GPU + case VIRTIO_ID_GPU: + features->dev_features = + CONVERT_FEATURES(strList, virtio_gpu_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_NET + case VIRTIO_ID_NET: + features->dev_features = + CONVERT_FEATURES(strList, virtio_net_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_SCSI + case VIRTIO_ID_SCSI: + features->dev_features = + CONVERT_FEATURES(strList, virtio_scsi_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_BALLOON + case VIRTIO_ID_BALLOON: + features->dev_features = + CONVERT_FEATURES(strList, virtio_balloon_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_IOMMU + case VIRTIO_ID_IOMMU: + features->dev_features = + CONVERT_FEATURES(strList, virtio_iommu_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_INPUT + case VIRTIO_ID_INPUT: + features->dev_features = + CONVERT_FEATURES(strList, virtio_input_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VHOST_USER_FS + case VIRTIO_ID_FS: + features->dev_features = + CONVERT_FEATURES(strList, virtio_fs_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VHOST_VSOCK + case VIRTIO_ID_VSOCK: + features->dev_features = + CONVERT_FEATURES(strList, virtio_vsock_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_CRYPTO + case VIRTIO_ID_CRYPTO: + features->dev_features = + CONVERT_FEATURES(strList, virtio_crypto_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_MEM + case VIRTIO_ID_MEM: + features->dev_features = + CONVERT_FEATURES(strList, virtio_mem_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_I2C_ADAPTER + case VIRTIO_ID_I2C_ADAPTER: + features->dev_features = + CONVERT_FEATURES(strList, virtio_i2c_feature_map, 0, bitmap); + break; +#endif +#ifdef CONFIG_VIRTIO_RNG + case VIRTIO_ID_RNG: + features->dev_features = + CONVERT_FEATURES(strList, virtio_rng_feature_map, 0, bitmap); + break; +#endif + /* No features */ + case VIRTIO_ID_9P: + case VIRTIO_ID_PMEM: + case VIRTIO_ID_IOMEM: + case VIRTIO_ID_RPMSG: + case VIRTIO_ID_CLOCK: + case VIRTIO_ID_MAC80211_WLAN: + case VIRTIO_ID_MAC80211_HWSIM: + case VIRTIO_ID_RPROC_SERIAL: + case VIRTIO_ID_MEMORY_BALLOON: + case VIRTIO_ID_CAIF: + case VIRTIO_ID_SIGNAL_DIST: + case VIRTIO_ID_PSTORE: + case VIRTIO_ID_SOUND: + case VIRTIO_ID_BT: + case VIRTIO_ID_RPMB: + case VIRTIO_ID_VIDEO_ENCODER: + case VIRTIO_ID_VIDEO_DECODER: + case VIRTIO_ID_SCMI: + case VIRTIO_ID_NITRO_SEC_MOD: + case VIRTIO_ID_WATCHDOG: + case VIRTIO_ID_CAN: + case VIRTIO_ID_DMABUF: + case VIRTIO_ID_PARAM_SERV: + case VIRTIO_ID_AUDIO_POLICY: + case VIRTIO_ID_GPIO: + break; + default: + g_assert_not_reached(); + } + + features->has_unknown_dev_features = bitmap != 0; + if (features->has_unknown_dev_features) { + features->unknown_dev_features = bitmap; + } + + return features; +} + +VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp) +{ + VirtIODevice *vdev; + VirtioStatus *status; + + vdev = virtio_device_find(path); + if (vdev == NULL) { + error_setg(errp, "Path %s is not a VirtIODevice", path); + return NULL; + } + + status = g_new0(VirtioStatus, 1); + status->name = g_strdup(vdev->name); + status->device_id = vdev->device_id; + status->vhost_started = vdev->vhost_started; + status->guest_features = qmp_decode_features(vdev->device_id, + vdev->guest_features); + status->host_features = qmp_decode_features(vdev->device_id, + vdev->host_features); + status->backend_features = qmp_decode_features(vdev->device_id, + vdev->backend_features); + + switch (vdev->device_endian) { + case VIRTIO_DEVICE_ENDIAN_LITTLE: + status->device_endian = g_strdup("little"); + break; + case VIRTIO_DEVICE_ENDIAN_BIG: + status->device_endian = g_strdup("big"); + break; + default: + status->device_endian = g_strdup("unknown"); + break; + } + + status->num_vqs = virtio_get_num_queues(vdev); + status->status = qmp_decode_status(vdev->status); + status->isr = vdev->isr; + status->queue_sel = vdev->queue_sel; + status->vm_running = vdev->vm_running; + status->broken = vdev->broken; + status->disabled = vdev->disabled; + status->use_started = vdev->use_started; + status->started = vdev->started; + status->start_on_kick = vdev->start_on_kick; + status->disable_legacy_check = vdev->disable_legacy_check; + status->bus_name = g_strdup(vdev->bus_name); + status->use_guest_notifier_mask = vdev->use_guest_notifier_mask; + status->has_vhost_dev = vdev->vhost_started; + + if (vdev->vhost_started) { + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); + struct vhost_dev *hdev = vdc->get_vhost(vdev); + + status->vhost_dev = g_new0(VhostStatus, 1); + status->vhost_dev->n_mem_sections = hdev->n_mem_sections; + status->vhost_dev->n_tmp_sections = hdev->n_tmp_sections; + status->vhost_dev->nvqs = hdev->nvqs; + status->vhost_dev->vq_index = hdev->vq_index; + status->vhost_dev->features = + qmp_decode_features(vdev->device_id, hdev->features); + status->vhost_dev->acked_features = + qmp_decode_features(vdev->device_id, hdev->acked_features); + status->vhost_dev->backend_features = + qmp_decode_features(vdev->device_id, hdev->backend_features); + status->vhost_dev->protocol_features = + qmp_decode_protocols(hdev->protocol_features); + status->vhost_dev->max_queues = hdev->max_queues; + status->vhost_dev->backend_cap = hdev->backend_cap; + status->vhost_dev->log_enabled = hdev->log_enabled; + status->vhost_dev->log_size = hdev->log_size; + } + + return status; +} + +VirtVhostQueueStatus *qmp_x_query_virtio_vhost_queue_status(const char *path, + uint16_t queue, + Error **errp) +{ + VirtIODevice *vdev; + VirtVhostQueueStatus *status; + + vdev = virtio_device_find(path); + if (vdev == NULL) { + error_setg(errp, "Path %s is not a VirtIODevice", path); + return NULL; + } + + if (!vdev->vhost_started) { + error_setg(errp, "Error: vhost device has not started yet"); + return NULL; + } + + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); + struct vhost_dev *hdev = vdc->get_vhost(vdev); + + if (queue < hdev->vq_index || queue >= hdev->vq_index + hdev->nvqs) { + error_setg(errp, "Invalid vhost virtqueue number %d", queue); + return NULL; + } + + status = g_new0(VirtVhostQueueStatus, 1); + status->name = g_strdup(vdev->name); + status->kick = hdev->vqs[queue].kick; + status->call = hdev->vqs[queue].call; + status->desc = (uintptr_t)hdev->vqs[queue].desc; + status->avail = (uintptr_t)hdev->vqs[queue].avail; + status->used = (uintptr_t)hdev->vqs[queue].used; + status->num = hdev->vqs[queue].num; + status->desc_phys = hdev->vqs[queue].desc_phys; + status->desc_size = hdev->vqs[queue].desc_size; + status->avail_phys = hdev->vqs[queue].avail_phys; + status->avail_size = hdev->vqs[queue].avail_size; + status->used_phys = hdev->vqs[queue].used_phys; + status->used_size = hdev->vqs[queue].used_size; + + return status; +} + +VirtQueueStatus *qmp_x_query_virtio_queue_status(const char *path, + uint16_t queue, + Error **errp) +{ + VirtIODevice *vdev; + VirtQueueStatus *status; + + vdev = virtio_device_find(path); + if (vdev == NULL) { + error_setg(errp, "Path %s is not a VirtIODevice", path); + return NULL; + } + + if (queue >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, queue)) { + error_setg(errp, "Invalid virtqueue number %d", queue); + return NULL; + } + + status = g_new0(VirtQueueStatus, 1); + status->name = g_strdup(vdev->name); + status->queue_index = vdev->vq[queue].queue_index; + status->inuse = vdev->vq[queue].inuse; + status->vring_num = vdev->vq[queue].vring.num; + status->vring_num_default = vdev->vq[queue].vring.num_default; + status->vring_align = vdev->vq[queue].vring.align; + status->vring_desc = vdev->vq[queue].vring.desc; + status->vring_avail = vdev->vq[queue].vring.avail; + status->vring_used = vdev->vq[queue].vring.used; + status->used_idx = vdev->vq[queue].used_idx; + status->signalled_used = vdev->vq[queue].signalled_used; + status->signalled_used_valid = vdev->vq[queue].signalled_used_valid; + + if (vdev->vhost_started) { + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); + struct vhost_dev *hdev = vdc->get_vhost(vdev); + + /* check if vq index exists for vhost as well */ + if (queue >= hdev->vq_index && queue < hdev->vq_index + hdev->nvqs) { + status->has_last_avail_idx = true; + + int vhost_vq_index = + hdev->vhost_ops->vhost_get_vq_index(hdev, queue); + struct vhost_vring_state state = { + .index = vhost_vq_index, + }; + + status->last_avail_idx = + hdev->vhost_ops->vhost_get_vring_base(hdev, &state); + } + } else { + status->has_shadow_avail_idx = true; + status->has_last_avail_idx = true; + status->last_avail_idx = vdev->vq[queue].last_avail_idx; + status->shadow_avail_idx = vdev->vq[queue].shadow_avail_idx; + } + + return status; +} + +static strList *qmp_decode_vring_desc_flags(uint16_t flags) +{ + strList *list = NULL; + strList *node; + int i; + + struct { + uint16_t flag; + const char *value; + } map[] = { + { VRING_DESC_F_NEXT, "next" }, + { VRING_DESC_F_WRITE, "write" }, + { VRING_DESC_F_INDIRECT, "indirect" }, + { 1 << VRING_PACKED_DESC_F_AVAIL, "avail" }, + { 1 << VRING_PACKED_DESC_F_USED, "used" }, + { 0, "" } + }; + + for (i = 0; map[i].flag; i++) { + if ((map[i].flag & flags) == 0) { + continue; + } + node = g_malloc0(sizeof(strList)); + node->value = g_strdup(map[i].value); + node->next = list; + list = node; + } + + return list; +} + +VirtioQueueElement *qmp_x_query_virtio_queue_element(const char *path, + uint16_t queue, + bool has_index, + uint16_t index, + Error **errp) +{ + VirtIODevice *vdev; + VirtQueue *vq; + VirtioQueueElement *element = NULL; + + vdev = virtio_device_find(path); + if (vdev == NULL) { + error_setg(errp, "Path %s is not a VirtIO device", path); + return NULL; + } + + if (queue >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, queue)) { + error_setg(errp, "Invalid virtqueue number %d", queue); + return NULL; + } + vq = &vdev->vq[queue]; + + if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) { + error_setg(errp, "Packed ring not supported"); + return NULL; + } else { + unsigned int head, i, max; + VRingMemoryRegionCaches *caches; + MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + MemoryRegionCache *desc_cache; + VRingDesc desc; + VirtioRingDescList *list = NULL; + VirtioRingDescList *node; + int rc; int ndescs; + + RCU_READ_LOCK_GUARD(); + + max = vq->vring.num; + + if (!has_index) { + head = vring_avail_ring(vq, vq->last_avail_idx % vq->vring.num); + } else { + head = vring_avail_ring(vq, index % vq->vring.num); + } + i = head; + + caches = vring_get_region_caches(vq); + if (!caches) { + error_setg(errp, "Region caches not initialized"); + return NULL; + } + if (caches->desc.len < max * sizeof(VRingDesc)) { + error_setg(errp, "Cannot map descriptor ring"); + return NULL; + } + + desc_cache = &caches->desc; + vring_split_desc_read(vdev, &desc, desc_cache, i); + if (desc.flags & VRING_DESC_F_INDIRECT) { + int64_t len; + len = address_space_cache_init(&indirect_desc_cache, vdev->dma_as, + desc.addr, desc.len, false); + desc_cache = &indirect_desc_cache; + if (len < desc.len) { + error_setg(errp, "Cannot map indirect buffer"); + goto done; + } + + max = desc.len / sizeof(VRingDesc); + i = 0; + vring_split_desc_read(vdev, &desc, desc_cache, i); + } + + element = g_new0(VirtioQueueElement, 1); + element->avail = g_new0(VirtioRingAvail, 1); + element->used = g_new0(VirtioRingUsed, 1); + element->name = g_strdup(vdev->name); + element->index = head; + element->avail->flags = vring_avail_flags(vq); + element->avail->idx = vring_avail_idx(vq); + element->avail->ring = head; + element->used->flags = vring_used_flags(vq); + element->used->idx = vring_used_idx(vq); + ndescs = 0; + + do { + /* A buggy driver may produce an infinite loop */ + if (ndescs >= max) { + break; + } + node = g_new0(VirtioRingDescList, 1); + node->value = g_new0(VirtioRingDesc, 1); + node->value->addr = desc.addr; + node->value->len = desc.len; + node->value->flags = qmp_decode_vring_desc_flags(desc.flags); + node->next = list; + list = node; + + ndescs++; + rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, + max, &i); + } while (rc == VIRTQUEUE_READ_DESC_MORE); + element->descs = list; +done: + address_space_cache_destroy(&indirect_desc_cache); + } + + return element; +} + static const TypeInfo virtio_device_info = { .name = TYPE_VIRTIO_DEVICE, .parent = TYPE_DEVICE, diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c index e49cacd0e2..7aa57a8c51 100644 --- a/hw/watchdog/sbsa_gwdt.c +++ b/hw/watchdog/sbsa_gwdt.c @@ -24,11 +24,6 @@ #include "qemu/log.h" #include "qemu/module.h" -static WatchdogTimerModel model = { - .wdt_name = TYPE_WDT_SBSA, - .wdt_description = "SBSA-compliant generic watchdog device", -}; - static const VMStateDescription vmstate_sbsa_gwdt = { .name = "sbsa-gwdt", .version_id = 1, @@ -287,7 +282,6 @@ static const TypeInfo wdt_sbsa_gwdt_info = { static void wdt_sbsa_gwdt_register_types(void) { - watchdog_add_model(&model); type_register_static(&wdt_sbsa_gwdt_info); } diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index 1437e6c5b6..6c082a3263 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -32,49 +32,6 @@ #include "qemu/help_option.h" static WatchdogAction watchdog_action = WATCHDOG_ACTION_RESET; -static QLIST_HEAD(, WatchdogTimerModel) watchdog_list; - -void watchdog_add_model(WatchdogTimerModel *model) -{ - QLIST_INSERT_HEAD(&watchdog_list, model, entry); -} - -/* Returns: - * 0 = continue - * 1 = exit program with error - * 2 = exit program without error - */ -int select_watchdog(const char *p) -{ - WatchdogTimerModel *model; - QemuOpts *opts; - - /* -watchdog ? lists available devices and exits cleanly. */ - if (is_help_option(p)) { - QLIST_FOREACH(model, &watchdog_list, entry) { - fprintf(stderr, "\t%s\t%s\n", - model->wdt_name, model->wdt_description); - } - return 2; - } - - QLIST_FOREACH(model, &watchdog_list, entry) { - if (strcasecmp(model->wdt_name, p) == 0) { - /* add the device */ - opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, - &error_abort); - qemu_opt_set(opts, "driver", p, &error_abort); - return 0; - } - } - - fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n"); - QLIST_FOREACH(model, &watchdog_list, entry) { - fprintf(stderr, "\t%s\t%s\n", - model->wdt_name, model->wdt_description); - } - return 1; -} WatchdogAction get_watchdog_action(void) { diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 31855afdf4..d753693a2e 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -202,11 +202,6 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, return; } -static WatchdogTimerModel model = { - .wdt_name = TYPE_ASPEED_WDT, - .wdt_description = "Aspeed watchdog device", -}; - static const VMStateDescription vmstate_aspeed_wdt = { .name = "vmstate_aspeed_wdt", .version_id = 0, @@ -416,7 +411,6 @@ static const TypeInfo aspeed_1030_wdt_info = { static void wdt_aspeed_register_types(void) { - watchdog_add_model(&model); type_register_static(&aspeed_wdt_info); type_register_static(&aspeed_2400_wdt_info); type_register_static(&aspeed_2500_wdt_info); diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c index 9e8882a11c..76d89fbf78 100644 --- a/hw/watchdog/wdt_diag288.c +++ b/hw/watchdog/wdt_diag288.c @@ -19,11 +19,6 @@ #include "migration/vmstate.h" #include "qemu/log.h" -static WatchdogTimerModel model = { - .wdt_name = TYPE_WDT_DIAG288, - .wdt_description = "diag288 device for s390x platform", -}; - static const VMStateDescription vmstate_diag288 = { .name = "vmstate_diag288", .version_id = 0, @@ -138,7 +133,6 @@ static const TypeInfo wdt_diag288_info = { static void wdt_diag288_register_types(void) { - watchdog_add_model(&model); type_register_static(&wdt_diag288_info); } diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index f99a1c9d29..5693ec6a09 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -457,11 +457,6 @@ static void i6300esb_exit(PCIDevice *dev) timer_free(d->timer); } -static WatchdogTimerModel model = { - .wdt_name = "i6300esb", - .wdt_description = "Intel 6300ESB", -}; - static void i6300esb_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -493,7 +488,6 @@ static const TypeInfo i6300esb_info = { static void i6300esb_register_types(void) { - watchdog_add_model(&model); type_register_static(&i6300esb_info); } diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index 91d1bdc0da..b116c3a3aa 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -128,11 +128,6 @@ static void wdt_ib700_reset(DeviceState *dev) timer_del(s->timer); } -static WatchdogTimerModel model = { - .wdt_name = "ib700", - .wdt_description = "iBASE 700", -}; - static void wdt_ib700_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -153,7 +148,6 @@ static const TypeInfo wdt_ib700_info = { static void wdt_ib700_register_types(void) { - watchdog_add_model(&model); type_register_static(&wdt_ib700_info); } diff --git a/hw/watchdog/wdt_imx2.c b/hw/watchdog/wdt_imx2.c index c3128370b5..e776a2fbd4 100644 --- a/hw/watchdog/wdt_imx2.c +++ b/hw/watchdog/wdt_imx2.c @@ -291,14 +291,8 @@ static const TypeInfo imx2_wdt_info = { .class_init = imx2_wdt_class_init, }; -static WatchdogTimerModel model = { - .wdt_name = "imx2-watchdog", - .wdt_description = "i.MX2 Watchdog", -}; - static void imx2_wdt_register_type(void) { - watchdog_add_model(&model); type_register_static(&imx2_wdt_info); } type_init(imx2_wdt_register_type) diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index 4758514ddf..cde898b744 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -985,8 +985,8 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = { .offset = 0x28, .size = 2, .init_val = 0x0000, - .ro_mask = 0xFFE0, - .emu_mask = 0xFFFF, + .ro_mask = 0xFFA0, + .emu_mask = 0xFFBF, .init = xen_pt_devctrl2_reg_init, .u.w.read = xen_pt_word_reg_read, .u.w.write = xen_pt_word_reg_write, diff --git a/include/block/accounting.h b/include/block/accounting.h index 878b4c3581..b9caad60d5 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -27,7 +27,7 @@ #include "qemu/timed-average.h" #include "qemu/thread.h" -#include "qapi/qapi-builtin-types.h" +#include "qapi/qapi-types-common.h" typedef struct BlockAcctTimedStats BlockAcctTimedStats; typedef struct BlockAcctStats BlockAcctStats; @@ -100,8 +100,8 @@ typedef struct BlockAcctCookie { } BlockAcctCookie; void block_acct_init(BlockAcctStats *stats); -void block_acct_setup(BlockAcctStats *stats, bool account_invalid, - bool account_failed); +void block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid, + enum OnOffAuto account_failed); void block_acct_cleanup(BlockAcctStats *stats); void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length); BlockAcctTimedStats *block_acct_interval_next(BlockAcctStats *stats, diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h index 54840f8622..dd9a7f6461 100644 --- a/include/block/aio-wait.h +++ b/include/block/aio-wait.h @@ -59,10 +59,13 @@ typedef struct { extern AioWait global_aio_wait; /** - * AIO_WAIT_WHILE: + * AIO_WAIT_WHILE_INTERNAL: * @ctx: the aio context, or NULL if multiple aio contexts (for which the * caller does not hold a lock) are involved in the polling condition. * @cond: wait while this conditional expression is true + * @unlock: whether to unlock and then lock again @ctx. This apples + * only when waiting for another AioContext from the main loop. + * Otherwise it's ignored. * * Wait while a condition is true. Use this to implement synchronous * operations that require event loop activity. @@ -75,7 +78,7 @@ extern AioWait global_aio_wait; * wait on conditions between two IOThreads since that could lead to deadlock, * go via the main loop instead. */ -#define AIO_WAIT_WHILE(ctx, cond) ({ \ +#define AIO_WAIT_WHILE_INTERNAL(ctx, cond, unlock) ({ \ bool waited_ = false; \ AioWait *wait_ = &global_aio_wait; \ AioContext *ctx_ = (ctx); \ @@ -92,11 +95,11 @@ extern AioWait global_aio_wait; assert(qemu_get_current_aio_context() == \ qemu_get_aio_context()); \ while ((cond)) { \ - if (ctx_) { \ + if (unlock && ctx_) { \ aio_context_release(ctx_); \ } \ aio_poll(qemu_get_aio_context(), true); \ - if (ctx_) { \ + if (unlock && ctx_) { \ aio_context_acquire(ctx_); \ } \ waited_ = true; \ @@ -105,6 +108,12 @@ extern AioWait global_aio_wait; qatomic_dec(&wait_->num_waiters); \ waited_; }) +#define AIO_WAIT_WHILE(ctx, cond) \ + AIO_WAIT_WHILE_INTERNAL(ctx, cond, true) + +#define AIO_WAIT_WHILE_UNLOCKED(ctx, cond) \ + AIO_WAIT_WHILE_INTERNAL(ctx, cond, false) + /** * aio_wait_kick: * Wake up the main thread if it is waiting on AIO_WAIT_WHILE(). During diff --git a/include/block/block-io.h b/include/block/block-io.h index fd25ffa9be..492f95fc05 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -150,7 +150,6 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size); void *qemu_blockalign0(BlockDriverState *bs, size_t size); void *qemu_try_blockalign(BlockDriverState *bs, size_t size); void *qemu_try_blockalign0(BlockDriverState *bs, size_t size); -bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index 91cdd61692..4b0b3e17ef 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -73,7 +73,7 @@ static inline int coroutine_fn bdrv_co_pwrite(BdrvChild *child, return bdrv_co_pwritev(child, offset, bytes, &qiov, flags); } -bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, +void coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, uint64_t align); BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs); diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 6525e16fd5..03032b2eca 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -40,21 +40,38 @@ typedef struct BlockJobDriver BlockJobDriver; * Long-running operation on a BlockDriverState. */ typedef struct BlockJob { - /** Data belonging to the generic Job infrastructure */ + /** + * Data belonging to the generic Job infrastructure. + * Protected by job mutex. + */ Job job; - /** Status that is published by the query-block-jobs QMP API */ + /** + * Status that is published by the query-block-jobs QMP API. + * Protected by job mutex. + */ BlockDeviceIoStatus iostatus; - /** Speed that was set with @block_job_set_speed. */ + /** + * Speed that was set with @block_job_set_speed. + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). + */ int64_t speed; - /** Rate limiting data structure for implementing @speed. */ + /** + * Rate limiting data structure for implementing @speed. + * RateLimit API is thread-safe. + */ RateLimit limit; - /** Block other operations when block job is running */ + /** + * Block other operations when block job is running. + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). + */ Error *blocker; + /** All notifiers are set once in block_job_create() and never modified. */ + /** Called when a cancelled job is finalised. */ Notifier finalize_cancelled_notifier; @@ -70,7 +87,10 @@ typedef struct BlockJob { /** Called when the job coroutine yields or terminates */ Notifier idle_notifier; - /** BlockDriverStates that are involved in this block job */ + /** + * BlockDriverStates that are involved in this block job. + * Always modified and read under QEMU global mutex (GLOBAL_STATE_CODE). + */ GSList *nodes; } BlockJob; @@ -82,15 +102,16 @@ typedef struct BlockJob { */ /** - * block_job_next: + * block_job_next_locked: * @job: A block job, or %NULL. * * Get the next element from the list of block jobs after @job, or the * first one if @job is %NULL. * * Returns the requested job, or %NULL if there are no more jobs left. + * Called with job lock held. */ -BlockJob *block_job_next(BlockJob *job); +BlockJob *block_job_next_locked(BlockJob *job); /** * block_job_get: @@ -99,9 +120,13 @@ BlockJob *block_job_next(BlockJob *job); * Get the block job identified by @id (which must not be %NULL). * * Returns the requested job, or %NULL if it doesn't exist. + * Called with job lock *not* held. */ BlockJob *block_job_get(const char *id); +/* Same as block_job_get(), but called with job lock held. */ +BlockJob *block_job_get_locked(const char *id); + /** * block_job_add_bdrv: * @job: A block job @@ -135,32 +160,38 @@ void block_job_remove_all_bdrv(BlockJob *job); bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs); /** - * block_job_set_speed: + * block_job_set_speed_locked: * @job: The job to set the speed for. * @speed: The new value * @errp: Error object. * * Set a rate-limiting parameter for the job; the actual meaning may * vary depending on the job type. + * + * Called with job lock held, but might release it temporarily. */ -bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); +bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp); /** - * block_job_query: + * block_job_query_locked: * @job: The job to get information about. * * Return information about a job. + * + * Called with job lock held. */ -BlockJobInfo *block_job_query(BlockJob *job, Error **errp); +BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp); /** - * block_job_iostatus_reset: + * block_job_iostatus_reset_locked: * @job: The job whose I/O status should be reset. * * Reset I/O status on @job and on BlockDriverState objects it uses, * other than job->blk. + * + * Called with job lock held. */ -void block_job_iostatus_reset(BlockJob *job); +void block_job_iostatus_reset_locked(BlockJob *job); /* * block_job_get_aio_context: diff --git a/include/block/nbd.h b/include/block/nbd.h index c74b7a9d2e..4ede3b2bd0 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -424,6 +424,6 @@ QIOChannel *coroutine_fn nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info, bool blocking, Error **errp); -void coroutine_fn nbd_co_establish_connection_cancel(NBDClientConnection *conn); +void nbd_co_establish_connection_cancel(NBDClientConnection *conn); #endif diff --git a/include/chardev/char.h b/include/chardev/char.h index a319b5fdff..44cd82e405 100644 --- a/include/chardev/char.h +++ b/include/chardev/char.h @@ -186,7 +186,7 @@ int qemu_chr_be_can_write(Chardev *s); * the caller should call @qemu_chr_be_can_write to determine how much data * the front end can currently accept. */ -void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len); +void qemu_chr_be_write(Chardev *s, const uint8_t *buf, int len); /** * qemu_chr_be_write_impl: @@ -195,7 +195,7 @@ void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len); * * Implementation of back end writing. Used by replay module. */ -void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len); +void qemu_chr_be_write_impl(Chardev *s, const uint8_t *buf, int len); /** * qemu_chr_be_update_read_handlers: diff --git a/include/elf.h b/include/elf.h index 3a4bcb646a..3d6b9062c0 100644 --- a/include/elf.h +++ b/include/elf.h @@ -31,6 +31,7 @@ typedef int64_t Elf64_Sxword; #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff +#define PT_GNU_STACK (PT_LOOS + 0x474e551) #define PT_GNU_PROPERTY (PT_LOOS + 0x474e553) #define PT_MIPS_REGINFO 0x70000000 diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index f5bda2c3ca..16b7df41bf 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -262,6 +262,12 @@ extern const TargetPageBits target_page; #define PAGE_TARGET_1 0x0200 #define PAGE_TARGET_2 0x0400 +/* + * For linux-user, indicates that the page is mapped with the same semantics + * in both guest and host. + */ +#define PAGE_PASSTHROUGH 0x0800 + #if defined(CONFIG_USER_ONLY) void page_dump(FILE *f); @@ -271,6 +277,7 @@ int walk_memory_regions(void *, walk_memory_regions_fn); int page_get_flags(target_ulong address); void page_set_flags(target_ulong start, target_ulong end, int flags); +void page_reset_target_data(target_ulong start, target_ulong end); int page_check_range(target_ulong start, target_ulong len, int flags); /** diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 2281be4e10..c493510ee9 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -38,6 +38,7 @@ void cpu_list_unlock(void); unsigned int cpu_list_generation_id_get(void); void tcg_flush_softmmu_tlb(CPUState *cs); +void tcg_flush_jmp_cache(CPUState *cs); void tcg_iommu_init_notifier_list(CPUState *cpu); void tcg_iommu_free_notifier_list(CPUState *cpu); @@ -72,6 +73,7 @@ typedef uintptr_t ram_addr_t; void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); /* This should not be used by devices. */ ram_addr_t qemu_ram_addr_from_host(void *ptr); +ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr); RAMBlock *qemu_ram_block_by_name(const char *name); RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset, ram_addr_t *offset); diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index ba3cd32a1e..21309cf567 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -54,6 +54,9 @@ # error TARGET_PAGE_BITS must be defined in cpu-param.h # endif #endif +#ifndef TARGET_TB_PCREL +# define TARGET_TB_PCREL 0 +#endif #define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8) @@ -108,6 +111,7 @@ typedef uint64_t target_ulong; # endif # endif +/* Minimalized TLB entry for use by TCG fast path. */ typedef struct CPUTLBEntry { /* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address bit TARGET_PAGE_BITS-1..4 : Nonzero for accesses that should not @@ -131,14 +135,14 @@ typedef struct CPUTLBEntry { QEMU_BUILD_BUG_ON(sizeof(CPUTLBEntry) != (1 << CPU_TLB_ENTRY_BITS)); -/* The IOTLB is not accessed directly inline by generated TCG code, - * so the CPUIOTLBEntry layout is not as critical as that of the - * CPUTLBEntry. (This is also why we don't want to combine the two - * structs into one.) +/* + * The full TLB entry, which is not accessed by generated TCG code, + * so the layout is not as critical as that of CPUTLBEntry. This is + * also why we don't want to combine the two structs. */ -typedef struct CPUIOTLBEntry { +typedef struct CPUTLBEntryFull { /* - * @addr contains: + * @xlat_section contains: * - in the lower TARGET_PAGE_BITS, a physical section number * - with the lower TARGET_PAGE_BITS masked off, an offset which * must be added to the virtual address to obtain: @@ -146,9 +150,32 @@ typedef struct CPUIOTLBEntry { * number is PHYS_SECTION_NOTDIRTY or PHYS_SECTION_ROM) * + the offset within the target MemoryRegion (otherwise) */ - hwaddr addr; + hwaddr xlat_section; + + /* + * @phys_addr contains the physical address in the address space + * given by cpu_asidx_from_attrs(cpu, @attrs). + */ + hwaddr phys_addr; + + /* @attrs contains the memory transaction attributes for the page. */ MemTxAttrs attrs; -} CPUIOTLBEntry; + + /* @prot contains the complete protections for the page. */ + uint8_t prot; + + /* @lg_page_size contains the log2 of the page size. */ + uint8_t lg_page_size; + + /* + * Allow target-specific additions to this structure. + * This may be used to cache items from the guest cpu + * page tables for later use by the implementation. + */ +#ifdef TARGET_PAGE_ENTRY_EXTRA + TARGET_PAGE_ENTRY_EXTRA +#endif +} CPUTLBEntryFull; /* * Data elements that are per MMU mode, minus the bits accessed by @@ -172,9 +199,8 @@ typedef struct CPUTLBDesc { size_t vindex; /* The tlb victim table, in two parts. */ CPUTLBEntry vtable[CPU_VTLB_SIZE]; - CPUIOTLBEntry viotlb[CPU_VTLB_SIZE]; - /* The iotlb. */ - CPUIOTLBEntry *iotlb; + CPUTLBEntryFull vfulltlb[CPU_VTLB_SIZE]; + CPUTLBEntryFull *fulltlb; } CPUTLBDesc; /* diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 311e5fb422..e5f8b224a5 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -39,7 +39,6 @@ typedef ram_addr_t tb_page_addr_t; #define TB_PAGE_ADDR_FMT RAM_ADDR_FMT #endif -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns); void restore_state_to_opc(CPUArchState *env, TranslationBlock *tb, target_ulong *data); @@ -258,6 +257,28 @@ void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu, uint16_t idxmap, unsigned bits); +/** + * tlb_set_page_full: + * @cpu: CPU context + * @mmu_idx: mmu index of the tlb to modify + * @vaddr: virtual address of the entry to add + * @full: the details of the tlb entry + * + * Add an entry to @cpu tlb index @mmu_idx. All of the fields of + * @full must be filled, except for xlat_section, and constitute + * the complete description of the translated page. + * + * This is generally called by the target tlb_fill function after + * having performed a successful page table walk to find the physical + * address and attributes for the translation. + * + * At most one entry for a given virtual address is permitted. Only a + * single TARGET_PAGE_SIZE region is mapped; @full->lg_page_size is only + * used by tlb_flush_page. + */ +void tlb_set_page_full(CPUState *cpu, int mmu_idx, target_ulong vaddr, + CPUTLBEntryFull *full); + /** * tlb_set_page_with_attrs: * @cpu: CPU to add this TLB entry for @@ -435,6 +456,21 @@ int probe_access_flags(CPUArchState *env, target_ulong addr, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, uintptr_t retaddr); +#ifndef CONFIG_USER_ONLY +/** + * probe_access_full: + * Like probe_access_flags, except also return into @pfull. + * + * The CPUTLBEntryFull structure returned via @pfull is transient + * and must be consumed or copied immediately, before any further + * access or changes to TLB @mmu_idx. + */ +int probe_access_full(CPUArchState *env, target_ulong addr, + MMUAccessType access_type, int mmu_idx, + bool nonfault, void **phost, + CPUTLBEntryFull **pfull, uintptr_t retaddr); +#endif + #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ /* Estimated block size for TB allocation. */ @@ -460,8 +496,32 @@ struct tb_tc { }; struct TranslationBlock { - target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ - target_ulong cs_base; /* CS base for this block */ +#if !TARGET_TB_PCREL + /* + * Guest PC corresponding to this block. This must be the true + * virtual address. Therefore e.g. x86 stores EIP + CS_BASE, and + * targets like Arm, MIPS, HP-PA, which reuse low bits for ISA or + * privilege, must store those bits elsewhere. + * + * If TARGET_TB_PCREL, the opcodes for the TranslationBlock are + * written such that the TB is associated only with the physical + * page and may be run in any virtual address context. In this case, + * PC must always be taken from ENV in a target-specific manner. + * Unwind information is taken as offsets from the page, to be + * deposited into the "current" PC. + */ + target_ulong pc; +#endif + + /* + * Target-specific data associated with the TranslationBlock, e.g.: + * x86: the original user, the Code Segment virtual base, + * arm: an extension of tb->flags, + * s390x: instruction data for EXECUTE, + * sparc: the next pc of the instruction queue (for delay slots). + */ + target_ulong cs_base; + uint32_t flags; /* flags defining in which context the code was generated */ uint32_t cflags; /* compile flags */ @@ -534,6 +594,16 @@ struct TranslationBlock { uintptr_t jmp_dest[2]; }; +/* Hide the read to avoid ifdefs for TARGET_TB_PCREL. */ +static inline target_ulong tb_pc(const TranslationBlock *tb) +{ +#if TARGET_TB_PCREL + qemu_build_not_reached(); +#else + return tb->pc; +#endif +} + /* Hide the qatomic_read to make code a little easier on the eyes */ static inline uint32_t tb_cflags(const TranslationBlock *tb) { @@ -552,9 +622,6 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs); #endif void tb_flush(CPUState *cpu); void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); -TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc, - target_ulong cs_base, uint32_t flags, - uint32_t cflags); void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr); /* GETPC is the true target of the return instruction that we'll execute. */ @@ -598,43 +665,44 @@ struct MemoryRegionSection *iotlb_to_section(CPUState *cpu, hwaddr index, MemTxAttrs attrs); #endif -#if defined(CONFIG_USER_ONLY) -void mmap_lock(void); -void mmap_unlock(void); -bool have_mmap_lock(void); - /** - * get_page_addr_code() - user-mode version + * get_page_addr_code_hostp() * @env: CPUArchState * @addr: guest virtual address of guest code * - * Returns @addr. + * See get_page_addr_code() (full-system version) for documentation on the + * return value. + * + * Sets *@hostp (when @hostp is non-NULL) as follows. + * If the return value is -1, sets *@hostp to NULL. Otherwise, sets *@hostp + * to the host address where @addr's content is kept. + * + * Note: this function can trigger an exception. + */ +tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, + void **hostp); + +/** + * get_page_addr_code() + * @env: CPUArchState + * @addr: guest virtual address of guest code + * + * If we cannot translate and execute from the entire RAM page, or if + * the region is not backed by RAM, returns -1. Otherwise, returns the + * ram_addr_t corresponding to the guest code at @addr. + * + * Note: this function can trigger an exception. */ static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) { - return addr; + return get_page_addr_code_hostp(env, addr, NULL); } -/** - * get_page_addr_code_hostp() - user-mode version - * @env: CPUArchState - * @addr: guest virtual address of guest code - * - * Returns @addr. - * - * If @hostp is non-NULL, sets *@hostp to the host address where @addr's content - * is kept. - */ -static inline tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, - target_ulong addr, - void **hostp) -{ - if (hostp) { - *hostp = g2h_untagged(addr); - } - return addr; -} +#if defined(CONFIG_USER_ONLY) +void mmap_lock(void); +void mmap_unlock(void); +bool have_mmap_lock(void); /** * adjust_signal_pc: @@ -691,36 +759,6 @@ G_NORETURN void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, static inline void mmap_lock(void) {} static inline void mmap_unlock(void) {} -/** - * get_page_addr_code() - full-system version - * @env: CPUArchState - * @addr: guest virtual address of guest code - * - * If we cannot translate and execute from the entire RAM page, or if - * the region is not backed by RAM, returns -1. Otherwise, returns the - * ram_addr_t corresponding to the guest code at @addr. - * - * Note: this function can trigger an exception. - */ -tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr); - -/** - * get_page_addr_code_hostp() - full-system version - * @env: CPUArchState - * @addr: guest virtual address of guest code - * - * See get_page_addr_code() (full-system version) for documentation on the - * return value. - * - * Sets *@hostp (when @hostp is non-NULL) as follows. - * If the return value is -1, sets *@hostp to NULL. Otherwise, sets *@hostp - * to the host address where @addr's content is kept. - * - * Note: this function can trigger an exception. - */ -tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, - void **hostp); - void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length); void tlb_set_dirty(CPUState *cpu, target_ulong vaddr); diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h index f92f169739..5004728c61 100644 --- a/include/exec/plugin-gen.h +++ b/include/exec/plugin-gen.h @@ -19,7 +19,8 @@ struct DisasContextBase; #ifdef CONFIG_PLUGIN -bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool supress); +bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db, + bool supress); void plugin_gen_tb_end(CPUState *cpu); void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db); void plugin_gen_insn_end(void); @@ -48,8 +49,8 @@ static inline void plugin_insn_append(abi_ptr pc, const void *from, size_t size) #else /* !CONFIG_PLUGIN */ -static inline -bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool supress) +static inline bool +plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db, bool sup) { return false; } diff --git a/include/exec/translator.h b/include/exec/translator.h index 7db6845535..3b77f5f4aa 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -26,6 +26,19 @@ #include "exec/translate-all.h" #include "tcg/tcg.h" +/** + * gen_intermediate_code + * @cpu: cpu context + * @tb: translation block + * @max_insns: max number of instructions to translate + * @pc: guest virtual program counter address + * @host_pc: host physical program counter address + * + * This function must be provided by the target, which should create + * the target-specific DisasContext, and then invoke translator_loop. + */ +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc); /** * DisasJumpType: @@ -68,24 +81,14 @@ typedef enum DisasJumpType { * Architecture-agnostic disassembly context. */ typedef struct DisasContextBase { - const TranslationBlock *tb; + TranslationBlock *tb; target_ulong pc_first; target_ulong pc_next; DisasJumpType is_jmp; int num_insns; int max_insns; bool singlestep_enabled; -#ifdef CONFIG_USER_ONLY - /* - * Guest address of the last byte of the last protected page. - * - * Pages containing the translated instructions are made non-writable in - * order to achieve consistency in case another thread is modifying the - * code while translate_insn() fetches the instruction bytes piecemeal. - * Such writer threads are blocked on mmap_lock() in page_unprotect(). - */ - target_ulong page_protect_end; -#endif + void *host_addr[2]; } DisasContextBase; /** @@ -123,11 +126,13 @@ typedef struct TranslatorOps { /** * translator_loop: - * @ops: Target-specific operations. - * @db: Disassembly context. * @cpu: Target vCPU. * @tb: Translation block. * @max_insns: Maximum number of insns to translate. + * @pc: guest virtual program counter address + * @host_pc: host physical program counter address + * @ops: Target-specific operations. + * @db: Disassembly context. * * Generic translator loop. * @@ -141,8 +146,9 @@ typedef struct TranslatorOps { * - When single-stepping is enabled (system-wide or on the current vCPU). * - When too many instructions have been translated. */ -void translator_loop(const TranslatorOps *ops, DisasContextBase *db, - CPUState *cpu, TranslationBlock *tb, int max_insns); +void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc, + const TranslatorOps *ops, DisasContextBase *db); void translator_loop_temp_check(DisasContextBase *db); @@ -167,24 +173,52 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest); * the relevant information at translation time. */ -#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \ - type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \ - abi_ptr pc, bool do_swap); \ - static inline type fullname(CPUArchState *env, \ - DisasContextBase *dcbase, abi_ptr pc) \ - { \ - return fullname ## _swap(env, dcbase, pc, false); \ +uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc); +uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc); +uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc); +uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc); + +static inline uint16_t +translator_lduw_swap(CPUArchState *env, DisasContextBase *db, + abi_ptr pc, bool do_swap) +{ + uint16_t ret = translator_lduw(env, db, pc); + if (do_swap) { + ret = bswap16(ret); } + return ret; +} -#define FOR_EACH_TRANSLATOR_LD(F) \ - F(translator_ldub, uint8_t, cpu_ldub_code, /* no swap */) \ - F(translator_ldsw, int16_t, cpu_ldsw_code, bswap16) \ - F(translator_lduw, uint16_t, cpu_lduw_code, bswap16) \ - F(translator_ldl, uint32_t, cpu_ldl_code, bswap32) \ - F(translator_ldq, uint64_t, cpu_ldq_code, bswap64) +static inline uint32_t +translator_ldl_swap(CPUArchState *env, DisasContextBase *db, + abi_ptr pc, bool do_swap) +{ + uint32_t ret = translator_ldl(env, db, pc); + if (do_swap) { + ret = bswap32(ret); + } + return ret; +} -FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD) +static inline uint64_t +translator_ldq_swap(CPUArchState *env, DisasContextBase *db, + abi_ptr pc, bool do_swap) +{ + uint64_t ret = translator_ldq(env, db, pc); + if (do_swap) { + ret = bswap64(ret); + } + return ret; +} -#undef GEN_TRANSLATOR_LD +/* + * Return whether addr is on the same page as where disassembly started. + * Translators can use this to enforce the rule that only single-insn + * translation blocks are allowed to cross page boundaries. + */ +static inline bool is_same_page(const DisasContextBase *db, target_ulong addr) +{ + return ((addr ^ db->pc_first) & TARGET_PAGE_MASK) == 0; +} #endif /* EXEC__TRANSLATOR_H */ diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index 7a6ea881d8..0884ec4ef7 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -195,6 +195,10 @@ typedef struct float_status { bool snan_bit_is_one; bool use_first_nan; bool no_signaling_nans; + /* should overflowed results subtract re_bias to its exponent? */ + bool rebias_overflow; + /* should underflowed results add re_bias to its exponent? */ + bool rebias_underflow; } float_status; #endif /* SOFTFLOAT_TYPES_H */ diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h index c7ebae156e..f18cc3064f 100644 --- a/include/hw/arm/boot.h +++ b/include/hw/arm/boot.h @@ -25,13 +25,16 @@ typedef enum { * armv7m_load_kernel: * @cpu: CPU * @kernel_filename: file to load + * @mem_base: base address to load image at (should be where the + * CPU expects to find its vector table on reset) * @mem_size: mem_size: maximum image size to load * * Load the guest image for an ARMv7M system. This must be called by * any ARMv7M board. (This is necessary to ensure that the CPU resets * correctly on system reset, as well as for kernel loading.) */ -void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size); +void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, + hwaddr mem_base, int mem_size); /* arm_boot.c */ struct arm_boot_info { diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 85fd9f53da..20bdf894aa 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -42,6 +42,7 @@ #include "hw/misc/xlnx-zynqmp-apu-ctrl.h" #include "hw/misc/xlnx-zynqmp-crf.h" #include "hw/timer/cadence_ttc.h" +#include "hw/usb/hcd-dwc3.h" #define TYPE_XLNX_ZYNQMP "xlnx-zynqmp" OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP) @@ -56,6 +57,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP) #define XLNX_ZYNQMP_NUM_SPIS 2 #define XLNX_ZYNQMP_NUM_GDMA_CH 8 #define XLNX_ZYNQMP_NUM_ADMA_CH 8 +#define XLNX_ZYNQMP_NUM_USB 2 #define XLNX_ZYNQMP_NUM_QSPI_BUS 2 #define XLNX_ZYNQMP_NUM_QSPI_BUS_CS 2 @@ -132,6 +134,7 @@ struct XlnxZynqMPState { XlnxZynqMPAPUCtrl apu_ctrl; XlnxZynqMPCRF crf; CadenceTTCState ttc[XLNX_ZYNQMP_NUM_TTC]; + USBDWC3 usb[XLNX_ZYNQMP_NUM_USB]; char *boot_cpu; ARMCPU *boot_cpu_ptr; diff --git a/include/hw/block/block.h b/include/hw/block/block.h index 5902c0440a..15fff66435 100644 --- a/include/hw/block/block.h +++ b/include/hw/block/block.h @@ -31,6 +31,7 @@ typedef struct BlockConf { uint32_t lcyls, lheads, lsecs; OnOffAuto wce; bool share_rw; + OnOffAuto account_invalid, account_failed; BlockdevOnError rerror; BlockdevOnError werror; } BlockConf; @@ -61,7 +62,11 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) _conf.discard_granularity, -1), \ DEFINE_PROP_ON_OFF_AUTO("write-cache", _state, _conf.wce, \ ON_OFF_AUTO_AUTO), \ - DEFINE_PROP_BOOL("share-rw", _state, _conf.share_rw, false) + DEFINE_PROP_BOOL("share-rw", _state, _conf.share_rw, false), \ + DEFINE_PROP_ON_OFF_AUTO("account-invalid", _state, \ + _conf.account_invalid, ON_OFF_AUTO_AUTO), \ + DEFINE_PROP_ON_OFF_AUTO("account-failed", _state, \ + _conf.account_failed, ON_OFF_AUTO_AUTO) #define DEFINE_BLOCK_PROPERTIES(_state, _conf) \ DEFINE_PROP_DRIVE("drive", _state, _conf.blk), \ diff --git a/include/hw/boards.h b/include/hw/boards.h index d94edcef28..311ed17e18 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -360,7 +360,6 @@ struct MachineState { CpuTopology smp; struct NVDIMMState *nvdimms_state; struct NumaState *numa_state; - CXLFixedMemoryWindowOptionsList *cfmws_list; }; #define DEFINE_MACHINE(namestr, machine_initfn) \ @@ -380,6 +379,9 @@ struct MachineState { } \ type_init(machine_initfn##_register_types) +extern GlobalProperty hw_compat_7_1[]; +extern const size_t hw_compat_7_1_len; + extern GlobalProperty hw_compat_7_0[]; extern const size_t hw_compat_7_0_len; diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 500503da13..f9b58773f7 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -51,6 +51,13 @@ typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, */ #define CPU(obj) ((CPUState *)(obj)) +/* + * The class checkers bring in CPU_GET_CLASS() which is potentially + * expensive given the eventual call to + * object_class_dynamic_cast_assert(). Because of this the CPUState + * has a cached value for the class in cs->cc which is set up in + * cpu_exec_realizefn() for use in hot code paths. + */ typedef struct CPUClass CPUClass; DECLARE_CLASS_CHECKERS(CPUClass, CPU, TYPE_CPU) @@ -108,6 +115,8 @@ struct SysemuCPUOps; * If the target behaviour here is anything other than "set * the PC register to the value passed in" then the target must * also implement the synchronize_from_tb hook. + * @get_pc: Callback for getting the Program Counter register. + * As above, with the semantics of the target architecture. * @gdb_read_register: Callback for letting GDB read a register. * @gdb_write_register: Callback for letting GDB write a register. * @gdb_adjust_breakpoint: Callback for adjusting the address of a @@ -144,6 +153,7 @@ struct CPUClass { void (*dump_state)(CPUState *cpu, FILE *, int flags); int64_t (*get_arch_id)(CPUState *cpu); void (*set_pc)(CPUState *cpu, vaddr value); + vaddr (*get_pc)(CPUState *cpu); int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg); int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg); vaddr (*gdb_adjust_breakpoint)(CPUState *cpu, vaddr addr); @@ -218,7 +228,6 @@ struct CPUWatchpoint { * the memory regions get moved around by io_writex. */ typedef struct SavedIOTLB { - hwaddr addr; MemoryRegionSection *section; hwaddr mr_offset; } SavedIOTLB; @@ -230,9 +239,6 @@ struct kvm_run; struct hax_vcpu_state; struct hvf_vcpu_state; -#define TB_JMP_CACHE_BITS 12 -#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) - /* work queue */ /* The union type allows passing of 64 bit target pointers on 32 bit @@ -317,6 +323,8 @@ struct qemu_work_item; struct CPUState { /*< private >*/ DeviceState parent_obj; + /* cache to avoid expensive CPU_GET_CLASS */ + CPUClass *cc; /*< public >*/ int nr_cores; @@ -361,8 +369,7 @@ struct CPUState { CPUArchState *env_ptr; IcountDecr *icount_decr_ptr; - /* Accessed in parallel; all accesses must be atomic */ - TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; + CPUJumpCache *tb_jmp_cache; struct GDBRegisterState *gdb_regs; int gdb_num_regs; @@ -448,15 +455,6 @@ extern CPUTailQ cpus; extern __thread CPUState *current_cpu; -static inline void cpu_tb_jmp_cache_clear(CPUState *cpu) -{ - unsigned int i; - - for (i = 0; i < TB_JMP_CACHE_SIZE; i++) { - qatomic_set(&cpu->tb_jmp_cache[i], NULL); - } -} - /** * qemu_tcg_mttcg_enabled: * Check whether we are running MultiThread TCG or not. diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index a9ba39e5f2..ee169b872c 100644 --- a/include/hw/core/sysemu-cpu-ops.h +++ b/include/hw/core/sysemu-cpu-ops.h @@ -53,25 +53,25 @@ typedef struct SysemuCPUOps { * 32-bit VM coredump. */ int (*write_elf32_note)(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque); + int cpuid, DumpState *s); /** * @write_elf64_note: Callback for writing a CPU-specific ELF note to a * 64-bit VM coredump. */ int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque); + int cpuid, DumpState *s); /** * @write_elf32_qemunote: Callback for writing a CPU- and QEMU-specific ELF * note to a 32-bit VM coredump. */ int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque); + DumpState *s); /** * @write_elf64_qemunote: Callback for writing a CPU- and QEMU-specific ELF * note to a 64-bit VM coredump. */ int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque); + DumpState *s); /** * @virtio_is_big_endian: Callback to return %true if a CPU which supports * runtime configurable endianness is currently big-endian. diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index 70b5018156..94ec2f07d7 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -215,7 +215,7 @@ uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp); static inline hwaddr cxl_decode_ig(int ig) { - return 1 << (ig + 8); + return 1ULL << (ig + 8); } CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb); diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 1e141b6621..e4d221cdb3 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -237,6 +237,7 @@ struct CXLType3Dev { /* Properties */ HostMemoryBackend *hostmem; HostMemoryBackend *lsa; + uint64_t sn; /* State */ AddressSpace hostmem_as; diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h index 4b7ad77a44..e7d386f7c8 100644 --- a/include/hw/firmware/smbios.h +++ b/include/hw/firmware/smbios.h @@ -189,6 +189,16 @@ struct smbios_type_4 { uint16_t processor_family2; } QEMU_PACKED; +/* SMBIOS type 8 - Port Connector Information */ +struct smbios_type_8 { + struct smbios_structure_header header; + uint8_t internal_reference_str; + uint8_t internal_connector_type; + uint8_t external_reference_str; + uint8_t external_connector_type; + uint8_t port_type; +} QEMU_PACKED; + /* SMBIOS type 11 - OEM strings */ struct smbios_type_11 { struct smbios_structure_header header; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 2a8ffbcfa8..c95333514e 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -118,6 +118,7 @@ struct PCMachineClass { bool has_reserved_memory; bool enforce_aligned_dimm; bool broken_reserved_end; + bool enforce_amd_1tb_hole; /* generate legacy CPU hotplug AML */ bool legacy_cpu_hotplug; @@ -162,7 +163,8 @@ void xen_load_linux(PCMachineState *pcms); void pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, MemoryRegion *rom_memory, - MemoryRegion **ram_memory); + MemoryRegion **ram_memory, + uint64_t pci_hole64_size); uint64_t pc_pci_hole64_start(void); DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); void pc_basic_device_init(struct PCMachineState *pcms, @@ -198,6 +200,9 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, /* sgx.c */ void pc_machine_init_sgx_epc(PCMachineState *pcms); +extern GlobalProperty pc_compat_7_1[]; +extern const size_t pc_compat_7_1_len; + extern GlobalProperty pc_compat_7_0[]; extern const size_t pc_compat_7_0_len; diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index 6bdf1f6ab2..62fa5774f8 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -56,6 +56,9 @@ struct X86MachineState { /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; + /* Start address of the initial RAM above 4G */ + uint64_t above_4g_mem_start; + /* CPU and apic information: */ bool apic_xrupt_override; unsigned pci_irq_mask; diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h index 97e7e59dc5..b17f36df95 100644 --- a/include/hw/ide/internal.h +++ b/include/hw/ide/internal.h @@ -375,6 +375,7 @@ struct IDEState { uint8_t unit; /* ide config */ IDEDriveKind drive_kind; + int drive_heads, drive_sectors; int cylinders, heads, sectors, chs_trans; int64_t nb_sectors; int mult_sectors; @@ -401,6 +402,8 @@ struct IDEState { uint8_t select; uint8_t status; + bool reset_reverts; + /* set for lba48 access */ uint8_t lba48; BlockBackend *blk; diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h index 22dd5e5ac2..4d82e9a3c6 100644 --- a/include/hw/intc/ppc-uic.h +++ b/include/hw/intc/ppc-uic.h @@ -25,8 +25,7 @@ #ifndef HW_INTC_PPC_UIC_H #define HW_INTC_PPC_UIC_H -#include "hw/sysbus.h" -#include "qom/object.h" +#include "hw/ppc/ppc4xx.h" #define TYPE_PPC_UIC "ppc-uic" OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC) @@ -56,14 +55,13 @@ enum { struct PPCUIC { /*< private >*/ - SysBusDevice parent_obj; + Ppc4xxDcrDeviceState parent_obj; /*< public >*/ qemu_irq output_int; qemu_irq output_cint; /* properties */ - CPUState *cpu; uint32_t dcr_base; bool use_vectors; diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h index 26d4048687..693415eb6d 100644 --- a/include/hw/intc/riscv_aclint.h +++ b/include/hw/intc/riscv_aclint.h @@ -32,6 +32,8 @@ typedef struct RISCVAclintMTimerState { /*< private >*/ SysBusDevice parent_obj; uint64_t time_delta; + uint64_t *timecmp; + QEMUTimer **timers; /*< public >*/ MemoryRegion mmio; diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h index f4f24df428..09f1c88ee5 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -15,8 +15,8 @@ #define LOONGARCH_MAX_VCPUS 4 -#define LOONGARCH_ISA_IO_BASE 0x18000000UL -#define LOONGARCH_ISA_IO_SIZE 0x0004000 +#define VIRT_ISA_IO_BASE 0x18000000UL +#define VIRT_ISA_IO_SIZE 0x0004000 #define VIRT_FWCFG_BASE 0x1e020000UL #define VIRT_BIOS_BASE 0x1c000000UL #define VIRT_BIOS_SIZE (4 * MiB) @@ -28,8 +28,8 @@ #define VIRT_GED_MEM_ADDR (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN) #define VIRT_GED_REG_ADDR (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN) -#define LA_FDT_BASE 0x1c400000 -#define LA_FDT_SIZE 0x100000 +#define VIRT_FDT_BASE 0x1c400000 +#define VIRT_FDT_SIZE 0x100000 struct LoongArchMachineState { /*< private >*/ @@ -49,6 +49,8 @@ struct LoongArchMachineState { char *oem_table_id; DeviceState *acpi_ged; int fdt_size; + DeviceState *platform_bus_dev; + PCIBus *pci_bus; }; #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h index cf8f59be44..acf887c83d 100644 --- a/include/hw/mem/nvdimm.h +++ b/include/hw/mem/nvdimm.h @@ -29,14 +29,6 @@ #include "hw/acpi/aml-build.h" #include "qom/object.h" -#define NVDIMM_DEBUG 0 -#define nvdimm_debug(fmt, ...) \ - do { \ - if (NVDIMM_DEBUG) { \ - fprintf(stderr, "nvdimm: " fmt, ## __VA_ARGS__); \ - } \ - } while (0) - /* * The minimum label data size is required by NVDIMM Namespace * specification, see the chapter 2 Namespaces: diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 0e7a8bc7af..e4fef393be 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -117,6 +117,28 @@ struct FWCfgMemState { */ void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len); +/** + * fw_cfg_add_bytes_callback: + * @s: fw_cfg device being modified + * @key: selector key value for new fw_cfg item + * @select_cb: callback function when selecting + * @write_cb: callback function after a write + * @callback_opaque: argument to be passed into callback function + * @data: pointer to start of item data + * @len: size of item data + * @read_only: is file read only + * + * Add a new fw_cfg item, available by selecting the given key, as a raw + * "blob" of the given size. The data referenced by the starting pointer + * is only linked, NOT copied, into the data structure of the fw_cfg device. + */ +void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, + FWCfgCallback select_cb, + FWCfgWriteCallback write_cb, + void *callback_opaque, + void *data, size_t len, + bool read_only); + /** * fw_cfg_add_string: * @s: fw_cfg device being modified diff --git a/include/hw/openrisc/boot.h b/include/hw/openrisc/boot.h new file mode 100644 index 0000000000..25a313d63a --- /dev/null +++ b/include/hw/openrisc/boot.h @@ -0,0 +1,34 @@ +/* + * QEMU OpenRISC boot helpers. + * + * Copyright (c) 2022 Stafford Horne + * + * 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 . + */ + +#ifndef OPENRISC_BOOT_H +#define OPENRISC_BOOT_H + +#include "exec/cpu-defs.h" + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, + const char *kernel_filename, + uint32_t *bootstrap_pc); + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, + hwaddr load_start, uint64_t mem_size); + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size); + +#endif /* OPENRISC_BOOT_H */ diff --git a/include/hw/pci-host/i440fx.h b/include/hw/pci-host/i440fx.h index 52518dbf08..d02bf1ed6b 100644 --- a/include/hw/pci-host/i440fx.h +++ b/include/hw/pci-host/i440fx.h @@ -35,7 +35,8 @@ struct PCII440FXState { #define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX" -PCIBus *i440fx_init(const char *host_type, const char *pci_type, +PCIBus *i440fx_init(const char *pci_type, + DeviceState *dev, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h index 0fdc86b973..9bd875ca8b 100644 --- a/include/hw/pci-host/ls7a.h +++ b/include/hw/pci-host/ls7a.h @@ -15,34 +15,36 @@ #include "qemu/range.h" #include "qom/object.h" -#define LS7A_PCI_MEM_BASE 0x40000000UL -#define LS7A_PCI_MEM_SIZE 0x40000000UL -#define LS7A_PCI_IO_OFFSET 0x4000 -#define LS_PCIECFG_BASE 0x20000000 -#define LS_PCIECFG_SIZE 0x08000000 -#define LS7A_PCI_IO_BASE 0x18004000UL -#define LS7A_PCI_IO_SIZE 0xC000 +#define VIRT_PCI_MEM_BASE 0x40000000UL +#define VIRT_PCI_MEM_SIZE 0x40000000UL +#define VIRT_PCI_IO_OFFSET 0x4000 +#define VIRT_PCI_CFG_BASE 0x20000000 +#define VIRT_PCI_CFG_SIZE 0x08000000 +#define VIRT_PCI_IO_BASE 0x18004000UL +#define VIRT_PCI_IO_SIZE 0xC000 -#define LS7A_PCI_MEM_BASE 0x40000000UL -#define LS7A_PCI_MEM_SIZE 0x40000000UL - -#define LS7A_PCH_REG_BASE 0x10000000UL -#define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE) -#define LS7A_PCH_MSI_ADDR_LOW 0x2FF00000UL +#define VIRT_PCH_REG_BASE 0x10000000UL +#define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE) +#define VIRT_PCH_MSI_ADDR_LOW 0x2FF00000UL /* * According to the kernel pch irq start from 64 offset * 0 ~ 16 irqs used for non-pci device while 16 ~ 64 irqs * used for pci device. */ -#define PCH_PIC_IRQ_OFFSET 64 -#define LS7A_DEVICE_IRQS 16 -#define LS7A_PCI_IRQS 48 -#define LS7A_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2) -#define LS7A_UART_BASE 0x1fe001e0 -#define LS7A_RTC_IRQ (PCH_PIC_IRQ_OFFSET + 3) -#define LS7A_MISC_REG_BASE (LS7A_PCH_REG_BASE + 0x00080000) -#define LS7A_RTC_REG_BASE (LS7A_MISC_REG_BASE + 0x00050100) -#define LS7A_RTC_LEN 0x100 -#define LS7A_SCI_IRQ (PCH_PIC_IRQ_OFFSET + 4) +#define PCH_PIC_IRQ_OFFSET 64 +#define VIRT_DEVICE_IRQS 16 +#define VIRT_PCI_IRQS 48 +#define VIRT_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2) +#define VIRT_UART_BASE 0x1fe001e0 +#define VIRT_RTC_IRQ (PCH_PIC_IRQ_OFFSET + 3) +#define VIRT_MISC_REG_BASE (VIRT_PCH_REG_BASE + 0x00080000) +#define VIRT_RTC_REG_BASE (VIRT_MISC_REG_BASE + 0x00050100) +#define VIRT_RTC_LEN 0x100 +#define VIRT_SCI_IRQ (PCH_PIC_IRQ_OFFSET + 4) + +#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000 +#define VIRT_PLATFORM_BUS_SIZE 0x2000000 +#define VIRT_PLATFORM_BUS_NUM_IRQS 2 +#define VIRT_PLATFORM_BUS_IRQ 69 #endif diff --git a/include/hw/pci-host/pnv_phb3.h b/include/hw/pci-host/pnv_phb3.h index af6ec83cf6..4854f6d2f6 100644 --- a/include/hw/pci-host/pnv_phb3.h +++ b/include/hw/pci-host/pnv_phb3.h @@ -14,6 +14,7 @@ #include "hw/pci/pcie_port.h" #include "hw/ppc/xics.h" #include "qom/object.h" +#include "hw/pci-host/pnv_phb.h" typedef struct PnvPHB3 PnvPHB3; typedef struct PnvChip PnvChip; @@ -103,15 +104,16 @@ struct PnvPBCQState { }; /* - * PHB3 PCIe Root port + * PHB3 PCIe Root Bus */ #define TYPE_PNV_PHB3_ROOT_BUS "pnv-phb3-root" +struct PnvPHB3RootBus { + PCIBus parent; -#define TYPE_PNV_PHB3_ROOT_PORT "pnv-phb3-root-port" - -typedef struct PnvPHB3RootPort { - PCIESlot parent_obj; -} PnvPHB3RootPort; + uint32_t chip_id; + uint32_t phb_id; +}; +OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB3RootBus, PNV_PHB3_ROOT_BUS) /* * PHB3 PCIe Host Bridge for PowerNV machines (POWER8) @@ -127,7 +129,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB3, PNV_PHB3) #define PCI_MMIO_TOTAL_SIZE (0x1ull << 60) struct PnvPHB3 { - PCIExpressHost parent_obj; + DeviceState parent; + + PnvPHB *phb_base; uint32_t chip_id; uint32_t phb_id; @@ -164,5 +168,6 @@ uint64_t pnv_phb3_reg_read(void *opaque, hwaddr off, unsigned size); void pnv_phb3_reg_write(void *opaque, hwaddr off, uint64_t val, unsigned size); void pnv_phb3_update_regions(PnvPHB3 *phb); void pnv_phb3_remap_irqs(PnvPHB3 *phb); +void pnv_phb3_bus_init(DeviceState *dev, PnvPHB3 *phb); #endif /* PCI_HOST_PNV_PHB3_H */ diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h index 19dcbd6f87..50d4faa001 100644 --- a/include/hw/pci-host/pnv_phb4.h +++ b/include/hw/pci-host/pnv_phb4.h @@ -18,6 +18,7 @@ typedef struct PnvPhb4PecState PnvPhb4PecState; typedef struct PnvPhb4PecStack PnvPhb4PecStack; typedef struct PnvPHB4 PnvPHB4; +typedef struct PnvPHB PnvPHB; typedef struct PnvChip PnvChip; /* @@ -45,15 +46,16 @@ typedef struct PnvPhb4DMASpace { } PnvPhb4DMASpace; /* - * PHB4 PCIe Root port + * PHB4 PCIe Root Bus */ #define TYPE_PNV_PHB4_ROOT_BUS "pnv-phb4-root" -#define TYPE_PNV_PHB4_ROOT_PORT "pnv-phb4-root-port" -#define TYPE_PNV_PHB5_ROOT_PORT "pnv-phb5-root-port" +struct PnvPHB4RootBus { + PCIBus parent; -typedef struct PnvPHB4RootPort { - PCIESlot parent_obj; -} PnvPHB4RootPort; + uint32_t chip_id; + uint32_t phb_id; +}; +OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4RootBus, PNV_PHB4_ROOT_BUS) /* * PHB4 PCIe Host Bridge for PowerNV machines (POWER9) @@ -78,13 +80,13 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4) #define PCI_MMIO_TOTAL_SIZE (0x1ull << 60) struct PnvPHB4 { - PCIExpressHost parent_obj; + DeviceState parent; + + PnvPHB *phb_base; uint32_t chip_id; uint32_t phb_id; - uint64_t version; - /* The owner PEC */ PnvPhb4PecState *pec; @@ -157,6 +159,7 @@ struct PnvPHB4 { void pnv_phb4_pic_print_info(PnvPHB4 *phb, Monitor *mon); int pnv_phb4_pec_get_phb_id(PnvPhb4PecState *pec, int stack_index); +void pnv_phb4_bus_init(DeviceState *dev, PnvPHB4 *phb); extern const MemoryRegionOps pnv_phb4_xscom_ops; /* @@ -205,7 +208,6 @@ struct PnvPhb4PecClass { uint64_t version; const char *phb_type; const uint32_t *num_phbs; - const char *rp_model; }; /* diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index b54b6ef88f..97937cc922 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -688,60 +688,44 @@ static inline void pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg) { uint8_t val = pci_get_byte(config); - uint8_t rval = reg << ctz32(mask); - pci_set_byte(config, (~mask & val) | (mask & rval)); -} + uint8_t rval; -static inline uint8_t -pci_get_byte_by_mask(uint8_t *config, uint8_t mask) -{ - uint8_t val = pci_get_byte(config); - return (val & mask) >> ctz32(mask); + assert(mask); + rval = reg << ctz32(mask); + pci_set_byte(config, (~mask & val) | (mask & rval)); } static inline void pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg) { uint16_t val = pci_get_word(config); - uint16_t rval = reg << ctz32(mask); - pci_set_word(config, (~mask & val) | (mask & rval)); -} + uint16_t rval; -static inline uint16_t -pci_get_word_by_mask(uint8_t *config, uint16_t mask) -{ - uint16_t val = pci_get_word(config); - return (val & mask) >> ctz32(mask); + assert(mask); + rval = reg << ctz32(mask); + pci_set_word(config, (~mask & val) | (mask & rval)); } static inline void pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg) { uint32_t val = pci_get_long(config); - uint32_t rval = reg << ctz32(mask); - pci_set_long(config, (~mask & val) | (mask & rval)); -} + uint32_t rval; -static inline uint32_t -pci_get_long_by_mask(uint8_t *config, uint32_t mask) -{ - uint32_t val = pci_get_long(config); - return (val & mask) >> ctz32(mask); + assert(mask); + rval = reg << ctz32(mask); + pci_set_long(config, (~mask & val) | (mask & rval)); } static inline void pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg) { uint64_t val = pci_get_quad(config); - uint64_t rval = reg << ctz32(mask); - pci_set_quad(config, (~mask & val) | (mask & rval)); -} + uint64_t rval; -static inline uint64_t -pci_get_quad_by_mask(uint8_t *config, uint64_t mask) -{ - uint64_t val = pci_get_quad(config); - return (val & mask) >> ctz32(mask); + assert(mask); + rval = reg << ctz32(mask); + pci_set_quad(config, (~mask & val) | (mask & rval)); } PCIDevice *pci_new_multifunction(int devfn, bool multifunction, diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index b991194223..9ef7e2d0dc 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -27,11 +27,13 @@ #include "hw/ppc/pnv_pnor.h" #include "hw/ppc/pnv_psi.h" #include "hw/ppc/pnv_occ.h" +#include "hw/ppc/pnv_sbe.h" #include "hw/ppc/pnv_homer.h" #include "hw/ppc/pnv_xive.h" #include "hw/ppc/pnv_core.h" #include "hw/pci-host/pnv_phb3.h" #include "hw/pci-host/pnv_phb4.h" +#include "hw/pci-host/pnv_phb.h" #include "qom/object.h" #define TYPE_PNV_CHIP "pnv-chip" @@ -80,7 +82,11 @@ struct Pnv8Chip { PnvHomer homer; #define PNV8_CHIP_PHB3_MAX 4 - PnvPHB3 phbs[PNV8_CHIP_PHB3_MAX]; + /* + * The array is used to allow quick access to the phbs by + * pnv_ics_get_child() and pnv_ics_resend_child(). + */ + PnvPHB *phbs[PNV8_CHIP_PHB3_MAX]; uint32_t num_phbs; XICSFabric *xics; @@ -100,6 +106,7 @@ struct Pnv9Chip { Pnv9Psi psi; PnvLpcController lpc; PnvOCC occ; + PnvSBE sbe; PnvHomer homer; uint32_t nr_quads; @@ -129,6 +136,7 @@ struct Pnv10Chip { Pnv9Psi psi; PnvLpcController lpc; PnvOCC occ; + PnvSBE sbe; PnvHomer homer; uint32_t nr_quads; @@ -189,8 +197,6 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10, TYPE_PNV_CHIP_POWER10) PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir); -void pnv_phb_attach_root_port(PCIHostState *pci, const char *name, - int index, int chip_id); #define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv") typedef struct PnvMachineClass PnvMachineClass; @@ -232,6 +238,7 @@ struct PnvMachineState { }; PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id); +Object *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp); #define PNV_FDT_ADDR 0x01000000 #define PNV_TIMEBASE_FREQ 512000000ULL diff --git a/include/hw/ppc/pnv_sbe.h b/include/hw/ppc/pnv_sbe.h new file mode 100644 index 0000000000..f54a3ae9ba --- /dev/null +++ b/include/hw/ppc/pnv_sbe.h @@ -0,0 +1,55 @@ +/* + * QEMU PowerPC PowerNV Emulation of some SBE behaviour + * + * Copyright (c) 2022, IBM Corporation. + * + * 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.1 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 . + */ + +#ifndef PPC_PNV_SBE_H +#define PPC_PNV_SBE_H + +#include "qom/object.h" + +#define TYPE_PNV_SBE "pnv-sbe" +OBJECT_DECLARE_TYPE(PnvSBE, PnvSBEClass, PNV_SBE) +#define TYPE_PNV9_SBE TYPE_PNV_SBE "-POWER9" +DECLARE_INSTANCE_CHECKER(PnvSBE, PNV9_SBE, TYPE_PNV9_SBE) +#define TYPE_PNV10_SBE TYPE_PNV_SBE "-POWER10" +DECLARE_INSTANCE_CHECKER(PnvSBE, PNV10_SBE, TYPE_PNV10_SBE) + +struct PnvSBE { + DeviceState xd; + + uint64_t mbox[8]; + uint64_t sbe_doorbell; + uint64_t host_doorbell; + + qemu_irq psi_irq; + QEMUTimer *timer; + + MemoryRegion xscom_mbox_regs; + MemoryRegion xscom_ctrl_regs; +}; + +struct PnvSBEClass { + DeviceClass parent_class; + + int xscom_ctrl_size; + int xscom_mbox_size; + const MemoryRegionOps *xscom_ctrl_ops; + const MemoryRegionOps *xscom_mbox_ops; +}; + +#endif /* PPC_PNV_SBE_H */ diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 7c7440de0c..c6e9ef8dd2 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -92,6 +92,12 @@ struct PnvXScomInterfaceClass { #define PNV9_XSCOM_OCC_BASE PNV_XSCOM_OCC_BASE #define PNV9_XSCOM_OCC_SIZE 0x8000 +#define PNV9_XSCOM_SBE_CTRL_BASE 0x00050008 +#define PNV9_XSCOM_SBE_CTRL_SIZE 0x1 + +#define PNV9_XSCOM_SBE_MBOX_BASE 0x000D0050 +#define PNV9_XSCOM_SBE_MBOX_SIZE 0x16 + #define PNV9_XSCOM_PBA_BASE 0x5012b00 #define PNV9_XSCOM_PBA_SIZE 0x40 @@ -134,6 +140,12 @@ struct PnvXScomInterfaceClass { #define PNV10_XSCOM_OCC_BASE PNV9_XSCOM_OCC_BASE #define PNV10_XSCOM_OCC_SIZE PNV9_XSCOM_OCC_SIZE +#define PNV10_XSCOM_SBE_CTRL_BASE PNV9_XSCOM_SBE_CTRL_BASE +#define PNV10_XSCOM_SBE_CTRL_SIZE PNV9_XSCOM_SBE_CTRL_SIZE + +#define PNV10_XSCOM_SBE_MBOX_BASE PNV9_XSCOM_SBE_MBOX_BASE +#define PNV10_XSCOM_SBE_MBOX_SIZE PNV9_XSCOM_SBE_MBOX_SIZE + #define PNV10_XSCOM_PBA_BASE 0x01010CDA #define PNV10_XSCOM_PBA_SIZE 0x40 diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h index 980f964b5a..a1781afa8e 100644 --- a/include/hw/ppc/ppc4xx.h +++ b/include/hw/ppc/ppc4xx.h @@ -27,11 +27,7 @@ #include "hw/ppc/ppc.h" #include "exec/memory.h" - -/* PowerPC 4xx core initialization */ -PowerPCCPU *ppc4xx_init(const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk); +#include "hw/sysbus.h" void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, MemoryRegion ram_memories[], @@ -44,9 +40,73 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, hwaddr *ram_sizes, int do_init); -void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum, - qemu_irq irqs[4]); - #define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" +/* + * Generic DCR device + */ +#define TYPE_PPC4xx_DCR_DEVICE "ppc4xx-dcr-device" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxDcrDeviceState, PPC4xx_DCR_DEVICE); +struct Ppc4xxDcrDeviceState { + SysBusDevice parent_obj; + + PowerPCCPU *cpu; +}; + +void ppc4xx_dcr_register(Ppc4xxDcrDeviceState *dev, int dcrn, void *opaque, + dcr_read_cb dcr_read, dcr_write_cb dcr_write); +bool ppc4xx_dcr_realize(Ppc4xxDcrDeviceState *dev, PowerPCCPU *cpu, + Error **errp); + +/* Memory Access Layer (MAL) */ +#define TYPE_PPC4xx_MAL "ppc4xx-mal" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxMalState, PPC4xx_MAL); +struct Ppc4xxMalState { + Ppc4xxDcrDeviceState parent_obj; + + qemu_irq irqs[4]; + uint32_t cfg; + uint32_t esr; + uint32_t ier; + uint32_t txcasr; + uint32_t txcarr; + uint32_t txeobisr; + uint32_t txdeir; + uint32_t rxcasr; + uint32_t rxcarr; + uint32_t rxeobisr; + uint32_t rxdeir; + uint32_t *txctpr; + uint32_t *rxctpr; + uint32_t *rcbs; + uint8_t txcnum; + uint8_t rxcnum; +}; + +/* Peripheral local bus arbitrer */ +#define TYPE_PPC4xx_PLB "ppc4xx-plb" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxPlbState, PPC4xx_PLB); +struct Ppc4xxPlbState { + Ppc4xxDcrDeviceState parent_obj; + + uint32_t acr; + uint32_t bear; + uint32_t besr; +}; + +/* Peripheral controller */ +#define TYPE_PPC4xx_EBC "ppc4xx-ebc" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxEbcState, PPC4xx_EBC); +struct Ppc4xxEbcState { + Ppc4xxDcrDeviceState parent_obj; + + uint32_t addr; + uint32_t bcr[8]; + uint32_t bap[8]; + uint32_t bear; + uint32_t besr0; + uint32_t besr1; + uint32_t cfg; +}; + #endif /* PPC4XX_H */ diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 530d739b1d..04a95669ab 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -848,7 +848,8 @@ static inline uint64_t ppc64_phys_to_real(uint64_t addr) static inline uint32_t rtas_ld(target_ulong phys, int n) { - return ldl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n)); + return ldl_be_phys(&address_space_memory, + ppc64_phys_to_real(phys + 4 * n)); } static inline uint64_t rtas_ldq(target_ulong phys, int n) @@ -858,7 +859,7 @@ static inline uint64_t rtas_ldq(target_ulong phys, int n) static inline void rtas_st(target_ulong phys, int n, uint32_t val) { - stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val); + stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4 * n), val); } typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, SpaprMachineState *sm, diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 98774e2835..785dd5a56e 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -386,7 +386,7 @@ bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp); * * - unrealize any child buses by calling qbus_unrealize() * (this will recursively unrealize any devices on those buses) - * - call the the unrealize method of @dev + * - call the unrealize method of @dev * * The device can then be freed by causing its reference count to go * to zero. diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index d2db29721a..a36f7618f5 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -51,7 +51,7 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts hwaddr saddr, hwaddr rom_base, hwaddr rom_size, uint64_t kernel_entry, - uint64_t fdt_load_addr, void *fdt); + uint64_t fdt_load_addr); void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base, hwaddr rom_size, uint32_t reset_vec_size, diff --git a/include/hw/riscv/microchip_pfsoc.h b/include/hw/riscv/microchip_pfsoc.h index a0673f5f59..a757b240e0 100644 --- a/include/hw/riscv/microchip_pfsoc.h +++ b/include/hw/riscv/microchip_pfsoc.h @@ -88,8 +88,11 @@ enum { MICROCHIP_PFSOC_L2LIM, MICROCHIP_PFSOC_PLIC, MICROCHIP_PFSOC_MMUART0, + MICROCHIP_PFSOC_WDOG0, MICROCHIP_PFSOC_SYSREG, + MICROCHIP_PFSOC_AXISW, MICROCHIP_PFSOC_MPUCFG, + MICROCHIP_PFSOC_FMETER, MICROCHIP_PFSOC_DDR_SGMII_PHY, MICROCHIP_PFSOC_EMMC_SD, MICROCHIP_PFSOC_DDR_CFG, @@ -97,19 +100,28 @@ enum { MICROCHIP_PFSOC_MMUART2, MICROCHIP_PFSOC_MMUART3, MICROCHIP_PFSOC_MMUART4, + MICROCHIP_PFSOC_WDOG1, + MICROCHIP_PFSOC_WDOG2, + MICROCHIP_PFSOC_WDOG3, + MICROCHIP_PFSOC_WDOG4, MICROCHIP_PFSOC_SPI0, MICROCHIP_PFSOC_SPI1, + MICROCHIP_PFSOC_I2C0, MICROCHIP_PFSOC_I2C1, + MICROCHIP_PFSOC_CAN0, + MICROCHIP_PFSOC_CAN1, MICROCHIP_PFSOC_GEM0, MICROCHIP_PFSOC_GEM1, MICROCHIP_PFSOC_GPIO0, MICROCHIP_PFSOC_GPIO1, MICROCHIP_PFSOC_GPIO2, + MICROCHIP_PFSOC_RTC, MICROCHIP_PFSOC_ENVM_CFG, MICROCHIP_PFSOC_ENVM_DATA, + MICROCHIP_PFSOC_USB, MICROCHIP_PFSOC_QSPI_XIP, MICROCHIP_PFSOC_IOSCB, - MICROCHIP_PFSOC_EMMC_SD_MUX, + MICROCHIP_PFSOC_FABRIC_FIC3, MICROCHIP_PFSOC_DRAM_LO, MICROCHIP_PFSOC_DRAM_LO_ALIAS, MICROCHIP_PFSOC_DRAM_HI, diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index 68892cd8e5..6665cd5794 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -46,6 +46,8 @@ struct LowRISCIbexSoCState { IbexTimerState timer; IbexSPIHostState spi_host[OPENTITAN_NUM_SPI_HOSTS]; + uint32_t resetvec; + MemoryRegion flash_mem; MemoryRegion rom; MemoryRegion flash_alias; @@ -74,6 +76,7 @@ enum { IBEX_DEV_TIMER, IBEX_DEV_SENSOR_CTRL, IBEX_DEV_OTP_CTRL, + IBEX_DEV_LC_CTRL, IBEX_DEV_PWRMGR, IBEX_DEV_RSTMGR, IBEX_DEV_CLKMGR, @@ -105,11 +108,11 @@ enum { IBEX_UART0_RX_BREAK_ERR_IRQ = 6, IBEX_UART0_RX_TIMEOUT_IRQ = 7, IBEX_UART0_RX_PARITY_ERR_IRQ = 8, - IBEX_TIMER_TIMEREXPIRED0_0 = 126, - IBEX_SPI_HOST0_ERR_IRQ = 150, - IBEX_SPI_HOST0_SPI_EVENT_IRQ = 151, - IBEX_SPI_HOST1_ERR_IRQ = 152, - IBEX_SPI_HOST1_SPI_EVENT_IRQ = 153, + IBEX_TIMER_TIMEREXPIRED0_0 = 127, + IBEX_SPI_HOST0_ERR_IRQ = 151, + IBEX_SPI_HOST0_SPI_EVENT_IRQ = 152, + IBEX_SPI_HOST1_ERR_IRQ = 153, + IBEX_SPI_HOST1_SPI_EVENT_IRQ = 154, }; #endif diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index 83604da805..d738745925 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -22,6 +22,7 @@ #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_cpu.h" #include "hw/gpio/sifive_gpio.h" +#include "hw/boards.h" #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc" #define RISCV_E_SOC(obj) \ @@ -41,7 +42,7 @@ typedef struct SiFiveESoCState { typedef struct SiFiveEState { /*< private >*/ - SysBusDevice parent_obj; + MachineState parent_obj; /*< public >*/ SiFiveESoCState soc; diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 984e55c77f..be4ab8fe7f 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -111,6 +111,7 @@ enum { #define FDT_PCI_ADDR_CELLS 3 #define FDT_PCI_INT_CELLS 1 +#define FDT_PLIC_ADDR_CELLS 0 #define FDT_PLIC_INT_CELLS 1 #define FDT_APLIC_INT_CELLS 2 #define FDT_IMSIC_INT_CELLS 0 diff --git a/include/hw/rtc/goldfish_rtc.h b/include/hw/rtc/goldfish_rtc.h index 79ca7daf5d..162be33863 100644 --- a/include/hw/rtc/goldfish_rtc.h +++ b/include/hw/rtc/goldfish_rtc.h @@ -42,6 +42,8 @@ struct GoldfishRTCState { uint32_t irq_pending; uint32_t irq_enabled; uint32_t time_high; + + bool big_endian; }; #endif diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index da3cde2bb4..0605fcea24 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -315,13 +315,16 @@ typedef struct ZpciFmb { QEMU_BUILD_BUG_MSG(offsetof(ZpciFmb, fmt0) != 48, "padding in ZpciFmb"); #define ZPCI_DEFAULT_FN_GRP 0xFF +#define ZPCI_SIM_GRP_START 0xF0 typedef struct S390PCIGroup { ClpRspQueryPciGrp zpci_group; int id; + int host_id; QTAILQ_ENTRY(S390PCIGroup) link; } S390PCIGroup; -S390PCIGroup *s390_group_create(int id); +S390PCIGroup *s390_group_create(int id, int host_id); S390PCIGroup *s390_group_find(int id); +S390PCIGroup *s390_group_find_host_sim(int host_id); struct S390PCIBusDevice { DeviceState qdev; @@ -350,6 +353,8 @@ struct S390PCIBusDevice { IndAddr *indicator; bool pci_unplug_request_processed; bool unplug_requested; + bool interp; + bool forwarding_assist; QTAILQ_ENTRY(S390PCIBusDevice) link; }; @@ -368,6 +373,7 @@ struct S390pciState { QTAILQ_HEAD(, S390PCIBusDevice) zpci_devs; QTAILQ_HEAD(, S390PCIDMACount) zpci_dma_limit; QTAILQ_HEAD(, S390PCIGroup) zpci_groups; + uint8_t next_sim_grp; }; S390pciState *s390_get_phb(void); diff --git a/include/hw/s390x/s390-pci-kvm.h b/include/hw/s390x/s390-pci-kvm.h new file mode 100644 index 0000000000..933814a402 --- /dev/null +++ b/include/hw/s390x/s390-pci-kvm.h @@ -0,0 +1,38 @@ +/* + * s390 PCI KVM interfaces + * + * Copyright 2022 IBM Corp. + * Author(s): Matthew Rosato + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef HW_S390_PCI_KVM_H +#define HW_S390_PCI_KVM_H + +#include "hw/s390x/s390-pci-bus.h" +#include "hw/s390x/s390-pci-inst.h" + +#ifdef CONFIG_KVM +bool s390_pci_kvm_interp_allowed(void); +int s390_pci_kvm_aif_enable(S390PCIBusDevice *pbdev, ZpciFib *fib, bool assist); +int s390_pci_kvm_aif_disable(S390PCIBusDevice *pbdev); +#else +static inline bool s390_pci_kvm_interp_allowed(void) +{ + return false; +} +static inline int s390_pci_kvm_aif_enable(S390PCIBusDevice *pbdev, ZpciFib *fib, + bool assist) +{ + return -EINVAL; +} +static inline int s390_pci_kvm_aif_disable(S390PCIBusDevice *pbdev) +{ + return -EINVAL; +} +#endif + +#endif diff --git a/include/hw/s390x/s390-pci-vfio.h b/include/hw/s390x/s390-pci-vfio.h index ff708aef50..ae1b126ff7 100644 --- a/include/hw/s390x/s390-pci-vfio.h +++ b/include/hw/s390x/s390-pci-vfio.h @@ -20,6 +20,7 @@ bool s390_pci_update_dma_avail(int fd, unsigned int *avail); S390PCIDMACount *s390_pci_start_dma_count(S390pciState *s, S390PCIBusDevice *pbdev); void s390_pci_end_dma_count(S390pciState *s, S390PCIDMACount *cnt); +bool s390_pci_get_host_fh(S390PCIBusDevice *pbdev, uint32_t *fh); void s390_pci_get_clp_info(S390PCIBusDevice *pbdev); #else static inline bool s390_pci_update_dma_avail(int fd, unsigned int *avail) @@ -33,6 +34,10 @@ static inline S390PCIDMACount *s390_pci_start_dma_count(S390pciState *s, } static inline void s390_pci_end_dma_count(S390pciState *s, S390PCIDMACount *cnt) { } +static inline bool s390_pci_get_host_fh(S390PCIBusDevice *pbdev, uint32_t *fh) +{ + return false; +} static inline void s390_pci_get_clp_info(S390PCIBusDevice *pbdev) { } #endif diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index 3331990e02..8a0090a071 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -27,6 +27,7 @@ struct S390CcwMachineState { bool aes_key_wrap; bool dea_key_wrap; bool pv; + bool zpcii_disable; uint8_t loadparm[8]; }; diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index e284e3a4ec..001103488c 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -59,7 +59,7 @@ struct SCSIDeviceClass { void (*realize)(SCSIDevice *dev, Error **errp); void (*unrealize)(SCSIDevice *dev); int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, - void *hba_private); + size_t buf_len, void *hba_private); SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun, uint8_t *buf, void *hba_private); void (*unit_attention_reported)(SCSIDevice *s); @@ -122,7 +122,7 @@ struct SCSIBusInfo { int tcq; int max_channel, max_target, max_lun; int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, - void *hba_private); + size_t buf_len, void *hba_private); void (*transfer_data)(SCSIRequest *req, uint32_t arg); void (*fail)(SCSIRequest *req); void (*complete)(SCSIRequest *req, size_t residual); @@ -192,14 +192,15 @@ void scsi_legacy_handle_cmdline(void); SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag, uint32_t lun, void *hba_private); SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, - uint8_t *buf, void *hba_private); + uint8_t *buf, size_t buf_len, void *hba_private); int32_t scsi_req_enqueue(SCSIRequest *req); SCSIRequest *scsi_req_ref(SCSIRequest *req); void scsi_req_unref(SCSIRequest *req); int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, - void *hba_private); -int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf); + size_t buf_len, void *hba_private); +int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf, + size_t buf_len); void scsi_req_build_sense(SCSIRequest *req, SCSISense sense); void scsi_req_print(SCSIRequest *req); void scsi_req_continue(SCSIRequest *req); diff --git a/include/hw/timer/ibex_timer.h b/include/hw/timer/ibex_timer.h index 1a0a28d5fa..41f5c82a92 100644 --- a/include/hw/timer/ibex_timer.h +++ b/include/hw/timer/ibex_timer.h @@ -33,6 +33,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IbexTimerState, IBEX_TIMER) struct IbexTimerState { /* */ SysBusDevice parent_obj; + uint64_t mtimecmp; + QEMUTimer *mtimer; /* Internal timer for M-mode interrupt */ /* */ MemoryRegion mmio; diff --git a/include/hw/usb/msd.h b/include/hw/usb/msd.h index 54e9f38bda..f9fd862b52 100644 --- a/include/hw/usb/msd.h +++ b/include/hw/usb/msd.h @@ -40,6 +40,7 @@ struct MSDState { bool removable; bool commandlog; SCSIDevice *scsi_dev; + bool needs_reset; }; typedef struct MSDState MSDState; diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h index 7c91f15040..ea085ee1ed 100644 --- a/include/hw/virtio/vhost-user-blk.h +++ b/include/hw/virtio/vhost-user-blk.h @@ -34,7 +34,6 @@ struct VHostUserBlk { struct virtio_blk_config blkcfg; uint16_t num_queues; uint32_t queue_size; - uint32_t config_wce; struct vhost_dev dev; struct vhost_inflight *inflight; VhostUserState vhost_user; diff --git a/include/hw/virtio/vhost-user-gpio.h b/include/hw/virtio/vhost-user-gpio.h new file mode 100644 index 0000000000..4fe9aeecc0 --- /dev/null +++ b/include/hw/virtio/vhost-user-gpio.h @@ -0,0 +1,35 @@ +/* + * Vhost-user GPIO virtio device + * + * Copyright (c) 2021 Viresh Kumar + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef _QEMU_VHOST_USER_GPIO_H +#define _QEMU_VHOST_USER_GPIO_H + +#include "hw/virtio/virtio.h" +#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-user.h" +#include "standard-headers/linux/virtio_gpio.h" +#include "chardev/char-fe.h" + +#define TYPE_VHOST_USER_GPIO "vhost-user-gpio-device" +OBJECT_DECLARE_SIMPLE_TYPE(VHostUserGPIO, VHOST_USER_GPIO); + +struct VHostUserGPIO { + /*< private >*/ + VirtIODevice parent_obj; + CharBackend chardev; + struct virtio_gpio_config config; + struct vhost_virtqueue *vhost_vq; + struct vhost_dev vhost_dev; + VhostUserState vhost_user; + VirtQueue *command_vq; + VirtQueue *interrupt_vq; + bool connected; + /*< public >*/ +}; + +#endif /* _QEMU_VHOST_USER_GPIO_H */ diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h index d10a89303e..1111d85643 100644 --- a/include/hw/virtio/vhost-vdpa.h +++ b/include/hw/virtio/vhost-vdpa.h @@ -35,7 +35,6 @@ typedef struct vhost_vdpa { bool shadow_vqs_enabled; /* IOVA mapping used by the Shadow Virtqueue */ VhostIOVATree *iova_tree; - Error *migration_blocker; GPtrArray *shadow_vqs; const VhostShadowVirtqueueOps *shadow_vq_ops; void *shadow_vq_ops_opaque; diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index a346f23d13..d7eb557885 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -5,6 +5,9 @@ #include "hw/virtio/virtio.h" #include "exec/memory.h" +#define VHOST_F_DEVICE_IOTLB 63 +#define VHOST_USER_F_PROTOCOL_FEATURES 30 + /* Generic structures common for any vhost based device. */ struct vhost_inflight { @@ -86,11 +89,15 @@ struct vhost_dev { /* if non-zero, minimum required value for max_queues */ int num_queues; uint64_t features; + /** @acked_features: final set of negotiated features */ uint64_t acked_features; + /** @backend_features: backend specific feature bits */ uint64_t backend_features; + /** @protocol_features: final negotiated protocol features */ uint64_t protocol_features; uint64_t max_queues; uint64_t backend_cap; + /* @started: is the vhost device started? */ bool started; bool log_enabled; uint64_t log_size; @@ -162,6 +169,17 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); */ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); +/** + * vhost_dev_is_started() - report status of vhost device + * @hdev: common vhost_dev structure + * + * Return the started status of the vhost device + */ +static inline bool vhost_dev_is_started(struct vhost_dev *hdev) +{ + return hdev->started; +} + /** * vhost_dev_start() - start the vhost device * @hdev: common vhost_dev structure diff --git a/include/hw/virtio/virtio-blk-common.h b/include/hw/virtio/virtio-blk-common.h new file mode 100644 index 0000000000..31daada3e3 --- /dev/null +++ b/include/hw/virtio/virtio-blk-common.h @@ -0,0 +1,20 @@ +/* + * Virtio Block Device common helpers + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef VIRTIO_BLK_COMMON_H +#define VIRTIO_BLK_COMMON_H + +#include "hw/virtio/virtio.h" + +extern const VirtIOConfigSizeParams virtio_blk_cfg_size_params; + +#endif diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index db1c0ddf6b..f41b4a7e64 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -24,7 +24,12 @@ #include "qom/object.h" #include "hw/virtio/vhost.h" -/* A guest should never accept this. It implies negotiation is broken. */ +/* + * A guest should never accept this. It implies negotiation is broken + * between the driver frontend and the device. This bit is re-used for + * vhost-user to advertise VHOST_USER_F_PROTOCOL_FEATURES between QEMU + * and a vhost-user backend. + */ #define VIRTIO_F_BAD_FEATURE 30 #define VIRTIO_LEGACY_FEATURES ((0x1ULL << VIRTIO_F_BAD_FEATURE) | \ @@ -44,8 +49,14 @@ typedef struct VirtIOFeature { size_t end; } VirtIOFeature; -size_t virtio_feature_get_config_size(const VirtIOFeature *features, - uint64_t host_features); +typedef struct VirtIOConfigSizeParams { + size_t min_size; + size_t max_size; + const VirtIOFeature *feature_sizes; +} VirtIOConfigSizeParams; + +size_t virtio_get_config_size(const VirtIOConfigSizeParams *params, + uint64_t host_features); typedef struct VirtQueue VirtQueue; @@ -71,6 +82,11 @@ typedef struct VirtQueueElement #define TYPE_VIRTIO_DEVICE "virtio-device" OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE) +typedef struct { + int virtio_bit; + const char *feature_desc; +} qmp_virtio_feature_map_t; + enum virtio_device_endian { VIRTIO_DEVICE_ENDIAN_UNKNOWN, VIRTIO_DEVICE_ENDIAN_LITTLE, @@ -95,6 +111,7 @@ struct VirtIODevice VirtQueue *vq; MemoryListener listener; uint16_t device_id; + /* @vm_running: current VM running state via virtio_vmstate_change() */ bool vm_running; bool broken; /* device in invalid state, needs reset */ bool use_disabled_flag; /* allow use of 'disable' flag when needed */ @@ -110,6 +127,7 @@ struct VirtIODevice bool use_guest_notifier_mask; AddressSpace *dma_as; QLIST_HEAD(, VirtQueue) *vector_queues; + QTAILQ_ENTRY(VirtIODevice) next; }; struct VirtioDeviceClass { @@ -371,6 +389,10 @@ static inline bool virtio_device_started(VirtIODevice *vdev, uint8_t status) return vdev->started; } + if (!vdev->vm_running) { + return false; + } + return status & VIRTIO_CONFIG_S_DRIVER_OK; } diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index a618eb1e4e..a9cf064ee8 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -95,6 +95,11 @@ 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 hmp_virtio_query(Monitor *mon, const QDict *qdict); +void hmp_virtio_status(Monitor *mon, const QDict *qdict); +void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict); +void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict); +void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict); void object_add_completion(ReadLineState *rs, int nb_args, const char *str); void object_del_completion(ReadLineState *rs, int nb_args, const char *str); void device_add_completion(ReadLineState *rs, int nb_args, const char *str); diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index a4b40e8391..737e750670 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -31,6 +31,7 @@ void monitor_resume(Monitor *mon); int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp); int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp); +int monitor_puts(Monitor *mon, const char *str); int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); int monitor_printf(Monitor *mon, const char *fmt, ...) G_GNUC_PRINTF(2, 3); diff --git a/include/net/net.h b/include/net/net.h index 523136c7ac..81d0b21def 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -44,6 +44,9 @@ typedef struct NICConf { typedef void (NetPoll)(NetClientState *, bool enable); typedef bool (NetCanReceive)(NetClientState *); +typedef int (NetStart)(NetClientState *); +typedef int (NetLoad)(NetClientState *); +typedef void (NetStop)(NetClientState *); typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); typedef void (NetCleanup) (NetClientState *); @@ -71,6 +74,9 @@ typedef struct NetClientInfo { NetReceive *receive_raw; NetReceiveIOV *receive_iov; NetCanReceive *can_receive; + NetStart *start; + NetLoad *load; + NetStop *stop; NetCleanup *cleanup; LinkStatusChanged *link_status_changed; QueryRxFilter *query_rx_filter; diff --git a/include/qemu-main.h b/include/qemu-main.h index 6a3e90d0ad..940960a7db 100644 --- a/include/qemu-main.h +++ b/include/qemu-main.h @@ -5,6 +5,7 @@ #ifndef QEMU_MAIN_H #define QEMU_MAIN_H -int qemu_main(int argc, char **argv, char **envp); +int qemu_default_main(void); +extern int (*qemu_main)(void); #endif /* QEMU_MAIN_H */ diff --git a/include/qemu/accel.h b/include/qemu/accel.h index be56da1b99..ce4747634a 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -43,6 +43,10 @@ typedef struct AccelClass { bool (*has_memory)(MachineState *ms, AddressSpace *as, hwaddr start_addr, hwaddr size); #endif + + /* gdbstub related hooks */ + int (*gdbstub_supported_sstep_flags)(void); + bool *allowed; /* * Array of global properties that would be applied when specific @@ -92,4 +96,12 @@ void accel_cpu_instance_init(CPUState *cpu); */ bool accel_cpu_realizefn(CPUState *cpu, Error **errp); +/** + * accel_supported_gdbstub_sstep_flags: + * + * Returns the supported single step modes for the configured + * accelerator. + */ +int accel_supported_gdbstub_sstep_flags(void); + #endif /* QEMU_ACCEL_H */ diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 08c5bb3c76..aae33cce17 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -92,12 +92,12 @@ void coroutine_fn qemu_coroutine_yield(void); /** * Get the AioContext of the given coroutine */ -AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co); +AioContext *qemu_coroutine_get_aio_context(Coroutine *co); /** * Get the currently executing coroutine */ -Coroutine *coroutine_fn qemu_coroutine_self(void); +Coroutine *qemu_coroutine_self(void); /** * Return whether or not currently inside a coroutine diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index 29f3a99878..88d476161c 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -533,8 +533,7 @@ static inline bool umul64_overflow(uint64_t x, uint64_t y, uint64_t *ret) */ static inline bool mulu128(uint64_t *plow, uint64_t *phigh, uint64_t factor) { -#if defined(CONFIG_INT128) && \ - (__has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5) +#if defined(CONFIG_INT128) bool res; __uint128_t r; __uint128_t f = ((__uint128_t)*phigh << 64) | *plow; diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h index 16bbfdf5f8..8528e5c98f 100644 --- a/include/qemu/iova-tree.h +++ b/include/qemu/iova-tree.h @@ -73,7 +73,7 @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map); * all the mappings that are included in the provided range will be * removed from the tree. Here map->translated_addr is meaningless. */ -void iova_tree_remove(IOVATree *tree, const DMAMap *map); +void iova_tree_remove(IOVATree *tree, DMAMap map); /** * iova_tree_find: diff --git a/include/qemu/job.h b/include/qemu/job.h index c105b31076..e502787dd8 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -40,27 +40,62 @@ typedef struct JobTxn JobTxn; * Long-running operation. */ typedef struct Job { + + /* Fields set at initialization (job_create), and never modified */ + /** The ID of the job. May be NULL for internal jobs. */ char *id; - /** The type of this job. */ + /** + * The type of this job. + * All callbacks are called with job_mutex *not* held. + */ const JobDriver *driver; + /** + * The coroutine that executes the job. If not NULL, it is reentered when + * busy is false and the job is cancelled. + * Initialized in job_start() + */ + Coroutine *co; + + /** True if this job should automatically finalize itself */ + bool auto_finalize; + + /** True if this job should automatically dismiss itself */ + bool auto_dismiss; + + /** + * The completion function that will be called when the job completes. + * Called with AioContext lock held, since many callback implementations + * use bdrv_* functions that require to hold the lock. + */ + BlockCompletionFunc *cb; + + /** The opaque value that is passed to the completion function. */ + void *opaque; + + /* ProgressMeter API is thread-safe */ + ProgressMeter progress; + + /** + * AioContext to run the job coroutine in. + * The job Aiocontext can be read when holding *either* + * the BQL (so we are in the main loop) or the job_mutex. + * It can only be written when we hold *both* BQL + * and the job_mutex. + */ + AioContext *aio_context; + + + /** Protected by job_mutex */ + /** Reference count of the block job */ int refcnt; /** Current state; See @JobStatus for details. */ JobStatus status; - /** AioContext to run the job coroutine in */ - AioContext *aio_context; - - /** - * The coroutine that executes the job. If not NULL, it is reentered when - * busy is false and the job is cancelled. - */ - Coroutine *co; - /** * Timer that is used by @job_sleep_ns. Accessed under job_mutex (in * job.c). @@ -76,7 +111,7 @@ typedef struct Job { /** * Set to false by the job while the coroutine has yielded and may be * re-entered by job_enter(). There may still be I/O or event loop activity - * pending. Accessed under block_job_mutex (in blockjob.c). + * pending. Accessed under job_mutex. * * When the job is deferred to the main loop, busy is true as long as the * bottom half is still pending. @@ -112,14 +147,6 @@ typedef struct Job { /** Set to true when the job has deferred work to the main loop. */ bool deferred_to_main_loop; - /** True if this job should automatically finalize itself */ - bool auto_finalize; - - /** True if this job should automatically dismiss itself */ - bool auto_dismiss; - - ProgressMeter progress; - /** * Return code from @run and/or @prepare callback(s). * Not final until the job has reached the CONCLUDED status. @@ -134,12 +161,6 @@ typedef struct Job { */ Error *err; - /** The completion function that will be called when the job completes. */ - BlockCompletionFunc *cb; - - /** The opaque value that is passed to the completion function. */ - void *opaque; - /** Notifiers called when a cancelled job is finalised */ NotifierList on_finalize_cancelled; @@ -167,6 +188,7 @@ typedef struct Job { /** * Callbacks and other information about a Job driver. + * All callbacks are invoked with job_mutex *not* held. */ struct JobDriver { @@ -242,6 +264,9 @@ struct JobDriver { * * This callback will not be invoked if the job has already failed. * If it fails, abort and then clean will be called. + * + * Called with AioContext lock held, since many callbacs implementations + * use bdrv_* functions that require to hold the lock. */ int (*prepare)(Job *job); @@ -252,6 +277,9 @@ struct JobDriver { * * All jobs will complete with a call to either .commit() or .abort() but * never both. + * + * Called with AioContext lock held, since many callback implementations + * use bdrv_* functions that require to hold the lock. */ void (*commit)(Job *job); @@ -262,6 +290,9 @@ struct JobDriver { * * All jobs will complete with a call to either .commit() or .abort() but * never both. + * + * Called with AioContext lock held, since many callback implementations + * use bdrv_* functions that require to hold the lock. */ void (*abort)(Job *job); @@ -270,6 +301,9 @@ struct JobDriver { * .commit() or .abort(). Regardless of which callback is invoked after * completion, .clean() will always be called, even if the job does not * belong to a transaction group. + * + * Called with AioContext lock held, since many callbacs implementations + * use bdrv_* functions that require to hold the lock. */ void (*clean)(Job *job); @@ -284,11 +318,18 @@ struct JobDriver { * READY). * (If the callback is NULL, the job is assumed to terminate * without I/O.) + * + * Called with AioContext lock held, since many callback implementations + * use bdrv_* functions that require to hold the lock. */ bool (*cancel)(Job *job, bool force); - /** Called when the job is freed */ + /** + * Called when the job is freed. + * Called with AioContext lock held, since many callback implementations + * use bdrv_* functions that require to hold the lock. + */ void (*free)(Job *job); }; @@ -303,6 +344,30 @@ typedef enum JobCreateFlags { JOB_MANUAL_DISMISS = 0x04, } JobCreateFlags; +extern QemuMutex job_mutex; + +#define JOB_LOCK_GUARD() QEMU_LOCK_GUARD(&job_mutex) + +#define WITH_JOB_LOCK_GUARD() WITH_QEMU_LOCK_GUARD(&job_mutex) + +/** + * job_lock: + * + * Take the mutex protecting the list of jobs and their status. + * Most functions called by the monitor need to call job_lock + * and job_unlock manually. On the other hand, function called + * by the block jobs themselves and by the block layer will take the + * lock for you. + */ +void job_lock(void); + +/** + * job_unlock: + * + * Release the mutex protecting the list of jobs and their status. + */ +void job_unlock(void); + /** * Allocate and return a new job transaction. Jobs can be added to the * transaction using job_txn_add_job(). @@ -319,23 +384,20 @@ JobTxn *job_txn_new(void); /** * Release a reference that was previously acquired with job_txn_add_job or * job_txn_new. If it's the last reference to the object, it will be freed. + * + * Called with job lock *not* held. */ void job_txn_unref(JobTxn *txn); -/** - * @txn: The transaction (may be NULL) - * @job: Job to add to the transaction - * - * Add @job to the transaction. The @job must not already be in a transaction. - * The caller must call either job_txn_unref() or job_completed() to release - * the reference that is automatically grabbed here. - * - * If @txn is NULL, the function does nothing. +/* + * Same as job_txn_unref(), but called with job lock held. + * Might release the lock temporarily. */ -void job_txn_add_job(JobTxn *txn, Job *job); +void job_txn_unref_locked(JobTxn *txn); /** * Create a new long-running job and return it. + * Called with job_mutex *not* held. * * @job_id: The id of the newly-created job, or %NULL for internal jobs * @driver: The class object for the newly-created job. @@ -353,20 +415,27 @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, /** * Add a reference to Job refcnt, it will be decreased with job_unref, and then * be freed if it comes to be the last reference. + * + * Called with job lock held. */ -void job_ref(Job *job); +void job_ref_locked(Job *job); /** - * Release a reference that was previously acquired with job_ref() or + * Release a reference that was previously acquired with job_ref_locked() or * job_create(). If it's the last reference to the object, it will be freed. + * + * Takes AioContext lock internally to invoke a job->driver callback. + * Called with job lock held. */ -void job_unref(Job *job); +void job_unref_locked(Job *job); /** * @job: The job that has made progress * @done: How much progress the job made since the last call * * Updates the progress counter of the job. + * + * May be called with mutex held or not held. */ void job_progress_update(Job *job, uint64_t done); @@ -377,6 +446,8 @@ void job_progress_update(Job *job, uint64_t done); * * Sets the expected end value of the progress counter of a job so that a * completion percentage can be calculated when the progress is updated. + * + * May be called with mutex held or not held. */ void job_progress_set_remaining(Job *job, uint64_t remaining); @@ -392,27 +463,27 @@ void job_progress_set_remaining(Job *job, uint64_t remaining); * length before, and job_progress_update() afterwards. * (So the operation acts as a parenthesis in regards to the main job * operation running in background.) + * + * May be called with mutex held or not held. */ void job_progress_increase_remaining(Job *job, uint64_t delta); -/** To be called when a cancelled job is finalised. */ -void job_event_cancelled(Job *job); - -/** To be called when a successfully completed job is finalised. */ -void job_event_completed(Job *job); - /** * Conditionally enter the job coroutine if the job is ready to run, not * already busy and fn() returns true. fn() is called while under the job_lock * critical section. + * + * Called with job lock held, but might release it temporarily. */ -void job_enter_cond(Job *job, bool(*fn)(Job *job)); +void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)); /** * @job: A job that has not yet been started. * * Begins execution of a job. * Takes ownership of one reference to the job object. + * + * Called with job_mutex *not* held. */ void job_start(Job *job); @@ -420,6 +491,7 @@ void job_start(Job *job); * @job: The job to enter. * * Continue the specified job by entering the coroutine. + * Called with job_mutex *not* held. */ void job_enter(Job *job); @@ -428,6 +500,8 @@ void job_enter(Job *job); * * Pause now if job_pause() has been called. Jobs that perform lots of I/O * must call this between requests so that the job can be paused. + * + * Called with job_mutex *not* held. */ void coroutine_fn job_pause_point(Job *job); @@ -435,8 +509,9 @@ void coroutine_fn job_pause_point(Job *job); * @job: The job that calls the function. * * Yield the job coroutine. + * Called with job_mutex *not* held. */ -void job_yield(Job *job); +void coroutine_fn job_yield(Job *job); /** * @job: The job that calls the function. @@ -445,10 +520,11 @@ void job_yield(Job *job); * Put the job to sleep (assuming that it wasn't canceled) for @ns * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately * interrupt the wait. + * + * Called with job_mutex *not* held. */ void coroutine_fn job_sleep_ns(Job *job, int64_t ns); - /** Returns the JobType of a given Job. */ JobType job_type(const Job *job); @@ -458,88 +534,138 @@ const char *job_type_str(const Job *job); /** Returns true if the job should not be visible to the management layer. */ bool job_is_internal(Job *job); -/** Returns whether the job is being cancelled. */ +/** + * Returns whether the job is being cancelled. + * Called with job_mutex *not* held. + */ bool job_is_cancelled(Job *job); +/* Same as job_is_cancelled(), but called with job lock held. */ +bool job_is_cancelled_locked(Job *job); + /** * Returns whether the job is scheduled for cancellation (at an * indefinite point). + * Called with job_mutex *not* held. */ bool job_cancel_requested(Job *job); -/** Returns whether the job is in a completed state. */ -bool job_is_completed(Job *job); +/** + * Returns whether the job is in a completed state. + * Called with job lock held. + */ +bool job_is_completed_locked(Job *job); -/** Returns whether the job is ready to be completed. */ +/** + * Returns whether the job is ready to be completed. + * Called with job_mutex *not* held. + */ bool job_is_ready(Job *job); +/* Same as job_is_ready(), but called with job lock held. */ +bool job_is_ready_locked(Job *job); + /** * Request @job to pause at the next pause point. Must be paired with * job_resume(). If the job is supposed to be resumed by user action, call - * job_user_pause() instead. + * job_user_pause_locked() instead. + * + * Called with job lock *not* held. */ void job_pause(Job *job); -/** Resumes a @job paused with job_pause. */ +/* Same as job_pause(), but called with job lock held. */ +void job_pause_locked(Job *job); + +/** Resumes a @job paused with job_pause. Called with job lock *not* held. */ void job_resume(Job *job); +/* + * Same as job_resume(), but called with job lock held. + * Might release the lock temporarily. + */ +void job_resume_locked(Job *job); + /** * Asynchronously pause the specified @job. * Do not allow a resume until a matching call to job_user_resume. + * Called with job lock held. */ -void job_user_pause(Job *job, Error **errp); +void job_user_pause_locked(Job *job, Error **errp); -/** Returns true if the job is user-paused. */ -bool job_user_paused(Job *job); +/** + * Returns true if the job is user-paused. + * Called with job lock held. + */ +bool job_user_paused_locked(Job *job); /** * Resume the specified @job. - * Must be paired with a preceding job_user_pause. + * Must be paired with a preceding job_user_pause_locked. + * Called with job lock held, but might release it temporarily. */ -void job_user_resume(Job *job, Error **errp); +void job_user_resume_locked(Job *job, Error **errp); /** * Get the next element from the list of block jobs after @job, or the * first one if @job is %NULL. * * Returns the requested job, or %NULL if there are no more jobs left. + * Called with job lock *not* held. */ Job *job_next(Job *job); +/* Same as job_next(), but called with job lock held. */ +Job *job_next_locked(Job *job); + /** * Get the job identified by @id (which must not be %NULL). * * Returns the requested job, or %NULL if it doesn't exist. + * Called with job lock held. */ -Job *job_get(const char *id); +Job *job_get_locked(const char *id); /** * Check whether the verb @verb can be applied to @job in its current state. * Returns 0 if the verb can be applied; otherwise errp is set and -EPERM * returned. + * + * Called with job lock held. */ -int job_apply_verb(Job *job, JobVerb verb, Error **errp); +int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp); -/** The @job could not be started, free it. */ +/** + * The @job could not be started, free it. + * Called with job_mutex *not* held. + */ void job_early_fail(Job *job); -/** Moves the @job from RUNNING to READY */ +/** + * Moves the @job from RUNNING to READY. + * Called with job_mutex *not* held. + */ void job_transition_to_ready(Job *job); -/** Asynchronously complete the specified @job. */ -void job_complete(Job *job, Error **errp); +/** + * Asynchronously complete the specified @job. + * Called with job lock held, but might release it temporarily. + */ +void job_complete_locked(Job *job, Error **errp); /** * Asynchronously cancel the specified @job. If @force is true, the job should * be cancelled immediately without waiting for a consistent state. + * Called with job lock held. */ -void job_cancel(Job *job, bool force); +void job_cancel_locked(Job *job, bool force); /** - * Cancels the specified job like job_cancel(), but may refuse to do so if the - * operation isn't meaningful in the current state of the job. + * Cancels the specified job like job_cancel_locked(), but may refuse + * to do so if the operation isn't meaningful in the current state of the job. + * Called with job lock held. */ -void job_user_cancel(Job *job, bool force, Error **errp); +void job_user_cancel_locked(Job *job, bool force, Error **errp); /** * Synchronously cancel the @job. The completion callback is called @@ -550,16 +676,23 @@ void job_user_cancel(Job *job, bool force, Error **errp); * Returns the return value from the job if the job actually completed * during the call, or -ECANCELED if it was canceled. * - * Callers must hold the AioContext lock of job->aio_context. + * Called with job_lock *not* held. */ int job_cancel_sync(Job *job, bool force); -/** Synchronously force-cancels all jobs using job_cancel_sync(). */ +/* Same as job_cancel_sync, but called with job lock held. */ +int job_cancel_sync_locked(Job *job, bool force); + +/** + * Synchronously force-cancels all jobs using job_cancel_sync_locked(). + * + * Called with job_lock *not* held. + */ void job_cancel_sync_all(void); /** * @job: The job to be completed. - * @errp: Error object which may be set by job_complete(); this is not + * @errp: Error object which may be set by job_complete_locked(); this is not * necessarily set on every error, the job return value has to be * checked as well. * @@ -568,10 +701,9 @@ void job_cancel_sync_all(void); * function). * * Returns the return value from the job. - * - * Callers must hold the AioContext lock of job->aio_context. + * Called with job_lock held. */ -int job_complete_sync(Job *job, Error **errp); +int job_complete_sync_locked(Job *job, Error **errp); /** * For a @job that has finished its work and is pending awaiting explicit @@ -580,14 +712,18 @@ int job_complete_sync(Job *job, Error **errp); * FIXME: Make the below statement universally true: * For jobs that support the manual workflow mode, all graph changes that occur * as a result will occur after this command and before a successful reply. + * + * Called with job lock held. */ -void job_finalize(Job *job, Error **errp); +void job_finalize_locked(Job *job, Error **errp); /** * Remove the concluded @job from the query list and resets the passed pointer * to %NULL. Returns an error if the job is not actually concluded. + * + * Called with job lock held. */ -void job_dismiss(Job **job, Error **errp); +void job_dismiss_locked(Job **job, Error **errp); /** * Synchronously finishes the given @job. If @finish is given, it is called to @@ -596,8 +732,20 @@ void job_dismiss(Job **job, Error **errp); * Returns 0 if the job is successfully completed, -ECANCELED if the job was * cancelled before completing, and -errno in other error cases. * - * Callers must hold the AioContext lock of job->aio_context. + * Called with job_lock held, but might release it temporarily. */ -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp); +int job_finish_sync_locked(Job *job, void (*finish)(Job *, Error **errp), + Error **errp); + +/** + * Sets the @job->aio_context. + * Called with job_mutex *not* held. + * + * This function must run in the main thread to protect against + * concurrent read in job_finish_sync_locked(), takes the job_mutex + * lock to protect against the read in job_do_yield_locked(), and must + * be called when the job is quiescent. + */ +void job_set_aio_context(Job *job, AioContext *ctx); #endif diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 5518845299..aac707d073 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -279,32 +279,31 @@ bool qemu_mutex_iothread_locked(void); */ bool qemu_in_main_thread(void); -/* Mark and check that the function is part of the global state API. */ -#ifdef CONFIG_COCOA /* - * When using the Cocoa UI, addRemovableDevicesMenuItems() is called from - * a thread different from the QEMU main thread and can not take the BQL, - * triggering this assertions in the block layer (commit 0439c5a462). - * As the Cocoa fix is not trivial, disable this assertion for the v7.0.0 - * release (when using Cocoa); we will restore it immediately after the - * release. - * This issue is tracked as https://gitlab.com/qemu-project/qemu/-/issues/926 + * Mark and check that the function is part of the Global State API. + * Please refer to include/block/block-global-state.h for more + * information about GS API. */ -#define GLOBAL_STATE_CODE() -#else #define GLOBAL_STATE_CODE() \ do { \ assert(qemu_in_main_thread()); \ } while (0) -#endif /* CONFIG_COCOA */ -/* Mark and check that the function is part of the I/O API. */ +/* + * Mark and check that the function is part of the I/O API. + * Please refer to include/block/block-io.h for more + * information about IO API. + */ #define IO_CODE() \ do { \ /* nop */ \ } while (0) -/* Mark and check that the function is part of the "I/O OR GS" API. */ +/* + * Mark and check that the function is part of the "I/O OR GS" API. + * Please refer to include/block/block-io.h for more + * information about "IO or GS" API. + */ #define IO_OR_GS_CODE() \ do { \ /* nop */ \ diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h index 5076695cc8..2825e231a7 100644 --- a/include/qemu/mmap-alloc.h +++ b/include/qemu/mmap-alloc.h @@ -4,8 +4,6 @@ size_t qemu_fd_getpagesize(int fd); -size_t qemu_mempath_getpagesize(const char *mem_path); - /** * qemu_ram_mmap: mmap anonymous memory, the specified file or device. * diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index 145f8a221a..a772e14193 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -224,6 +224,23 @@ void qemu_plugin_disable_mem_helpers(CPUState *cpu); */ void qemu_plugin_user_exit(void); +/** + * qemu_plugin_user_prefork_lock(): take plugin lock before forking + * + * This is a user-mode only helper to take the internal plugin lock + * before a fork event. This is ensure a consistent lock state + */ +void qemu_plugin_user_prefork_lock(void); + +/** + * qemu_plugin_user_postfork(): reset the plugin lock + * @is_child: is this thread the child + * + * This user-mode only helper resets the lock state after a fork so we + * can continue using the plugin interface. + */ +void qemu_plugin_user_postfork(bool is_child); + #else /* !CONFIG_PLUGIN */ static inline void qemu_plugin_add_opts(void) @@ -287,6 +304,13 @@ static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu) static inline void qemu_plugin_user_exit(void) { } + +static inline void qemu_plugin_user_prefork_lock(void) +{ } + +static inline void qemu_plugin_user_postfork(bool is_child) +{ } + #endif /* !CONFIG_PLUGIN */ #endif /* QEMU_PLUGIN_H */ diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 038faa157f..036745e586 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -14,6 +14,24 @@ int inet_aton(const char *cp, struct in_addr *ia); /* misc helpers */ bool fd_is_socket(int fd); int qemu_socket(int domain, int type, int protocol); + +#ifndef WIN32 +/** + * qemu_socketpair: + * @domain: specifies a communication domain, such as PF_UNIX + * @type: specifies the socket type. + * @protocol: specifies a particular protocol to be used with the socket + * @sv: an array to store the pair of socket created + * + * Creates an unnamed pair of connected sockets in the specified domain, + * of the specified type, and using the optionally specified protocol. + * And automatically set the close-on-exec flags on the returned sockets + * + * Return 0 on success. + */ +int qemu_socketpair(int domain, int type, int protocol, int sv[2]); +#endif + int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); int socket_set_cork(int fd, int v); int socket_set_nodelay(int fd); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 42f4ceb701..6d4e6d9708 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -41,7 +41,9 @@ typedef struct CoMutex CoMutex; typedef struct ConfidentialGuestSupport ConfidentialGuestSupport; typedef struct CPUAddressSpace CPUAddressSpace; typedef struct CPUArchState CPUArchState; +typedef struct CPUJumpCache CPUJumpCache; typedef struct CPUState CPUState; +typedef struct CPUTLBEntryFull CPUTLBEntryFull; typedef struct DeviceListener DeviceListener; typedef struct DeviceState DeviceState; typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot; @@ -129,6 +131,7 @@ typedef struct VirtIODevice VirtIODevice; typedef struct Visitor Visitor; typedef struct VMChangeStateEntry VMChangeStateEntry; typedef struct VMStateDescription VMStateDescription; +typedef struct DumpState DumpState; /* * Pointer types diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h index 93a3c21b44..efd2efa25a 100644 --- a/include/semihosting/semihost.h +++ b/include/semihosting/semihost.h @@ -27,7 +27,7 @@ typedef enum SemihostingTarget { } SemihostingTarget; #ifdef CONFIG_USER_ONLY -static inline bool semihosting_enabled(void) +static inline bool semihosting_enabled(bool is_user) { return true; } @@ -52,7 +52,13 @@ static inline const char *semihosting_get_cmdline(void) return NULL; } #else /* !CONFIG_USER_ONLY */ -bool semihosting_enabled(void); +/** + * semihosting_enabled: + * @is_user: true if guest code is in usermode (i.e. not privileged) + * + * Return true if guest code is allowed to make semihosting calls. + */ +bool semihosting_enabled(bool is_user); SemihostingTarget semihosting_get_target(void); const char *semihosting_get_arg(int i); int semihosting_get_argc(void); diff --git a/include/standard-headers/asm-x86/bootparam.h b/include/standard-headers/asm-x86/bootparam.h index b2aaad10e5..0b06d2bff1 100644 --- a/include/standard-headers/asm-x86/bootparam.h +++ b/include/standard-headers/asm-x86/bootparam.h @@ -10,12 +10,13 @@ #define SETUP_EFI 4 #define SETUP_APPLE_PROPERTIES 5 #define SETUP_JAILHOUSE 6 +#define SETUP_CC_BLOB 7 +#define SETUP_IMA 8 #define SETUP_RNG_SEED 9 +#define SETUP_ENUM_MAX SETUP_RNG_SEED #define SETUP_INDIRECT (1<<31) - -/* SETUP_INDIRECT | max(SETUP_*) */ -#define SETUP_TYPE_MAX (SETUP_INDIRECT | SETUP_JAILHOUSE) +#define SETUP_TYPE_MAX (SETUP_ENUM_MAX | SETUP_INDIRECT) /* ram_size flags */ #define RAMDISK_IMAGE_START_MASK 0x07FF diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h index 4888f85f69..48b620cbef 100644 --- a/include/standard-headers/drm/drm_fourcc.h +++ b/include/standard-headers/drm/drm_fourcc.h @@ -558,7 +558,7 @@ extern "C" { * * The main surface is Y-tiled and is at plane index 0 whereas CCS is linear * and at index 1. The clear color is stored at index 2, and the pitch should - * be ignored. The clear color structure is 256 bits. The first 128 bits + * be 64 bytes aligned. The clear color structure is 256 bits. The first 128 bits * represents Raw Clear Color Red, Green, Blue and Alpha color each represented * by 32 bits. The raw clear color is consumed by the 3d engine and generates * the converted clear color of size 64 bits. The first 32 bits store the Lower @@ -571,6 +571,53 @@ extern "C" { */ #define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC fourcc_mod_code(INTEL, 8) +/* + * Intel Tile 4 layout + * + * This is a tiled layout using 4KB tiles in a row-major layout. It has the same + * shape as Tile Y at two granularities: 4KB (128B x 32) and 64B (16B x 4). It + * only differs from Tile Y at the 256B granularity in between. At this + * granularity, Tile Y has a shape of 16B x 32 rows, but this tiling has a shape + * of 64B x 8 rows. + */ +#define I915_FORMAT_MOD_4_TILED fourcc_mod_code(INTEL, 9) + +/* + * Intel color control surfaces (CCS) for DG2 render compression. + * + * The main surface is Tile 4 and at plane index 0. The CCS data is stored + * outside of the GEM object in a reserved memory area dedicated for the + * storage of the CCS data for all RC/RC_CC/MC compressible GEM objects. The + * main surface pitch is required to be a multiple of four Tile 4 widths. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_RC_CCS fourcc_mod_code(INTEL, 10) + +/* + * Intel color control surfaces (CCS) for DG2 media compression. + * + * The main surface is Tile 4 and at plane index 0. For semi-planar formats + * like NV12, the Y and UV planes are Tile 4 and are located at plane indices + * 0 and 1, respectively. The CCS for all planes are stored outside of the + * GEM object in a reserved memory area dedicated for the storage of the + * CCS data for all RC/RC_CC/MC compressible GEM objects. The main surface + * pitch is required to be a multiple of four Tile 4 widths. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_MC_CCS fourcc_mod_code(INTEL, 11) + +/* + * Intel Color Control Surface with Clear Color (CCS) for DG2 render compression. + * + * The main surface is Tile 4 and at plane index 0. The CCS data is stored + * outside of the GEM object in a reserved memory area dedicated for the + * storage of the CCS data for all RC/RC_CC/MC compressible GEM objects. The + * main surface pitch is required to be a multiple of four Tile 4 widths. The + * clear color is stored at plane index 1 and the pitch should be 64 bytes + * aligned. The format of the 256 bits of clear color data matches the one used + * for the I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC modifier, see its description + * for details. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC fourcc_mod_code(INTEL, 12) + /* * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks * @@ -608,6 +655,28 @@ extern "C" { */ #define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) +/* + * Qualcomm Tiled Format + * + * Similar to DRM_FORMAT_MOD_QCOM_COMPRESSED but not compressed. + * Implementation may be platform and base-format specific. + * + * Each macrotile consists of m x n (mostly 4 x 4) tiles. + * Pixel data pitch/stride is aligned with macrotile width. + * Pixel data height is aligned with macrotile height. + * Entire pixel data buffer is aligned with 4k(bytes). + */ +#define DRM_FORMAT_MOD_QCOM_TILED3 fourcc_mod_code(QCOM, 3) + +/* + * Qualcomm Alternate Tiled Format + * + * Alternate tiled format typically only used within GMEM. + * Implementation may be platform and base-format specific. + */ +#define DRM_FORMAT_MOD_QCOM_TILED2 fourcc_mod_code(QCOM, 2) + + /* Vivante framebuffer modifiers */ /* @@ -1293,6 +1362,7 @@ drm_fourcc_canonicalize_nvidia_format_mod(uint64_t modifier) #define AMD_FMT_MOD_TILE_VER_GFX9 1 #define AMD_FMT_MOD_TILE_VER_GFX10 2 #define AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS 3 +#define AMD_FMT_MOD_TILE_VER_GFX11 4 /* * 64K_S is the same for GFX9/GFX10/GFX10_RBPLUS and hence has GFX9 as canonical @@ -1308,6 +1378,7 @@ drm_fourcc_canonicalize_nvidia_format_mod(uint64_t modifier) #define AMD_FMT_MOD_TILE_GFX9_64K_S_X 25 #define AMD_FMT_MOD_TILE_GFX9_64K_D_X 26 #define AMD_FMT_MOD_TILE_GFX9_64K_R_X 27 +#define AMD_FMT_MOD_TILE_GFX11_256K_R_X 31 #define AMD_FMT_MOD_DCC_BLOCK_64B 0 #define AMD_FMT_MOD_DCC_BLOCK_128B 1 diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h index 38d5a4cd6e..4537da20cc 100644 --- a/include/standard-headers/linux/ethtool.h +++ b/include/standard-headers/linux/ethtool.h @@ -257,7 +257,7 @@ struct ethtool_tunable { uint32_t id; uint32_t type_id; uint32_t len; - void *data[0]; + void *data[]; }; #define DOWNSHIFT_DEV_DEFAULT_COUNT 0xff @@ -322,7 +322,7 @@ struct ethtool_regs { uint32_t cmd; uint32_t version; uint32_t len; - uint8_t data[0]; + uint8_t data[]; }; /** @@ -348,7 +348,7 @@ struct ethtool_eeprom { uint32_t magic; uint32_t offset; uint32_t len; - uint8_t data[0]; + uint8_t data[]; }; /** @@ -752,7 +752,7 @@ struct ethtool_gstrings { uint32_t cmd; uint32_t string_set; uint32_t len; - uint8_t data[0]; + uint8_t data[]; }; /** @@ -777,7 +777,7 @@ struct ethtool_sset_info { uint32_t cmd; uint32_t reserved; uint64_t sset_mask; - uint32_t data[0]; + uint32_t data[]; }; /** @@ -817,7 +817,7 @@ struct ethtool_test { uint32_t flags; uint32_t reserved; uint32_t len; - uint64_t data[0]; + uint64_t data[]; }; /** @@ -834,7 +834,7 @@ struct ethtool_test { struct ethtool_stats { uint32_t cmd; uint32_t n_stats; - uint64_t data[0]; + uint64_t data[]; }; /** @@ -851,7 +851,7 @@ struct ethtool_stats { struct ethtool_perm_addr { uint32_t cmd; uint32_t size; - uint8_t data[0]; + uint8_t data[]; }; /* boolean flags controlling per-interface behavior characteristics. @@ -1160,7 +1160,7 @@ struct ethtool_rxnfc { struct ethtool_rxfh_indir { uint32_t cmd; uint32_t size; - uint32_t ring_index[0]; + uint32_t ring_index[]; }; /** @@ -1201,7 +1201,7 @@ struct ethtool_rxfh { uint8_t hfunc; uint8_t rsvd8[3]; uint32_t rsvd32; - uint32_t rss_config[0]; + uint32_t rss_config[]; }; #define ETH_RXFH_CONTEXT_ALLOC 0xffffffff #define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff @@ -1286,7 +1286,7 @@ struct ethtool_dump { uint32_t version; uint32_t flag; uint32_t len; - uint8_t data[0]; + uint8_t data[]; }; #define ETH_FW_DUMP_DISABLE 0 @@ -1318,7 +1318,7 @@ struct ethtool_get_features_block { struct ethtool_gfeatures { uint32_t cmd; uint32_t size; - struct ethtool_get_features_block features[0]; + struct ethtool_get_features_block features[]; }; /** @@ -1340,7 +1340,7 @@ struct ethtool_set_features_block { struct ethtool_sfeatures { uint32_t cmd; uint32_t size; - struct ethtool_set_features_block features[0]; + struct ethtool_set_features_block features[]; }; /** @@ -1691,6 +1691,7 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT = 89, ETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90, ETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91, + ETHTOOL_LINK_MODE_10baseT1L_Full_BIT = 92, /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS }; @@ -2086,7 +2087,7 @@ struct ethtool_link_settings { uint8_t master_slave_state; uint8_t reserved1[1]; uint32_t reserved[7]; - uint32_t link_mode_masks[0]; + uint32_t link_mode_masks[]; /* layout of link_mode_masks fields: * uint32_t map_supported[link_mode_masks_nwords]; * uint32_t map_advertising[link_mode_masks_nwords]; diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h index 7822c24178..942ea6aaa9 100644 --- a/include/standard-headers/linux/input.h +++ b/include/standard-headers/linux/input.h @@ -75,10 +75,13 @@ struct input_id { * Note that input core does not clamp reported values to the * [minimum, maximum] limits, such task is left to userspace. * - * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z) - * is reported in units per millimeter (units/mm), resolution - * for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported - * in units per radian. + * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z, + * ABS_MT_POSITION_X, ABS_MT_POSITION_Y) is reported in units + * per millimeter (units/mm), resolution for rotational axes + * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian. + * The resolution for the size axes (ABS_MT_TOUCH_MAJOR, + * ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MAJOR, ABS_MT_WIDTH_MINOR) + * is reported in units per millimeter (units/mm). * When INPUT_PROP_ACCELEROMETER is set the resolution changes. * The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in * units per g (units/g) and in units per degree per second @@ -268,6 +271,7 @@ struct input_mask { #define BUS_RMI 0x1D #define BUS_CEC 0x1E #define BUS_INTEL_ISHTP 0x1F +#define BUS_AMD_SFH 0x20 /* * MT_TOOL types diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index bee1a9ed6e..57b8e2ffb1 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -616,6 +616,7 @@ #define PCI_EXP_SLTCTL_PWR_OFF 0x0400 /* Power Off */ #define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ #define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ +#define PCI_EXP_SLTCTL_ASPL_DISABLE 0x2000 /* Auto Slot Power Limit Disable */ #define PCI_EXP_SLTCTL_IBPD_DISABLE 0x4000 /* In-band PD disable */ #define PCI_EXP_SLTSTA 0x1a /* Slot Status */ #define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ @@ -736,7 +737,8 @@ #define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */ #define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */ #define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */ -#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_16GT +#define PCI_EXT_CAP_ID_DOE 0x2E /* Data Object Exchange */ +#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DOE #define PCI_EXT_CAP_DSN_SIZEOF 12 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 @@ -1102,4 +1104,30 @@ #define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK 0x000000F0 #define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT 4 +/* Data Object Exchange */ +#define PCI_DOE_CAP 0x04 /* DOE Capabilities Register */ +#define PCI_DOE_CAP_INT_SUP 0x00000001 /* Interrupt Support */ +#define PCI_DOE_CAP_INT_MSG_NUM 0x00000ffe /* Interrupt Message Number */ +#define PCI_DOE_CTRL 0x08 /* DOE Control Register */ +#define PCI_DOE_CTRL_ABORT 0x00000001 /* DOE Abort */ +#define PCI_DOE_CTRL_INT_EN 0x00000002 /* DOE Interrupt Enable */ +#define PCI_DOE_CTRL_GO 0x80000000 /* DOE Go */ +#define PCI_DOE_STATUS 0x0c /* DOE Status Register */ +#define PCI_DOE_STATUS_BUSY 0x00000001 /* DOE Busy */ +#define PCI_DOE_STATUS_INT_STATUS 0x00000002 /* DOE Interrupt Status */ +#define PCI_DOE_STATUS_ERROR 0x00000004 /* DOE Error */ +#define PCI_DOE_STATUS_DATA_OBJECT_READY 0x80000000 /* Data Object Ready */ +#define PCI_DOE_WRITE 0x10 /* DOE Write Data Mailbox Register */ +#define PCI_DOE_READ 0x14 /* DOE Read Data Mailbox Register */ + +/* DOE Data Object - note not actually registers */ +#define PCI_DOE_DATA_OBJECT_HEADER_1_VID 0x0000ffff +#define PCI_DOE_DATA_OBJECT_HEADER_1_TYPE 0x00ff0000 +#define PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH 0x0003ffff + +#define PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX 0x000000ff +#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID 0x0000ffff +#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL 0x00ff0000 +#define PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX 0xff000000 + #endif /* LINUX_PCI_REGS_H */ diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h index 0bd2684a2a..c41a73fe36 100644 --- a/include/standard-headers/linux/vhost_types.h +++ b/include/standard-headers/linux/vhost_types.h @@ -87,7 +87,7 @@ struct vhost_msg { struct vhost_msg_v2 { uint32_t type; - uint32_t reserved; + uint32_t asid; union { struct vhost_iotlb_msg iotlb; uint8_t padding[64]; @@ -107,7 +107,7 @@ struct vhost_memory_region { struct vhost_memory { uint32_t nregions; uint32_t padding; - struct vhost_memory_region regions[0]; + struct vhost_memory_region regions[]; }; /* VHOST_SCSI specific definitions */ @@ -135,7 +135,7 @@ struct vhost_scsi_target { struct vhost_vdpa_config { uint32_t off; uint32_t len; - uint8_t buf[0]; + uint8_t buf[]; }; /* vhost vdpa IOVA range @@ -153,4 +153,15 @@ struct vhost_vdpa_iova_range { /* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */ #define VHOST_NET_F_VIRTIO_NET_HDR 27 +/* Use message type V2 */ +#define VHOST_BACKEND_F_IOTLB_MSG_V2 0x1 +/* IOTLB can accept batching hints */ +#define VHOST_BACKEND_F_IOTLB_BATCH 0x2 +/* IOTLB can accept address space identifier through V2 type of IOTLB + * message + */ +#define VHOST_BACKEND_F_IOTLB_ASID 0x3 +/* Device can be suspended */ +#define VHOST_BACKEND_F_SUSPEND 0x4 + #endif diff --git a/include/standard-headers/linux/virtio_9p.h b/include/standard-headers/linux/virtio_9p.h index f5604fc5fb..da61dee98c 100644 --- a/include/standard-headers/linux/virtio_9p.h +++ b/include/standard-headers/linux/virtio_9p.h @@ -38,7 +38,7 @@ struct virtio_9p_config { /* length of the tag name */ __virtio16 tag_len; /* non-NULL terminated tag name */ - uint8_t tag[0]; + uint8_t tag[]; } QEMU_PACKED; #endif /* _LINUX_VIRTIO_9P_H */ diff --git a/include/standard-headers/linux/virtio_config.h b/include/standard-headers/linux/virtio_config.h index 7acd8d4abc..965ee6ae23 100644 --- a/include/standard-headers/linux/virtio_config.h +++ b/include/standard-headers/linux/virtio_config.h @@ -52,7 +52,7 @@ * rest are per-device feature bits. */ #define VIRTIO_TRANSPORT_F_START 28 -#define VIRTIO_TRANSPORT_F_END 38 +#define VIRTIO_TRANSPORT_F_END 41 #ifndef VIRTIO_CONFIG_NO_LEGACY /* Do we get callbacks when the ring is completely used, even if we've @@ -96,4 +96,9 @@ * Does the device support Single Root I/O Virtualization? */ #define VIRTIO_F_SR_IOV 37 + +/* + * This feature indicates that the driver can reset a queue individually. + */ +#define VIRTIO_F_RING_RESET 40 #endif /* _LINUX_VIRTIO_CONFIG_H */ diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h index 80d76b75bc..7aa2eb7662 100644 --- a/include/standard-headers/linux/virtio_ids.h +++ b/include/standard-headers/linux/virtio_ids.h @@ -73,12 +73,12 @@ * Virtio Transitional IDs */ -#define VIRTIO_TRANS_ID_NET 1000 /* transitional virtio net */ -#define VIRTIO_TRANS_ID_BLOCK 1001 /* transitional virtio block */ -#define VIRTIO_TRANS_ID_BALLOON 1002 /* transitional virtio balloon */ -#define VIRTIO_TRANS_ID_CONSOLE 1003 /* transitional virtio console */ -#define VIRTIO_TRANS_ID_SCSI 1004 /* transitional virtio SCSI */ -#define VIRTIO_TRANS_ID_RNG 1005 /* transitional virtio rng */ -#define VIRTIO_TRANS_ID_9P 1009 /* transitional virtio 9p console */ +#define VIRTIO_TRANS_ID_NET 0x1000 /* transitional virtio net */ +#define VIRTIO_TRANS_ID_BLOCK 0x1001 /* transitional virtio block */ +#define VIRTIO_TRANS_ID_BALLOON 0x1002 /* transitional virtio balloon */ +#define VIRTIO_TRANS_ID_CONSOLE 0x1003 /* transitional virtio console */ +#define VIRTIO_TRANS_ID_SCSI 0x1004 /* transitional virtio SCSI */ +#define VIRTIO_TRANS_ID_RNG 0x1005 /* transitional virtio rng */ +#define VIRTIO_TRANS_ID_9P 0x1009 /* transitional virtio 9p console */ #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/standard-headers/linux/virtio_net.h b/include/standard-headers/linux/virtio_net.h index e0a070518f..42c68caf71 100644 --- a/include/standard-headers/linux/virtio_net.h +++ b/include/standard-headers/linux/virtio_net.h @@ -56,7 +56,7 @@ #define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow * Steering */ #define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */ - +#define VIRTIO_NET_F_NOTF_COAL 53 /* Device supports notifications coalescing */ #define VIRTIO_NET_F_HASH_REPORT 57 /* Supports hash report */ #define VIRTIO_NET_F_RSS 60 /* Supports RSS RX steering */ #define VIRTIO_NET_F_RSC_EXT 61 /* extended coalescing info */ @@ -355,4 +355,36 @@ struct virtio_net_hash_config { #define VIRTIO_NET_CTRL_GUEST_OFFLOADS 5 #define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET 0 +/* + * Control notifications coalescing. + * + * Request the device to change the notifications coalescing parameters. + * + * Available with the VIRTIO_NET_F_NOTF_COAL feature bit. + */ +#define VIRTIO_NET_CTRL_NOTF_COAL 6 +/* + * Set the tx-usecs/tx-max-packets parameters. + */ +struct virtio_net_ctrl_coal_tx { + /* Maximum number of packets to send before a TX notification */ + uint32_t tx_max_packets; + /* Maximum number of usecs to delay a TX notification */ + uint32_t tx_usecs; +}; + +#define VIRTIO_NET_CTRL_NOTF_COAL_TX_SET 0 + +/* + * Set the rx-usecs/rx-max-packets parameters. + */ +struct virtio_net_ctrl_coal_rx { + /* Maximum number of packets to receive before a RX notification */ + uint32_t rx_max_packets; + /* Maximum number of usecs to delay a RX notification */ + uint32_t rx_usecs; +}; + +#define VIRTIO_NET_CTRL_NOTF_COAL_RX_SET 1 + #endif /* _LINUX_VIRTIO_NET_H */ diff --git a/include/standard-headers/linux/virtio_pci.h b/include/standard-headers/linux/virtio_pci.h index db7a8e2fcb..be912cfc95 100644 --- a/include/standard-headers/linux/virtio_pci.h +++ b/include/standard-headers/linux/virtio_pci.h @@ -202,6 +202,8 @@ struct virtio_pci_cfg_cap { #define VIRTIO_PCI_COMMON_Q_AVAILHI 44 #define VIRTIO_PCI_COMMON_Q_USEDLO 48 #define VIRTIO_PCI_COMMON_Q_USEDHI 52 +#define VIRTIO_PCI_COMMON_Q_NDATA 56 +#define VIRTIO_PCI_COMMON_Q_RESET 58 #endif /* VIRTIO_PCI_NO_MODERN */ diff --git a/include/standard-headers/linux/virtio_ring.h b/include/standard-headers/linux/virtio_ring.h index 0fa0e1067f..22f6eb8ca7 100644 --- a/include/standard-headers/linux/virtio_ring.h +++ b/include/standard-headers/linux/virtio_ring.h @@ -91,15 +91,21 @@ #define VRING_USED_ALIGN_SIZE 4 #define VRING_DESC_ALIGN_SIZE 16 -/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */ +/** + * struct vring_desc - Virtio ring descriptors, + * 16 bytes long. These can chain together via @next. + * + * @addr: buffer address (guest-physical) + * @len: buffer length + * @flags: descriptor flags + * @next: index of the next descriptor in the chain, + * if the VRING_DESC_F_NEXT flag is set. We chain unused + * descriptors via this, too. + */ struct vring_desc { - /* Address (guest-physical). */ __virtio64 addr; - /* Length. */ __virtio32 len; - /* The flags as indicated above. */ __virtio16 flags; - /* We chain unused descriptors via this, too */ __virtio16 next; }; diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h index a0572ea87a..8cc7996def 100644 --- a/include/sysemu/accel-ops.h +++ b/include/sysemu/accel-ops.h @@ -10,6 +10,7 @@ #ifndef ACCEL_OPS_H #define ACCEL_OPS_H +#include "exec/hwaddr.h" #include "qom/object.h" #define ACCEL_OPS_SUFFIX "-ops" @@ -44,6 +45,12 @@ struct AccelOpsClass { int64_t (*get_virtual_clock)(void); int64_t (*get_elapsed_ticks)(void); + + /* gdbstub hooks */ + bool (*supports_guest_debug)(void); + int (*insert_breakpoint)(CPUState *cpu, int type, hwaddr addr, hwaddr len); + int (*remove_breakpoint)(CPUState *cpu, int type, hwaddr addr, hwaddr len); + void (*remove_all_breakpoints)(CPUState *cpu); }; #endif /* ACCEL_OPS_H */ diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index b5c87d48b3..1bace3379b 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -7,6 +7,9 @@ /* register accel-specific operations */ void cpus_register_accel(const AccelOpsClass *i); +/* return registers ops */ +const AccelOpsClass *cpus_get_accel(void); + /* accel/dummy-cpus.c */ /* Create a dummy vcpu for AccelOpsClass->create_vcpu_thread */ diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index ffc2ea1072..b62513d87d 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -166,11 +166,16 @@ typedef struct DumpState { hwaddr memory_offset; int fd; - GuestPhysBlock *next_block; - ram_addr_t start; - bool has_filter; - int64_t begin; - int64_t length; + /* + * Dump filter area variables + * + * A filtered dump only contains the guest memory designated by + * the start address and length variables defined below. + * + * If length is 0, no filtering is applied. + */ + int64_t filter_area_begin; /* Start address of partial guest memory area */ + int64_t filter_area_length; /* Length of partial guest memory area */ uint8_t *note_buf; /* buffer for notes */ size_t note_buf_offset; /* the writing place in note_buf */ diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index efd6dee818..790d35ef78 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -46,8 +46,6 @@ extern bool kvm_readonly_mem_allowed; extern bool kvm_direct_msi_allowed; extern bool kvm_ioeventfd_any_length_allowed; extern bool kvm_msi_use_devid; -extern bool kvm_has_guest_debug; -extern int kvm_sstep_flags; #define kvm_enabled() (kvm_allowed) /** @@ -169,17 +167,6 @@ extern int kvm_sstep_flags; */ #define kvm_msi_devid_required() (kvm_msi_use_devid) -/* - * Does KVM support guest debugging - */ -#define kvm_supports_guest_debug() (kvm_has_guest_debug) - -/* - * kvm_supported_sstep_flags - * Returns: SSTEP_* flags that KVM supports for guest debug - */ -#define kvm_get_supported_sstep_flags() (kvm_sstep_flags) - #else #define kvm_enabled() (0) @@ -197,8 +184,6 @@ extern int kvm_sstep_flags; #define kvm_direct_msi_enabled() (false) #define kvm_ioeventfd_any_length_enabled() (false) #define kvm_msi_devid_required() (false) -#define kvm_supports_guest_debug() (false) -#define kvm_get_supported_sstep_flags() (0) #endif /* CONFIG_KVM_IS_POSSIBLE */ @@ -262,12 +247,23 @@ int kvm_on_sigbus(int code, void *addr); void kvm_flush_coalesced_mmio_buffer(void); -int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type); -int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type); -void kvm_remove_all_breakpoints(CPUState *cpu); +/** + * kvm_update_guest_debug(): ensure KVM debug structures updated + * @cs: the CPUState for this cpu + * @reinject_trap: KVM trap injection control + * + * There are usually per-arch specifics which will be handled by + * calling down to kvm_arch_update_guest_debug after the generic + * fields have been set. + */ +#ifdef KVM_CAP_SET_GUEST_DEBUG int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap); +#else +static inline int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) +{ + return -EINVAL; +} +#endif /* internal API */ diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index edc3b38a57..5b38c7bd04 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -30,6 +30,23 @@ #include #include +#ifdef HAVE_AFUNIX_H +#include +#else +/* + * Fallback definitions of things we need in afunix.h, if not available from + * the used Windows SDK or MinGW headers. + */ +#define UNIX_PATH_MAX 108 + +typedef struct sockaddr_un { + ADDRESS_FAMILY sun_family; + char sun_path[UNIX_PATH_MAX]; +} SOCKADDR_UN, *PSOCKADDR_UN; + +#define SIO_AF_UNIX_GETPEERPID _WSAIOR(IOC_VENDOR, 256) +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 73dee9ccdf..7ec0882b50 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -198,7 +198,7 @@ uint64_t blkreplay_next_id(void); /*! Registers char driver to save it's events */ void replay_register_char_driver(struct Chardev *chr); /*! Saves write to char device event to the log */ -void replay_chr_be_write(struct Chardev *s, uint8_t *buf, int len); +void replay_chr_be_write(struct Chardev *s, const uint8_t *buf, int len); /*! Writes char write return value to the replay log. */ void replay_char_write_event_save(int res, int offset); /*! Reads char write return value from the replay log. */ diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 812f66a31a..6a7a31e64d 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -102,8 +102,8 @@ void qemu_boot_set(const char *boot_order, Error **errp); bool defaults_enabled(void); -void qemu_init(int argc, char **argv, char **envp); -void qemu_main_loop(void); +void qemu_init(int argc, char **argv); +int qemu_main_loop(void); void qemu_cleanup(void); extern QemuOptsList qemu_legacy_drive_opts; diff --git a/include/sysemu/watchdog.h b/include/sysemu/watchdog.h index d2d4901dbb..745c89b02b 100644 --- a/include/sysemu/watchdog.h +++ b/include/sysemu/watchdog.h @@ -25,20 +25,8 @@ #include "qemu/queue.h" #include "qapi/qapi-types-run-state.h" -struct WatchdogTimerModel { - QLIST_ENTRY(WatchdogTimerModel) entry; - - /* Short name of the device - used to select it on the command line. */ - const char *wdt_name; - /* Longer description (eg. manufacturer and full model number). */ - const char *wdt_description; -}; -typedef struct WatchdogTimerModel WatchdogTimerModel; - /* in hw/watchdog.c */ -int select_watchdog(const char *p); WatchdogAction get_watchdog_action(void); -void watchdog_add_model(WatchdogTimerModel *model); void watchdog_perform_action(void); #endif /* QEMU_WATCHDOG_H */ diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 26a70526f1..d84bae6e3f 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -840,7 +840,7 @@ void tcg_register_thread(void); void tcg_prologue_init(TCGContext *s); void tcg_func_start(TCGContext *s); -int tcg_gen_code(TCGContext *s, TranslationBlock *tb); +int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start); void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size); diff --git a/include/ui/console.h b/include/ui/console.h index c0520c694c..e400ee9fa7 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -70,6 +70,7 @@ void hmp_mouse_set(Monitor *mon, const QDict *qdict); /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx constants) */ #define QEMU_KEY_ESC1(c) ((c) | 0xe100) +#define QEMU_KEY_TAB 0x0009 #define QEMU_KEY_BACKSPACE 0x007f #define QEMU_KEY_UP QEMU_KEY_ESC1('A') #define QEMU_KEY_DOWN QEMU_KEY_ESC1('B') diff --git a/include/user/safe-syscall.h b/include/user/safe-syscall.h index 61a04e2b5a..ddceef12e2 100644 --- a/include/user/safe-syscall.h +++ b/include/user/safe-syscall.h @@ -70,7 +70,7 @@ * If the host libc is used then the implementation will appear to work * most of the time, but there will be a race condition where a * signal could arrive just before we make the host syscall inside libc, - * and then then guest syscall will not correctly be interrupted. + * and then the guest syscall will not correctly be interrupted. * Instead the implementation of the guest syscall can use the safe_syscall * function but otherwise just return the result or errno in the usual * way; the main loop code will take care of restarting the syscall diff --git a/io/channel-socket.c b/io/channel-socket.c index 74a936cc1f..b76dca9cc1 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -746,8 +746,8 @@ static int qio_channel_socket_flush(QIOChannel *ioc, } cm = CMSG_FIRSTHDR(&msg); - if (cm->cmsg_level != SOL_IP && - cm->cmsg_type != IP_RECVERR) { + if (cm->cmsg_level != SOL_IP && cm->cmsg_type != IP_RECVERR && + cm->cmsg_level != SOL_IPV6 && cm->cmsg_type != IPV6_RECVERR) { error_setg_errno(errp, EPROTOTYPE, "Wrong cmsg in errqueue"); return -1; diff --git a/io/channel-websock.c b/io/channel-websock.c index 9619906ac3..fb4932ade7 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -32,7 +32,7 @@ #define QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN 24 #define QIO_CHANNEL_WEBSOCK_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" -#define QIO_CHANNEL_WEBSOCK_GUID_LEN strlen(QIO_CHANNEL_WEBSOCK_GUID) +#define QIO_CHANNEL_WEBSOCK_GUID_LEN (sizeof(QIO_CHANNEL_WEBSOCK_GUID) - 1) #define QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL "sec-websocket-protocol" #define QIO_CHANNEL_WEBSOCK_HEADER_VERSION "sec-websocket-version" diff --git a/job-qmp.c b/job-qmp.c index 829a28aa70..d498fc89c0 100644 --- a/job-qmp.c +++ b/job-qmp.c @@ -29,119 +29,117 @@ #include "qapi/error.h" #include "trace/trace-root.h" -/* Get a job using its ID and acquire its AioContext */ -static Job *find_job(const char *id, AioContext **aio_context, Error **errp) +/* + * Get a job using its ID. Called with job_mutex held. + */ +static Job *find_job_locked(const char *id, Error **errp) { Job *job; - *aio_context = NULL; - - job = job_get(id); + job = job_get_locked(id); if (!job) { error_setg(errp, "Job not found"); return NULL; } - *aio_context = job->aio_context; - aio_context_acquire(*aio_context); - return job; } void qmp_job_cancel(const char *id, Error **errp) { - AioContext *aio_context; - Job *job = find_job(id, &aio_context, errp); + Job *job; + + JOB_LOCK_GUARD(); + job = find_job_locked(id, errp); if (!job) { return; } trace_qmp_job_cancel(job); - job_user_cancel(job, true, errp); - aio_context_release(aio_context); + job_user_cancel_locked(job, true, errp); } void qmp_job_pause(const char *id, Error **errp) { - AioContext *aio_context; - Job *job = find_job(id, &aio_context, errp); + Job *job; + + JOB_LOCK_GUARD(); + job = find_job_locked(id, errp); if (!job) { return; } trace_qmp_job_pause(job); - job_user_pause(job, errp); - aio_context_release(aio_context); + job_user_pause_locked(job, errp); } void qmp_job_resume(const char *id, Error **errp) { - AioContext *aio_context; - Job *job = find_job(id, &aio_context, errp); + Job *job; + + JOB_LOCK_GUARD(); + job = find_job_locked(id, errp); if (!job) { return; } trace_qmp_job_resume(job); - job_user_resume(job, errp); - aio_context_release(aio_context); + job_user_resume_locked(job, errp); } void qmp_job_complete(const char *id, Error **errp) { - AioContext *aio_context; - Job *job = find_job(id, &aio_context, errp); + Job *job; + + JOB_LOCK_GUARD(); + job = find_job_locked(id, errp); if (!job) { return; } trace_qmp_job_complete(job); - job_complete(job, errp); - aio_context_release(aio_context); + job_complete_locked(job, errp); } void qmp_job_finalize(const char *id, Error **errp) { - AioContext *aio_context; - Job *job = find_job(id, &aio_context, errp); + Job *job; + + JOB_LOCK_GUARD(); + job = find_job_locked(id, errp); if (!job) { return; } trace_qmp_job_finalize(job); - job_ref(job); - job_finalize(job, errp); + job_ref_locked(job); + job_finalize_locked(job, errp); - /* - * Job's context might have changed via job_finalize (and job_txn_apply - * automatically acquires the new one), so make sure we release the correct - * one. - */ - aio_context = job->aio_context; - job_unref(job); - aio_context_release(aio_context); + job_unref_locked(job); } void qmp_job_dismiss(const char *id, Error **errp) { - AioContext *aio_context; - Job *job = find_job(id, &aio_context, errp); + Job *job; + + JOB_LOCK_GUARD(); + job = find_job_locked(id, errp); if (!job) { return; } trace_qmp_job_dismiss(job); - job_dismiss(&job, errp); - aio_context_release(aio_context); + job_dismiss_locked(&job, errp); } -static JobInfo *job_query_single(Job *job, Error **errp) +/* Called with job_mutex held. */ +static JobInfo *job_query_single_locked(Job *job, Error **errp) { JobInfo *info; uint64_t progress_current; @@ -171,17 +169,15 @@ JobInfoList *qmp_query_jobs(Error **errp) JobInfoList *head = NULL, **tail = &head; Job *job; - for (job = job_next(NULL); job; job = job_next(job)) { + JOB_LOCK_GUARD(); + + for (job = job_next_locked(NULL); job; job = job_next_locked(job)) { JobInfo *value; - AioContext *aio_context; if (job_is_internal(job)) { continue; } - aio_context = job->aio_context; - aio_context_acquire(aio_context); - value = job_query_single(job, errp); - aio_context_release(aio_context); + value = job_query_single_locked(job, errp); if (!value) { qapi_free_JobInfoList(head); return NULL; diff --git a/job.c b/job.c index 075c6f3a20..78feae05fb 100644 --- a/job.c +++ b/job.c @@ -32,6 +32,27 @@ #include "trace/trace-root.h" #include "qapi/qapi-events-job.h" +/* + * The job API is composed of two categories of functions. + * + * The first includes functions used by the monitor. The monitor is + * peculiar in that it accesses the job list with job_get, and + * therefore needs consistency across job_get and the actual operation + * (e.g. job_user_cancel). To achieve this consistency, the caller + * calls job_lock/job_unlock itself around the whole operation. + * + * + * The second includes functions used by the job drivers and sometimes + * by the core block layer. These delegate the locking to the callee instead. + */ + +/* + * job_mutex protects the jobs list, but also makes the + * struct job fields thread-safe. + */ +QemuMutex job_mutex; + +/* Protected by job_mutex */ static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); /* Job State Transition Table */ @@ -74,17 +95,12 @@ struct JobTxn { int refcnt; }; -/* Right now, this mutex is only needed to synchronize accesses to job->busy - * and job->sleep_timer, such as concurrent calls to job_do_yield and - * job_enter. */ -static QemuMutex job_mutex; - -static void job_lock(void) +void job_lock(void) { qemu_mutex_lock(&job_mutex); } -static void job_unlock(void) +void job_unlock(void) { qemu_mutex_unlock(&job_mutex); } @@ -102,19 +118,38 @@ JobTxn *job_txn_new(void) return txn; } -static void job_txn_ref(JobTxn *txn) +/* Called with job_mutex held. */ +static void job_txn_ref_locked(JobTxn *txn) { txn->refcnt++; } -void job_txn_unref(JobTxn *txn) +void job_txn_unref_locked(JobTxn *txn) { if (txn && --txn->refcnt == 0) { g_free(txn); } } -void job_txn_add_job(JobTxn *txn, Job *job) +void job_txn_unref(JobTxn *txn) +{ + JOB_LOCK_GUARD(); + job_txn_unref_locked(txn); +} + +/** + * @txn: The transaction (may be NULL) + * @job: Job to add to the transaction + * + * Add @job to the transaction. The @job must not already be in a transaction. + * The caller must call either job_txn_unref() or job_completed() to release + * the reference that is automatically grabbed here. + * + * If @txn is NULL, the function does nothing. + * + * Called with job_mutex held. + */ +static void job_txn_add_job_locked(JobTxn *txn, Job *job) { if (!txn) { return; @@ -124,21 +159,22 @@ void job_txn_add_job(JobTxn *txn, Job *job) job->txn = txn; QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); - job_txn_ref(txn); + job_txn_ref_locked(txn); } -static void job_txn_del_job(Job *job) +/* Called with job_mutex held. */ +static void job_txn_del_job_locked(Job *job) { if (job->txn) { QLIST_REMOVE(job, txn_list); - job_txn_unref(job->txn); + job_txn_unref_locked(job->txn); job->txn = NULL; } } -static int job_txn_apply(Job *job, int fn(Job *)) +/* Called with job_mutex held, but releases it temporarily. */ +static int job_txn_apply_locked(Job *job, int fn(Job *)) { - AioContext *inner_ctx; Job *other_job, *next; JobTxn *txn = job->txn; int rc = 0; @@ -149,25 +185,16 @@ static int job_txn_apply(Job *job, int fn(Job *)) * we need to release it here to avoid holding the lock twice - which would * break AIO_WAIT_WHILE from within fn. */ - job_ref(job); - aio_context_release(job->aio_context); + job_ref_locked(job); QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { - inner_ctx = other_job->aio_context; - aio_context_acquire(inner_ctx); rc = fn(other_job); - aio_context_release(inner_ctx); if (rc) { break; } } - /* - * Note that job->aio_context might have been changed by calling fn, so we - * can't use a local variable to cache it. - */ - aio_context_acquire(job->aio_context); - job_unref(job); + job_unref_locked(job); return rc; } @@ -176,7 +203,8 @@ bool job_is_internal(Job *job) return (job->id == NULL); } -static void job_state_transition(Job *job, JobStatus s1) +/* Called with job_mutex held. */ +static void job_state_transition_locked(Job *job, JobStatus s1) { JobStatus s0 = job->status; assert(s1 >= 0 && s1 < JOB_STATUS__MAX); @@ -191,7 +219,7 @@ static void job_state_transition(Job *job, JobStatus s1) } } -int job_apply_verb(Job *job, JobVerb verb, Error **errp) +int job_apply_verb_locked(Job *job, JobVerb verb, Error **errp) { JobStatus s0 = job->status; assert(verb >= 0 && verb < JOB_VERB__MAX); @@ -215,41 +243,60 @@ const char *job_type_str(const Job *job) return JobType_str(job_type(job)); } -bool job_is_cancelled(Job *job) +bool job_is_cancelled_locked(Job *job) { /* force_cancel may be true only if cancelled is true, too */ assert(job->cancelled || !job->force_cancel); return job->force_cancel; } -bool job_cancel_requested(Job *job) +bool job_is_cancelled(Job *job) +{ + JOB_LOCK_GUARD(); + return job_is_cancelled_locked(job); +} + +/* Called with job_mutex held. */ +static bool job_cancel_requested_locked(Job *job) { return job->cancelled; } +bool job_cancel_requested(Job *job) +{ + JOB_LOCK_GUARD(); + return job_cancel_requested_locked(job); +} + +bool job_is_ready_locked(Job *job) +{ + switch (job->status) { + case JOB_STATUS_UNDEFINED: + case JOB_STATUS_CREATED: + case JOB_STATUS_RUNNING: + case JOB_STATUS_PAUSED: + case JOB_STATUS_WAITING: + case JOB_STATUS_PENDING: + case JOB_STATUS_ABORTING: + case JOB_STATUS_CONCLUDED: + case JOB_STATUS_NULL: + return false; + case JOB_STATUS_READY: + case JOB_STATUS_STANDBY: + return true; + default: + g_assert_not_reached(); + } + return false; +} + bool job_is_ready(Job *job) { - switch (job->status) { - case JOB_STATUS_UNDEFINED: - case JOB_STATUS_CREATED: - case JOB_STATUS_RUNNING: - case JOB_STATUS_PAUSED: - case JOB_STATUS_WAITING: - case JOB_STATUS_PENDING: - case JOB_STATUS_ABORTING: - case JOB_STATUS_CONCLUDED: - case JOB_STATUS_NULL: - return false; - case JOB_STATUS_READY: - case JOB_STATUS_STANDBY: - return true; - default: - g_assert_not_reached(); - } - return false; + JOB_LOCK_GUARD(); + return job_is_ready_locked(job); } -bool job_is_completed(Job *job) +bool job_is_completed_locked(Job *job) { switch (job->status) { case JOB_STATUS_UNDEFINED: @@ -271,17 +318,24 @@ bool job_is_completed(Job *job) return false; } -static bool job_started(Job *job) +static bool job_is_completed(Job *job) +{ + JOB_LOCK_GUARD(); + return job_is_completed_locked(job); +} + +static bool job_started_locked(Job *job) { return job->co; } -static bool job_should_pause(Job *job) +/* Called with job_mutex held. */ +static bool job_should_pause_locked(Job *job) { return job->pause_count > 0; } -Job *job_next(Job *job) +Job *job_next_locked(Job *job) { if (!job) { return QLIST_FIRST(&jobs); @@ -289,7 +343,13 @@ Job *job_next(Job *job) return QLIST_NEXT(job, job_list); } -Job *job_get(const char *id) +Job *job_next(Job *job) +{ + JOB_LOCK_GUARD(); + return job_next_locked(job); +} + +Job *job_get_locked(const char *id) { Job *job; @@ -302,6 +362,18 @@ Job *job_get(const char *id) return NULL; } +void job_set_aio_context(Job *job, AioContext *ctx) +{ + /* protect against read in job_finish_sync_locked and job_start */ + GLOBAL_STATE_CODE(); + /* protect against read in job_do_yield_locked */ + JOB_LOCK_GUARD(); + /* ensure the job is quiescent while the AioContext is changed */ + assert(job->paused || job_is_completed_locked(job)); + job->aio_context = ctx; +} + +/* Called with job_mutex *not* held. */ static void job_sleep_timer_cb(void *opaque) { Job *job = opaque; @@ -315,6 +387,8 @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, { Job *job; + JOB_LOCK_GUARD(); + if (job_id) { if (flags & JOB_INTERNAL) { error_setg(errp, "Cannot specify job ID for internal job"); @@ -324,7 +398,7 @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, error_setg(errp, "Invalid job ID '%s'", job_id); return NULL; } - if (job_get(job_id)) { + if (job_get_locked(job_id)) { error_setg(errp, "Job ID '%s' already in use", job_id); return NULL; } @@ -354,7 +428,7 @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, notifier_list_init(&job->on_ready); notifier_list_init(&job->on_idle); - job_state_transition(job, JOB_STATUS_CREATED); + job_state_transition_locked(job, JOB_STATUS_CREATED); aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, QEMU_CLOCK_REALTIME, SCALE_NS, job_sleep_timer_cb, job); @@ -365,21 +439,21 @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, * consolidating the job management logic */ if (!txn) { txn = job_txn_new(); - job_txn_add_job(txn, job); - job_txn_unref(txn); + job_txn_add_job_locked(txn, job); + job_txn_unref_locked(txn); } else { - job_txn_add_job(txn, job); + job_txn_add_job_locked(txn, job); } return job; } -void job_ref(Job *job) +void job_ref_locked(Job *job) { ++job->refcnt; } -void job_unref(Job *job) +void job_unref_locked(Job *job) { GLOBAL_STATE_CODE(); @@ -389,7 +463,13 @@ void job_unref(Job *job) assert(!job->txn); if (job->driver->free) { + AioContext *aio_context = job->aio_context; + job_unlock(); + /* FIXME: aiocontext lock is required because cb calls blk_unref */ + aio_context_acquire(aio_context); job->driver->free(job); + aio_context_release(aio_context); + job_lock(); } QLIST_REMOVE(job, job_list); @@ -416,48 +496,56 @@ void job_progress_increase_remaining(Job *job, uint64_t delta) progress_increase_remaining(&job->progress, delta); } -void job_event_cancelled(Job *job) +/** + * To be called when a cancelled job is finalised. + * Called with job_mutex held. + */ +static void job_event_cancelled_locked(Job *job) { notifier_list_notify(&job->on_finalize_cancelled, job); } -void job_event_completed(Job *job) +/** + * To be called when a successfully completed job is finalised. + * Called with job_mutex held. + */ +static void job_event_completed_locked(Job *job) { notifier_list_notify(&job->on_finalize_completed, job); } -static void job_event_pending(Job *job) +/* Called with job_mutex held. */ +static void job_event_pending_locked(Job *job) { notifier_list_notify(&job->on_pending, job); } -static void job_event_ready(Job *job) +/* Called with job_mutex held. */ +static void job_event_ready_locked(Job *job) { notifier_list_notify(&job->on_ready, job); } -static void job_event_idle(Job *job) +/* Called with job_mutex held. */ +static void job_event_idle_locked(Job *job) { notifier_list_notify(&job->on_idle, job); } -void job_enter_cond(Job *job, bool(*fn)(Job *job)) +void job_enter_cond_locked(Job *job, bool(*fn)(Job *job)) { - if (!job_started(job)) { + if (!job_started_locked(job)) { return; } if (job->deferred_to_main_loop) { return; } - job_lock(); if (job->busy) { - job_unlock(); return; } if (fn && !fn(job)) { - job_unlock(); return; } @@ -465,12 +553,14 @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)) timer_del(&job->sleep_timer); job->busy = true; job_unlock(); - aio_co_enter(job->aio_context, job->co); + aio_co_wake(job->co); + job_lock(); } void job_enter(Job *job) { - job_enter_cond(job, NULL); + JOB_LOCK_GUARD(); + job_enter_cond_locked(job, NULL); } /* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. @@ -478,100 +568,137 @@ void job_enter(Job *job) * is allowed and cancels the timer. * * If @ns is (uint64_t) -1, no timer is scheduled and job_enter() must be - * called explicitly. */ -static void coroutine_fn job_do_yield(Job *job, uint64_t ns) + * called explicitly. + * + * Called with job_mutex held, but releases it temporarily. + */ +static void coroutine_fn job_do_yield_locked(Job *job, uint64_t ns) { - job_lock(); + AioContext *next_aio_context; + if (ns != -1) { timer_mod(&job->sleep_timer, ns); } job->busy = false; - job_event_idle(job); + job_event_idle_locked(job); job_unlock(); qemu_coroutine_yield(); + job_lock(); - /* Set by job_enter_cond() before re-entering the coroutine. */ + next_aio_context = job->aio_context; + /* + * Coroutine has resumed, but in the meanwhile the job AioContext + * might have changed via bdrv_try_set_aio_context(), so we need to move + * the coroutine too in the new aiocontext. + */ + while (qemu_get_current_aio_context() != next_aio_context) { + job_unlock(); + aio_co_reschedule_self(next_aio_context); + job_lock(); + next_aio_context = job->aio_context; + } + + /* Set by job_enter_cond_locked() before re-entering the coroutine. */ assert(job->busy); } -void coroutine_fn job_pause_point(Job *job) +/* Called with job_mutex held, but releases it temporarily. */ +static void coroutine_fn job_pause_point_locked(Job *job) { - assert(job && job_started(job)); + assert(job && job_started_locked(job)); - if (!job_should_pause(job)) { + if (!job_should_pause_locked(job)) { return; } - if (job_is_cancelled(job)) { + if (job_is_cancelled_locked(job)) { return; } if (job->driver->pause) { + job_unlock(); job->driver->pause(job); + job_lock(); } - if (job_should_pause(job) && !job_is_cancelled(job)) { + if (job_should_pause_locked(job) && !job_is_cancelled_locked(job)) { JobStatus status = job->status; - job_state_transition(job, status == JOB_STATUS_READY - ? JOB_STATUS_STANDBY - : JOB_STATUS_PAUSED); + job_state_transition_locked(job, status == JOB_STATUS_READY + ? JOB_STATUS_STANDBY + : JOB_STATUS_PAUSED); job->paused = true; - job_do_yield(job, -1); + job_do_yield_locked(job, -1); job->paused = false; - job_state_transition(job, status); + job_state_transition_locked(job, status); } if (job->driver->resume) { + job_unlock(); job->driver->resume(job); + job_lock(); } } -void job_yield(Job *job) +void coroutine_fn job_pause_point(Job *job) { + JOB_LOCK_GUARD(); + job_pause_point_locked(job); +} + +void coroutine_fn job_yield(Job *job) +{ + JOB_LOCK_GUARD(); assert(job->busy); /* Check cancellation *before* setting busy = false, too! */ - if (job_is_cancelled(job)) { + if (job_is_cancelled_locked(job)) { return; } - if (!job_should_pause(job)) { - job_do_yield(job, -1); + if (!job_should_pause_locked(job)) { + job_do_yield_locked(job, -1); } - job_pause_point(job); + job_pause_point_locked(job); } void coroutine_fn job_sleep_ns(Job *job, int64_t ns) { + JOB_LOCK_GUARD(); assert(job->busy); /* Check cancellation *before* setting busy = false, too! */ - if (job_is_cancelled(job)) { + if (job_is_cancelled_locked(job)) { return; } - if (!job_should_pause(job)) { - job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); + if (!job_should_pause_locked(job)) { + job_do_yield_locked(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); } - job_pause_point(job); + job_pause_point_locked(job); } -/* Assumes the block_job_mutex is held */ -static bool job_timer_not_pending(Job *job) +/* Assumes the job_mutex is held */ +static bool job_timer_not_pending_locked(Job *job) { return !timer_pending(&job->sleep_timer); } -void job_pause(Job *job) +void job_pause_locked(Job *job) { job->pause_count++; if (!job->paused) { - job_enter(job); + job_enter_cond_locked(job, NULL); } } -void job_resume(Job *job) +void job_pause(Job *job) +{ + JOB_LOCK_GUARD(); + job_pause_locked(job); +} + +void job_resume_locked(Job *job) { assert(job->pause_count > 0); job->pause_count--; @@ -580,12 +707,18 @@ void job_resume(Job *job) } /* kick only if no timer is pending */ - job_enter_cond(job, job_timer_not_pending); + job_enter_cond_locked(job, job_timer_not_pending_locked); } -void job_user_pause(Job *job, Error **errp) +void job_resume(Job *job) { - if (job_apply_verb(job, JOB_VERB_PAUSE, errp)) { + JOB_LOCK_GUARD(); + job_resume_locked(job); +} + +void job_user_pause_locked(Job *job, Error **errp) +{ + if (job_apply_verb_locked(job, JOB_VERB_PAUSE, errp)) { return; } if (job->user_paused) { @@ -593,15 +726,15 @@ void job_user_pause(Job *job, Error **errp) return; } job->user_paused = true; - job_pause(job); + job_pause_locked(job); } -bool job_user_paused(Job *job) +bool job_user_paused_locked(Job *job) { return job->user_paused; } -void job_user_resume(Job *job, Error **errp) +void job_user_resume_locked(Job *job, Error **errp) { assert(job); GLOBAL_STATE_CODE(); @@ -609,66 +742,72 @@ void job_user_resume(Job *job, Error **errp) error_setg(errp, "Can't resume a job that was not paused"); return; } - if (job_apply_verb(job, JOB_VERB_RESUME, errp)) { + if (job_apply_verb_locked(job, JOB_VERB_RESUME, errp)) { return; } if (job->driver->user_resume) { + job_unlock(); job->driver->user_resume(job); + job_lock(); } job->user_paused = false; - job_resume(job); + job_resume_locked(job); } -static void job_do_dismiss(Job *job) +/* Called with job_mutex held, but releases it temporarily. */ +static void job_do_dismiss_locked(Job *job) { assert(job); job->busy = false; job->paused = false; job->deferred_to_main_loop = true; - job_txn_del_job(job); + job_txn_del_job_locked(job); - job_state_transition(job, JOB_STATUS_NULL); - job_unref(job); + job_state_transition_locked(job, JOB_STATUS_NULL); + job_unref_locked(job); } -void job_dismiss(Job **jobptr, Error **errp) +void job_dismiss_locked(Job **jobptr, Error **errp) { Job *job = *jobptr; /* similarly to _complete, this is QMP-interface only. */ assert(job->id); - if (job_apply_verb(job, JOB_VERB_DISMISS, errp)) { + if (job_apply_verb_locked(job, JOB_VERB_DISMISS, errp)) { return; } - job_do_dismiss(job); + job_do_dismiss_locked(job); *jobptr = NULL; } void job_early_fail(Job *job) { + JOB_LOCK_GUARD(); assert(job->status == JOB_STATUS_CREATED); - job_do_dismiss(job); + job_do_dismiss_locked(job); } -static void job_conclude(Job *job) +/* Called with job_mutex held. */ +static void job_conclude_locked(Job *job) { - job_state_transition(job, JOB_STATUS_CONCLUDED); - if (job->auto_dismiss || !job_started(job)) { - job_do_dismiss(job); + job_state_transition_locked(job, JOB_STATUS_CONCLUDED); + if (job->auto_dismiss || !job_started_locked(job)) { + job_do_dismiss_locked(job); } } -static void job_update_rc(Job *job) +/* Called with job_mutex held. */ +static void job_update_rc_locked(Job *job) { - if (!job->ret && job_is_cancelled(job)) { + if (!job->ret && job_is_cancelled_locked(job)) { job->ret = -ECANCELED; } if (job->ret) { if (!job->err) { error_setg(&job->err, "%s", strerror(-job->ret)); } - job_state_transition(job, JOB_STATUS_ABORTING); + job_state_transition_locked(job, JOB_STATUS_ABORTING); } } @@ -698,14 +837,25 @@ static void job_clean(Job *job) } } -static int job_finalize_single(Job *job) +/* + * Called with job_mutex held, but releases it temporarily. + * Takes AioContext lock internally to invoke a job->driver callback. + */ +static int job_finalize_single_locked(Job *job) { - assert(job_is_completed(job)); + int job_ret; + AioContext *ctx = job->aio_context; + + assert(job_is_completed_locked(job)); /* Ensure abort is called for late-transactional failures */ - job_update_rc(job); + job_update_rc_locked(job); - if (!job->ret) { + job_ret = job->ret; + job_unlock(); + aio_context_acquire(ctx); + + if (!job_ret) { job_commit(job); } else { job_abort(job); @@ -713,28 +863,40 @@ static int job_finalize_single(Job *job) job_clean(job); if (job->cb) { - job->cb(job->opaque, job->ret); + job->cb(job->opaque, job_ret); } + aio_context_release(ctx); + job_lock(); + /* Emit events only if we actually started */ - if (job_started(job)) { - if (job_is_cancelled(job)) { - job_event_cancelled(job); + if (job_started_locked(job)) { + if (job_is_cancelled_locked(job)) { + job_event_cancelled_locked(job); } else { - job_event_completed(job); + job_event_completed_locked(job); } } - job_txn_del_job(job); - job_conclude(job); + job_txn_del_job_locked(job); + job_conclude_locked(job); return 0; } -static void job_cancel_async(Job *job, bool force) +/* + * Called with job_mutex held, but releases it temporarily. + * Takes AioContext lock internally to invoke a job->driver callback. + */ +static void job_cancel_async_locked(Job *job, bool force) { + AioContext *ctx = job->aio_context; GLOBAL_STATE_CODE(); if (job->driver->cancel) { + job_unlock(); + aio_context_acquire(ctx); force = job->driver->cancel(job, force); + aio_context_release(ctx); + job_lock(); } else { /* No .cancel() means the job will behave as if force-cancelled */ force = true; @@ -743,7 +905,9 @@ static void job_cancel_async(Job *job, bool force) if (job->user_paused) { /* Do not call job_enter here, the caller will handle it. */ if (job->driver->user_resume) { + job_unlock(); job->driver->user_resume(job); + job_lock(); } job->user_paused = false; assert(job->pause_count > 0); @@ -764,9 +928,12 @@ static void job_cancel_async(Job *job, bool force) } } -static void job_completed_txn_abort(Job *job) +/* + * Called with job_mutex held, but releases it temporarily. + * Takes AioContext lock internally to invoke a job->driver callback. + */ +static void job_completed_txn_abort_locked(Job *job) { - AioContext *ctx; JobTxn *txn = job->txn; Job *other_job; @@ -777,178 +944,164 @@ static void job_completed_txn_abort(Job *job) return; } txn->aborting = true; - job_txn_ref(txn); + job_txn_ref_locked(txn); - /* - * We can only hold the single job's AioContext lock while calling - * job_finalize_single() because the finalization callbacks can involve - * calls of AIO_WAIT_WHILE(), which could deadlock otherwise. - * Note that the job's AioContext may change when it is finalized. - */ - job_ref(job); - aio_context_release(job->aio_context); + job_ref_locked(job); /* Other jobs are effectively cancelled by us, set the status for * them; this job, however, may or may not be cancelled, depending * on the caller, so leave it. */ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { if (other_job != job) { - ctx = other_job->aio_context; - aio_context_acquire(ctx); /* * This is a transaction: If one job failed, no result will matter. * Therefore, pass force=true to terminate all other jobs as quickly * as possible. */ - job_cancel_async(other_job, true); - aio_context_release(ctx); + job_cancel_async_locked(other_job, true); } } while (!QLIST_EMPTY(&txn->jobs)) { other_job = QLIST_FIRST(&txn->jobs); - /* - * The job's AioContext may change, so store it in @ctx so we - * release the same context that we have acquired before. - */ - ctx = other_job->aio_context; - aio_context_acquire(ctx); - if (!job_is_completed(other_job)) { - assert(job_cancel_requested(other_job)); - job_finish_sync(other_job, NULL, NULL); + if (!job_is_completed_locked(other_job)) { + assert(job_cancel_requested_locked(other_job)); + job_finish_sync_locked(other_job, NULL, NULL); } - job_finalize_single(other_job); - aio_context_release(ctx); + job_finalize_single_locked(other_job); } - /* - * Use job_ref()/job_unref() so we can read the AioContext here - * even if the job went away during job_finalize_single(). - */ - aio_context_acquire(job->aio_context); - job_unref(job); - - job_txn_unref(txn); + job_unref_locked(job); + job_txn_unref_locked(txn); } -static int job_prepare(Job *job) +/* Called with job_mutex held, but releases it temporarily */ +static int job_prepare_locked(Job *job) { + int ret; + AioContext *ctx = job->aio_context; + GLOBAL_STATE_CODE(); + if (job->ret == 0 && job->driver->prepare) { - job->ret = job->driver->prepare(job); - job_update_rc(job); + job_unlock(); + aio_context_acquire(ctx); + ret = job->driver->prepare(job); + aio_context_release(ctx); + job_lock(); + job->ret = ret; + job_update_rc_locked(job); } + return job->ret; } -static int job_needs_finalize(Job *job) +/* Called with job_mutex held */ +static int job_needs_finalize_locked(Job *job) { return !job->auto_finalize; } -static void job_do_finalize(Job *job) +/* Called with job_mutex held */ +static void job_do_finalize_locked(Job *job) { int rc; assert(job && job->txn); /* prepare the transaction to complete */ - rc = job_txn_apply(job, job_prepare); + rc = job_txn_apply_locked(job, job_prepare_locked); if (rc) { - job_completed_txn_abort(job); + job_completed_txn_abort_locked(job); } else { - job_txn_apply(job, job_finalize_single); + job_txn_apply_locked(job, job_finalize_single_locked); } } -void job_finalize(Job *job, Error **errp) +void job_finalize_locked(Job *job, Error **errp) { assert(job && job->id); - if (job_apply_verb(job, JOB_VERB_FINALIZE, errp)) { + if (job_apply_verb_locked(job, JOB_VERB_FINALIZE, errp)) { return; } - job_do_finalize(job); + job_do_finalize_locked(job); } -static int job_transition_to_pending(Job *job) +/* Called with job_mutex held. */ +static int job_transition_to_pending_locked(Job *job) { - job_state_transition(job, JOB_STATUS_PENDING); + job_state_transition_locked(job, JOB_STATUS_PENDING); if (!job->auto_finalize) { - job_event_pending(job); + job_event_pending_locked(job); } return 0; } void job_transition_to_ready(Job *job) { - job_state_transition(job, JOB_STATUS_READY); - job_event_ready(job); + JOB_LOCK_GUARD(); + job_state_transition_locked(job, JOB_STATUS_READY); + job_event_ready_locked(job); } -static void job_completed_txn_success(Job *job) +/* Called with job_mutex held. */ +static void job_completed_txn_success_locked(Job *job) { JobTxn *txn = job->txn; Job *other_job; - job_state_transition(job, JOB_STATUS_WAITING); + job_state_transition_locked(job, JOB_STATUS_WAITING); /* * Successful completion, see if there are other running jobs in this * txn. */ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { - if (!job_is_completed(other_job)) { + if (!job_is_completed_locked(other_job)) { return; } assert(other_job->ret == 0); } - job_txn_apply(job, job_transition_to_pending); + job_txn_apply_locked(job, job_transition_to_pending_locked); /* If no jobs need manual finalization, automatically do so */ - if (job_txn_apply(job, job_needs_finalize) == 0) { - job_do_finalize(job); + if (job_txn_apply_locked(job, job_needs_finalize_locked) == 0) { + job_do_finalize_locked(job); } } -static void job_completed(Job *job) +/* Called with job_mutex held. */ +static void job_completed_locked(Job *job) { - assert(job && job->txn && !job_is_completed(job)); + assert(job && job->txn && !job_is_completed_locked(job)); - job_update_rc(job); + job_update_rc_locked(job); trace_job_completed(job, job->ret); if (job->ret) { - job_completed_txn_abort(job); + job_completed_txn_abort_locked(job); } else { - job_completed_txn_success(job); + job_completed_txn_success_locked(job); } } -/** Useful only as a type shim for aio_bh_schedule_oneshot. */ +/** + * Useful only as a type shim for aio_bh_schedule_oneshot. + * Called with job_mutex *not* held. + */ static void job_exit(void *opaque) { Job *job = (Job *)opaque; - AioContext *ctx; - - job_ref(job); - aio_context_acquire(job->aio_context); + JOB_LOCK_GUARD(); + job_ref_locked(job); /* This is a lie, we're not quiescent, but still doing the completion * callbacks. However, completion callbacks tend to involve operations that * drain block nodes, and if .drained_poll still returned true, we would * deadlock. */ job->busy = false; - job_event_idle(job); + job_event_idle_locked(job); - job_completed(job); - - /* - * Note that calling job_completed can move the job to a different - * aio_context, so we cannot cache from above. job_txn_apply takes care of - * acquiring the new lock, and we ref/unref to avoid job_completed freeing - * the job underneath us. - */ - ctx = job->aio_context; - job_unref(job); - aio_context_release(ctx); + job_completed_locked(job); + job_unref_locked(job); } /** @@ -958,37 +1111,47 @@ static void job_exit(void *opaque) static void coroutine_fn job_co_entry(void *opaque) { Job *job = opaque; + int ret; assert(job && job->driver && job->driver->run); - assert(job->aio_context == qemu_get_current_aio_context()); - job_pause_point(job); - job->ret = job->driver->run(job, &job->err); - job->deferred_to_main_loop = true; - job->busy = true; + WITH_JOB_LOCK_GUARD() { + assert(job->aio_context == qemu_get_current_aio_context()); + job_pause_point_locked(job); + } + ret = job->driver->run(job, &job->err); + WITH_JOB_LOCK_GUARD() { + job->ret = ret; + job->deferred_to_main_loop = true; + job->busy = true; + } aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); } void job_start(Job *job) { - assert(job && !job_started(job) && job->paused && - job->driver && job->driver->run); - job->co = qemu_coroutine_create(job_co_entry, job); - job->pause_count--; - job->busy = true; - job->paused = false; - job_state_transition(job, JOB_STATUS_RUNNING); + assert(qemu_in_main_thread()); + + WITH_JOB_LOCK_GUARD() { + assert(job && !job_started_locked(job) && job->paused && + job->driver && job->driver->run); + job->co = qemu_coroutine_create(job_co_entry, job); + job->pause_count--; + job->busy = true; + job->paused = false; + job_state_transition_locked(job, JOB_STATUS_RUNNING); + } aio_co_enter(job->aio_context, job->co); } -void job_cancel(Job *job, bool force) +void job_cancel_locked(Job *job, bool force) { if (job->status == JOB_STATUS_CONCLUDED) { - job_do_dismiss(job); + job_do_dismiss_locked(job); return; } - job_cancel_async(job, force); - if (!job_started(job)) { - job_completed(job); + job_cancel_async_locked(job, force); + if (!job_started_locked(job)) { + job_completed_locked(job); } else if (job->deferred_to_main_loop) { /* * job_cancel_async() ignores soft-cancel requests for jobs @@ -1000,102 +1163,117 @@ void job_cancel(Job *job, bool force) * choose to call job_is_cancelled() to show that we invoke * job_completed_txn_abort() only for force-cancelled jobs.) */ - if (job_is_cancelled(job)) { - job_completed_txn_abort(job); + if (job_is_cancelled_locked(job)) { + job_completed_txn_abort_locked(job); } } else { - job_enter(job); + job_enter_cond_locked(job, NULL); } } -void job_user_cancel(Job *job, bool force, Error **errp) +void job_user_cancel_locked(Job *job, bool force, Error **errp) { - if (job_apply_verb(job, JOB_VERB_CANCEL, errp)) { + if (job_apply_verb_locked(job, JOB_VERB_CANCEL, errp)) { return; } - job_cancel(job, force); + job_cancel_locked(job, force); } -/* A wrapper around job_cancel() taking an Error ** parameter so it may be - * used with job_finish_sync() without the need for (rather nasty) function - * pointer casts there. */ -static void job_cancel_err(Job *job, Error **errp) +/* A wrapper around job_cancel_locked() taking an Error ** parameter so it may + * be used with job_finish_sync_locked() without the need for (rather nasty) + * function pointer casts there. + * + * Called with job_mutex held. + */ +static void job_cancel_err_locked(Job *job, Error **errp) { - job_cancel(job, false); + job_cancel_locked(job, false); } /** * Same as job_cancel_err(), but force-cancel. + * Called with job_mutex held. */ -static void job_force_cancel_err(Job *job, Error **errp) +static void job_force_cancel_err_locked(Job *job, Error **errp) { - job_cancel(job, true); + job_cancel_locked(job, true); +} + +int job_cancel_sync_locked(Job *job, bool force) +{ + if (force) { + return job_finish_sync_locked(job, &job_force_cancel_err_locked, NULL); + } else { + return job_finish_sync_locked(job, &job_cancel_err_locked, NULL); + } } int job_cancel_sync(Job *job, bool force) { - if (force) { - return job_finish_sync(job, &job_force_cancel_err, NULL); - } else { - return job_finish_sync(job, &job_cancel_err, NULL); - } + JOB_LOCK_GUARD(); + return job_cancel_sync_locked(job, force); } void job_cancel_sync_all(void) { Job *job; - AioContext *aio_context; + JOB_LOCK_GUARD(); - while ((job = job_next(NULL))) { - aio_context = job->aio_context; - aio_context_acquire(aio_context); - job_cancel_sync(job, true); - aio_context_release(aio_context); + while ((job = job_next_locked(NULL))) { + job_cancel_sync_locked(job, true); } } -int job_complete_sync(Job *job, Error **errp) +int job_complete_sync_locked(Job *job, Error **errp) { - return job_finish_sync(job, job_complete, errp); + return job_finish_sync_locked(job, job_complete_locked, errp); } -void job_complete(Job *job, Error **errp) +void job_complete_locked(Job *job, Error **errp) { /* Should not be reachable via external interface for internal jobs */ assert(job->id); GLOBAL_STATE_CODE(); - if (job_apply_verb(job, JOB_VERB_COMPLETE, errp)) { + if (job_apply_verb_locked(job, JOB_VERB_COMPLETE, errp)) { return; } - if (job_cancel_requested(job) || !job->driver->complete) { + if (job_cancel_requested_locked(job) || !job->driver->complete) { error_setg(errp, "The active block job '%s' cannot be completed", job->id); return; } + job_unlock(); job->driver->complete(job, errp); + job_lock(); } -int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) +int job_finish_sync_locked(Job *job, + void (*finish)(Job *, Error **errp), + Error **errp) { Error *local_err = NULL; int ret; + GLOBAL_STATE_CODE(); - job_ref(job); + job_ref_locked(job); if (finish) { finish(job, &local_err); } if (local_err) { error_propagate(errp, local_err); - job_unref(job); + job_unref_locked(job); return -EBUSY; } - AIO_WAIT_WHILE(job->aio_context, - (job_enter(job), !job_is_completed(job))); + job_unlock(); + AIO_WAIT_WHILE_UNLOCKED(job->aio_context, + (job_enter(job), !job_is_completed(job))); + job_lock(); - ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret; - job_unref(job); + ret = (job_is_cancelled_locked(job) && job->ret == 0) + ? -ECANCELED : job->ret; + job_unref_locked(job); return ret; } diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 5c28a9737a..4bf2d7246e 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -75,9 +75,11 @@ struct kvm_regs { /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ #define KVM_ARM_DEVICE_TYPE_SHIFT 0 -#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT) +#define KVM_ARM_DEVICE_TYPE_MASK GENMASK(KVM_ARM_DEVICE_TYPE_SHIFT + 15, \ + KVM_ARM_DEVICE_TYPE_SHIFT) #define KVM_ARM_DEVICE_ID_SHIFT 16 -#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT) +#define KVM_ARM_DEVICE_ID_MASK GENMASK(KVM_ARM_DEVICE_ID_SHIFT + 15, \ + KVM_ARM_DEVICE_ID_SHIFT) /* Supported device IDs */ #define KVM_ARM_DEVICE_VGIC_V2 0 @@ -139,8 +141,10 @@ struct kvm_guest_debug_arch { __u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS]; }; +#define KVM_DEBUG_ARCH_HSR_HIGH_VALID (1 << 0) struct kvm_debug_exit_arch { __u32 hsr; + __u32 hsr_high; /* ESR_EL2[61:32] */ __u64 far; /* used for watchpoints */ }; @@ -332,6 +336,31 @@ struct kvm_arm_copy_mte_tags { #define KVM_ARM64_SVE_VLS_WORDS \ ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1) +/* Bitmap feature firmware registers */ +#define KVM_REG_ARM_FW_FEAT_BMAP (0x0016 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_FW_FEAT_BMAP | \ + ((r) & 0xffff)) + +#define KVM_REG_ARM_STD_BMAP KVM_REG_ARM_FW_FEAT_BMAP_REG(0) + +enum { + KVM_REG_ARM_STD_BIT_TRNG_V1_0 = 0, +}; + +#define KVM_REG_ARM_STD_HYP_BMAP KVM_REG_ARM_FW_FEAT_BMAP_REG(1) + +enum { + KVM_REG_ARM_STD_HYP_BIT_PV_TIME = 0, +}; + +#define KVM_REG_ARM_VENDOR_HYP_BMAP KVM_REG_ARM_FW_FEAT_BMAP_REG(2) + +enum { + KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT = 0, + KVM_REG_ARM_VENDOR_HYP_BIT_PTP = 1, +}; + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 diff --git a/linux-headers/asm-generic/unistd.h b/linux-headers/asm-generic/unistd.h index 1c48b0ae3b..45fa180cc5 100644 --- a/linux-headers/asm-generic/unistd.h +++ b/linux-headers/asm-generic/unistd.h @@ -383,7 +383,7 @@ __SYSCALL(__NR_syslog, sys_syslog) /* kernel/ptrace.c */ #define __NR_ptrace 117 -__SYSCALL(__NR_ptrace, sys_ptrace) +__SC_COMP(__NR_ptrace, sys_ptrace, compat_sys_ptrace) /* kernel/sched/core.c */ #define __NR_sched_setparam 118 @@ -779,7 +779,7 @@ __SYSCALL(__NR_rseq, sys_rseq) #define __NR_kexec_file_load 294 __SYSCALL(__NR_kexec_file_load, sys_kexec_file_load) /* 295 through 402 are unassigned to sync up with generic numbers, don't use */ -#if __BITS_PER_LONG == 32 +#if defined(__SYSCALL_COMPAT) || __BITS_PER_LONG == 32 #define __NR_clock_gettime64 403 __SYSCALL(__NR_clock_gettime64, sys_clock_gettime) #define __NR_clock_settime64 404 diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h index f808ad1ce5..7351417afd 100644 --- a/linux-headers/asm-riscv/kvm.h +++ b/linux-headers/asm-riscv/kvm.h @@ -82,6 +82,25 @@ struct kvm_riscv_timer { __u64 state; }; +/* + * ISA extension IDs specific to KVM. This is not the same as the host ISA + * extension IDs as that is internal to the host and should not be exposed + * to the guest. This should always be contiguous to keep the mapping simple + * in KVM implementation. + */ +enum KVM_RISCV_ISA_EXT_ID { + KVM_RISCV_ISA_EXT_A = 0, + KVM_RISCV_ISA_EXT_C, + KVM_RISCV_ISA_EXT_D, + KVM_RISCV_ISA_EXT_F, + KVM_RISCV_ISA_EXT_H, + KVM_RISCV_ISA_EXT_I, + KVM_RISCV_ISA_EXT_M, + KVM_RISCV_ISA_EXT_SVPBMT, + KVM_RISCV_ISA_EXT_SSTC, + KVM_RISCV_ISA_EXT_MAX, +}; + /* Possible states for kvm_riscv_timer */ #define KVM_RISCV_TIMER_STATE_OFF 0 #define KVM_RISCV_TIMER_STATE_ON 1 @@ -123,6 +142,9 @@ struct kvm_riscv_timer { #define KVM_REG_RISCV_FP_D_REG(name) \ (offsetof(struct __riscv_d_ext_state, name) / sizeof(__u64)) +/* ISA Extension registers are mapped as type 7 */ +#define KVM_REG_RISCV_ISA_EXT (0x07 << KVM_REG_RISCV_TYPE_SHIFT) + #endif #endif /* __LINUX_KVM_RISCV_H */ diff --git a/linux-headers/asm-riscv/unistd.h b/linux-headers/asm-riscv/unistd.h index 8062996c2d..73d7cdd2ec 100644 --- a/linux-headers/asm-riscv/unistd.h +++ b/linux-headers/asm-riscv/unistd.h @@ -15,12 +15,13 @@ * along with this program. If not, see . */ -#ifdef __LP64__ +#if defined(__LP64__) && !defined(__SYSCALL_COMPAT) #define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_SET_GET_RLIMIT #endif /* __LP64__ */ #define __ARCH_WANT_SYS_CLONE3 +#define __ARCH_WANT_MEMFD_SECRET #include diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h index f053b8304a..e2afd95420 100644 --- a/linux-headers/asm-s390/kvm.h +++ b/linux-headers/asm-s390/kvm.h @@ -74,6 +74,7 @@ struct kvm_s390_io_adapter_req { #define KVM_S390_VM_CRYPTO 2 #define KVM_S390_VM_CPU_MODEL 3 #define KVM_S390_VM_MIGRATION 4 +#define KVM_S390_VM_CPU_TOPOLOGY 5 /* kvm attributes for mem_ctrl */ #define KVM_S390_VM_MEM_ENABLE_CMMA 0 diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index bf6e96011d..46de10a809 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -198,13 +198,13 @@ struct kvm_msrs { __u32 nmsrs; /* number of msrs in entries */ __u32 pad; - struct kvm_msr_entry entries[0]; + struct kvm_msr_entry entries[]; }; /* for KVM_GET_MSR_INDEX_LIST */ struct kvm_msr_list { __u32 nmsrs; /* number of msrs in entries */ - __u32 indices[0]; + __u32 indices[]; }; /* Maximum size of any access bitmap in bytes */ @@ -241,7 +241,7 @@ struct kvm_cpuid_entry { struct kvm_cpuid { __u32 nent; __u32 padding; - struct kvm_cpuid_entry entries[0]; + struct kvm_cpuid_entry entries[]; }; struct kvm_cpuid_entry2 { @@ -263,7 +263,7 @@ struct kvm_cpuid_entry2 { struct kvm_cpuid2 { __u32 nent; __u32 padding; - struct kvm_cpuid_entry2 entries[0]; + struct kvm_cpuid_entry2 entries[]; }; /* for KVM_GET_PIT and KVM_SET_PIT */ @@ -306,7 +306,8 @@ struct kvm_pit_state { struct kvm_pit_channel_state channels[3]; }; -#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001 +#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001 +#define KVM_PIT_FLAGS_SPEAKER_DATA_ON 0x00000002 struct kvm_pit_state2 { struct kvm_pit_channel_state channels[3]; @@ -325,6 +326,7 @@ struct kvm_reinject_control { #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 #define KVM_VCPUEVENT_VALID_SMM 0x00000008 #define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010 +#define KVM_VCPUEVENT_VALID_TRIPLE_FAULT 0x00000020 /* Interrupt shadow states */ #define KVM_X86_SHADOW_INT_MOV_SS 0x01 @@ -359,7 +361,10 @@ struct kvm_vcpu_events { __u8 smm_inside_nmi; __u8 latched_init; } smi; - __u8 reserved[27]; + struct { + __u8 pending; + } triple_fault; + __u8 reserved[26]; __u8 exception_has_payload; __u64 exception_payload; }; @@ -389,7 +394,7 @@ struct kvm_xsave { * the contents of CPUID leaf 0xD on the host. */ __u32 region[1024]; - __u32 extra[0]; + __u32 extra[]; }; #define KVM_MAX_XCRS 16 @@ -428,11 +433,13 @@ struct kvm_sync_regs { struct kvm_vcpu_events events; }; -#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) -#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) -#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) -#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) -#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) +#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) +#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) +#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) +#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) +#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) +#define KVM_X86_QUIRK_FIX_HYPERCALL_INSN (1 << 5) +#define KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS (1 << 6) #define KVM_STATE_NESTED_FORMAT_VMX 0 #define KVM_STATE_NESTED_FORMAT_SVM 1 @@ -515,7 +522,7 @@ struct kvm_pmu_event_filter { __u32 fixed_counter_bitmap; __u32 flags; __u32 pad[4]; - __u64 events[0]; + __u64 events[]; }; #define KVM_PMU_EVENT_ALLOW 0 diff --git a/linux-headers/asm-x86/mman.h b/linux-headers/asm-x86/mman.h index d4a8d0424b..775dbd3aff 100644 --- a/linux-headers/asm-x86/mman.h +++ b/linux-headers/asm-x86/mman.h @@ -5,20 +5,6 @@ #define MAP_32BIT 0x40 /* only give out 32bit addresses */ #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS -/* - * Take the 4 protection key bits out of the vma->vm_flags - * value and turn them in to the bits that we can put in - * to a pte. - * - * Only override these if Protection Keys are available - * (which is only on 64-bit). - */ -#define arch_vm_get_page_prot(vm_flags) __pgprot( \ - ((vm_flags) & VM_PKEY_BIT0 ? _PAGE_PKEY_BIT0 : 0) | \ - ((vm_flags) & VM_PKEY_BIT1 ? _PAGE_PKEY_BIT1 : 0) | \ - ((vm_flags) & VM_PKEY_BIT2 ? _PAGE_PKEY_BIT2 : 0) | \ - ((vm_flags) & VM_PKEY_BIT3 ? _PAGE_PKEY_BIT3 : 0)) - #define arch_calc_vm_prot_bits(prot, key) ( \ ((key) & 0x1 ? VM_PKEY_BIT0 : 0) | \ ((key) & 0x2 ? VM_PKEY_BIT1 : 0) | \ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index f089349149..ebdafa576d 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -270,6 +270,8 @@ struct kvm_xen_exit { #define KVM_EXIT_X86_BUS_LOCK 33 #define KVM_EXIT_XEN 34 #define KVM_EXIT_RISCV_SBI 35 +#define KVM_EXIT_RISCV_CSR 36 +#define KVM_EXIT_NOTIFY 37 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -444,6 +446,9 @@ struct kvm_run { #define KVM_SYSTEM_EVENT_SHUTDOWN 1 #define KVM_SYSTEM_EVENT_RESET 2 #define KVM_SYSTEM_EVENT_CRASH 3 +#define KVM_SYSTEM_EVENT_WAKEUP 4 +#define KVM_SYSTEM_EVENT_SUSPEND 5 +#define KVM_SYSTEM_EVENT_SEV_TERM 6 __u32 type; __u32 ndata; union { @@ -491,6 +496,18 @@ struct kvm_run { unsigned long args[6]; unsigned long ret[2]; } riscv_sbi; + /* KVM_EXIT_RISCV_CSR */ + struct { + unsigned long csr_num; + unsigned long new_value; + unsigned long write_mask; + unsigned long ret_value; + } riscv_csr; + /* KVM_EXIT_NOTIFY */ + struct { +#define KVM_NOTIFY_CONTEXT_INVALID (1 << 0) + __u32 flags; + } notify; /* Fix the size of the union. */ char padding[256]; }; @@ -537,7 +554,7 @@ struct kvm_coalesced_mmio { struct kvm_coalesced_mmio_ring { __u32 first, last; - struct kvm_coalesced_mmio coalesced_mmio[0]; + struct kvm_coalesced_mmio coalesced_mmio[]; }; #define KVM_COALESCED_MMIO_MAX \ @@ -616,7 +633,7 @@ struct kvm_clear_dirty_log { /* for KVM_SET_SIGNAL_MASK */ struct kvm_signal_mask { __u32 len; - __u8 sigset[0]; + __u8 sigset[]; }; /* for KVM_TPR_ACCESS_REPORTING */ @@ -644,6 +661,7 @@ struct kvm_vapic_addr { #define KVM_MP_STATE_OPERATING 7 #define KVM_MP_STATE_LOAD 8 #define KVM_MP_STATE_AP_RESET_HOLD 9 +#define KVM_MP_STATE_SUSPENDED 10 struct kvm_mp_state { __u32 mp_state; @@ -1148,8 +1166,15 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_MEM_OP_EXTENSION 211 #define KVM_CAP_PMU_CAPABILITY 212 #define KVM_CAP_DISABLE_QUIRKS2 213 -/* #define KVM_CAP_VM_TSC_CONTROL 214 */ +#define KVM_CAP_VM_TSC_CONTROL 214 #define KVM_CAP_SYSTEM_EVENT_DATA 215 +#define KVM_CAP_ARM_SYSTEM_SUSPEND 216 +#define KVM_CAP_S390_PROTECTED_DUMP 217 +#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 +#define KVM_CAP_X86_NOTIFY_VMEXIT 219 +#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220 +#define KVM_CAP_S390_ZPCI_OP 221 +#define KVM_CAP_S390_CPU_TOPOLOGY 222 #ifdef KVM_CAP_IRQ_ROUTING @@ -1214,7 +1239,7 @@ struct kvm_irq_routing_entry { struct kvm_irq_routing { __u32 nr; __u32 flags; - struct kvm_irq_routing_entry entries[0]; + struct kvm_irq_routing_entry entries[]; }; #endif @@ -1238,6 +1263,7 @@ struct kvm_x86_mce { #define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2) #define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3) #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4) +#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5) struct kvm_xen_hvm_config { __u32 flags; @@ -1333,7 +1359,7 @@ struct kvm_dirty_tlb { struct kvm_reg_list { __u64 n; /* number of regs */ - __u64 reg[0]; + __u64 reg[]; }; struct kvm_one_reg { @@ -1476,7 +1502,8 @@ struct kvm_s390_ucas_mapping { #define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2) /* Available with KVM_CAP_PPC_GET_PVINFO */ #define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo) -/* Available with KVM_CAP_TSC_CONTROL */ +/* Available with KVM_CAP_TSC_CONTROL for a vCPU, or with +* KVM_CAP_VM_TSC_CONTROL to set defaults for a VM */ #define KVM_SET_TSC_KHZ _IO(KVMIO, 0xa2) #define KVM_GET_TSC_KHZ _IO(KVMIO, 0xa3) /* Available with KVM_CAP_PCI_2_3 */ @@ -1651,6 +1678,55 @@ struct kvm_s390_pv_unp { __u64 tweak; }; +enum pv_cmd_dmp_id { + KVM_PV_DUMP_INIT, + KVM_PV_DUMP_CONFIG_STOR_STATE, + KVM_PV_DUMP_COMPLETE, + KVM_PV_DUMP_CPU, +}; + +struct kvm_s390_pv_dmp { + __u64 subcmd; + __u64 buff_addr; + __u64 buff_len; + __u64 gaddr; /* For dump storage state */ + __u64 reserved[4]; +}; + +enum pv_cmd_info_id { + KVM_PV_INFO_VM, + KVM_PV_INFO_DUMP, +}; + +struct kvm_s390_pv_info_dump { + __u64 dump_cpu_buffer_len; + __u64 dump_config_mem_buffer_per_1m; + __u64 dump_config_finalize_len; +}; + +struct kvm_s390_pv_info_vm { + __u64 inst_calls_list[4]; + __u64 max_cpus; + __u64 max_guests; + __u64 max_guest_addr; + __u64 feature_indication; +}; + +struct kvm_s390_pv_info_header { + __u32 id; + __u32 len_max; + __u32 len_written; + __u32 reserved; +}; + +struct kvm_s390_pv_info { + struct kvm_s390_pv_info_header header; + union { + struct kvm_s390_pv_info_dump dump; + struct kvm_s390_pv_info_vm vm; + }; +}; + enum pv_cmd_id { KVM_PV_ENABLE, KVM_PV_DISABLE, @@ -1659,6 +1735,8 @@ enum pv_cmd_id { KVM_PV_VERIFY, KVM_PV_PREP_RESET, KVM_PV_UNSHARE_ALL, + KVM_PV_INFO, + KVM_PV_DUMP, }; struct kvm_pv_cmd { @@ -1692,6 +1770,32 @@ struct kvm_xen_hvm_attr { struct { __u64 gfn; } shared_info; + struct { + __u32 send_port; + __u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */ + __u32 flags; +#define KVM_XEN_EVTCHN_DEASSIGN (1 << 0) +#define KVM_XEN_EVTCHN_UPDATE (1 << 1) +#define KVM_XEN_EVTCHN_RESET (1 << 2) + /* + * Events sent by the guest are either looped back to + * the guest itself (potentially on a different port#) + * or signalled via an eventfd. + */ + union { + struct { + __u32 port; + __u32 vcpu; + __u32 priority; + } port; + struct { + __u32 port; /* Zero for eventfd */ + __s32 fd; + } eventfd; + __u32 padding[4]; + } deliver; + } evtchn; + __u32 xen_version; __u64 pad[8]; } u; }; @@ -1700,11 +1804,17 @@ struct kvm_xen_hvm_attr { #define KVM_XEN_ATTR_TYPE_LONG_MODE 0x0 #define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x1 #define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR 0x2 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ +#define KVM_XEN_ATTR_TYPE_EVTCHN 0x3 +#define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4 /* Per-vCPU Xen attributes */ #define KVM_XEN_VCPU_GET_ATTR _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr) #define KVM_XEN_VCPU_SET_ATTR _IOW(KVMIO, 0xcb, struct kvm_xen_vcpu_attr) +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ +#define KVM_XEN_HVM_EVTCHN_SEND _IOW(KVMIO, 0xd0, struct kvm_irq_routing_xen_evtchn) + #define KVM_GET_SREGS2 _IOR(KVMIO, 0xcc, struct kvm_sregs2) #define KVM_SET_SREGS2 _IOW(KVMIO, 0xcd, struct kvm_sregs2) @@ -1722,6 +1832,13 @@ struct kvm_xen_vcpu_attr { __u64 time_blocked; __u64 time_offline; } runstate; + __u32 vcpu_id; + struct { + __u32 port; + __u32 priority; + __u64 expires_ns; + } timer; + __u8 vector; } u; }; @@ -1732,6 +1849,10 @@ struct kvm_xen_vcpu_attr { #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT 0x3 #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA 0x4 #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ +#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID 0x6 +#define KVM_XEN_VCPU_ATTR_TYPE_TIMER 0x7 +#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR 0x8 /* Secure Encrypted Virtualization command */ enum sev_cmd_id { @@ -2032,7 +2153,7 @@ struct kvm_stats_header { #define KVM_STATS_UNIT_SECONDS (0x2 << KVM_STATS_UNIT_SHIFT) #define KVM_STATS_UNIT_CYCLES (0x3 << KVM_STATS_UNIT_SHIFT) #define KVM_STATS_UNIT_BOOLEAN (0x4 << KVM_STATS_UNIT_SHIFT) -#define KVM_STATS_UNIT_MAX KVM_STATS_UNIT_CYCLES +#define KVM_STATS_UNIT_MAX KVM_STATS_UNIT_BOOLEAN #define KVM_STATS_BASE_SHIFT 8 #define KVM_STATS_BASE_MASK (0xF << KVM_STATS_BASE_SHIFT) @@ -2067,4 +2188,41 @@ struct kvm_stats_desc { /* Available with KVM_CAP_XSAVE2 */ #define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) +/* Available with KVM_CAP_S390_PROTECTED_DUMP */ +#define KVM_S390_PV_CPU_COMMAND _IOWR(KVMIO, 0xd0, struct kvm_pv_cmd) + +/* Available with KVM_CAP_X86_NOTIFY_VMEXIT */ +#define KVM_X86_NOTIFY_VMEXIT_ENABLED (1ULL << 0) +#define KVM_X86_NOTIFY_VMEXIT_USER (1ULL << 1) + +/* Available with KVM_CAP_S390_ZPCI_OP */ +#define KVM_S390_ZPCI_OP _IOW(KVMIO, 0xd1, struct kvm_s390_zpci_op) + +struct kvm_s390_zpci_op { + /* in */ + __u32 fh; /* target device */ + __u8 op; /* operation to perform */ + __u8 pad[3]; + union { + /* for KVM_S390_ZPCIOP_REG_AEN */ + struct { + __u64 ibv; /* Guest addr of interrupt bit vector */ + __u64 sb; /* Guest addr of summary bit */ + __u32 flags; + __u32 noi; /* Number of interrupts */ + __u8 isc; /* Guest interrupt subclass */ + __u8 sbo; /* Offset of guest summary bit vector */ + __u16 pad; + } reg_aen; + __u64 reserved[8]; + } u; +}; + +/* types for kvm_s390_zpci_op->op */ +#define KVM_S390_ZPCIOP_REG_AEN 0 +#define KVM_S390_ZPCIOP_DEREG_AEN 1 + +/* flags for kvm_s390_zpci_op->u.reg_aen.flags */ +#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0) + #endif /* __LINUX_KVM_H */ diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h index 769b8379e4..a3a377cd44 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -33,7 +33,8 @@ UFFD_FEATURE_THREAD_ID | \ UFFD_FEATURE_MINOR_HUGETLBFS | \ UFFD_FEATURE_MINOR_SHMEM | \ - UFFD_FEATURE_EXACT_ADDRESS) + UFFD_FEATURE_EXACT_ADDRESS | \ + UFFD_FEATURE_WP_HUGETLBFS_SHMEM) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -47,7 +48,8 @@ #define UFFD_API_RANGE_IOCTLS_BASIC \ ((__u64)1 << _UFFDIO_WAKE | \ (__u64)1 << _UFFDIO_COPY | \ - (__u64)1 << _UFFDIO_CONTINUE) + (__u64)1 << _UFFDIO_CONTINUE | \ + (__u64)1 << _UFFDIO_WRITEPROTECT) /* * Valid ioctl command number range with this API is from 0x00 to @@ -194,6 +196,9 @@ struct uffdio_api { * UFFD_FEATURE_EXACT_ADDRESS indicates that the exact address of page * faults would be provided and the offset within the page would not be * masked. + * + * UFFD_FEATURE_WP_HUGETLBFS_SHMEM indicates that userfaultfd + * write-protection mode is supported on both shmem and hugetlbfs. */ #define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) #define UFFD_FEATURE_EVENT_FORK (1<<1) @@ -207,6 +212,7 @@ struct uffdio_api { #define UFFD_FEATURE_MINOR_HUGETLBFS (1<<9) #define UFFD_FEATURE_MINOR_SHMEM (1<<10) #define UFFD_FEATURE_EXACT_ADDRESS (1<<11) +#define UFFD_FEATURE_WP_HUGETLBFS_SHMEM (1<<12) __u64 features; __u64 ioctls; diff --git a/linux-headers/linux/vduse.h b/linux-headers/linux/vduse.h index d47b004ce6..6d2ca064b5 100644 --- a/linux-headers/linux/vduse.h +++ b/linux-headers/linux/vduse.h @@ -210,6 +210,53 @@ struct vduse_vq_eventfd { */ #define VDUSE_VQ_INJECT_IRQ _IOW(VDUSE_BASE, 0x17, __u32) +/** + * struct vduse_iova_umem - userspace memory configuration for one IOVA region + * @uaddr: start address of userspace memory, it must be aligned to page size + * @iova: start of the IOVA region + * @size: size of the IOVA region + * @reserved: for future use, needs to be initialized to zero + * + * Structure used by VDUSE_IOTLB_REG_UMEM and VDUSE_IOTLB_DEREG_UMEM + * ioctls to register/de-register userspace memory for IOVA regions + */ +struct vduse_iova_umem { + __u64 uaddr; + __u64 iova; + __u64 size; + __u64 reserved[3]; +}; + +/* Register userspace memory for IOVA regions */ +#define VDUSE_IOTLB_REG_UMEM _IOW(VDUSE_BASE, 0x18, struct vduse_iova_umem) + +/* De-register the userspace memory. Caller should set iova and size field. */ +#define VDUSE_IOTLB_DEREG_UMEM _IOW(VDUSE_BASE, 0x19, struct vduse_iova_umem) + +/** + * struct vduse_iova_info - information of one IOVA region + * @start: start of the IOVA region + * @last: last of the IOVA region + * @capability: capability of the IOVA regsion + * @reserved: for future use, needs to be initialized to zero + * + * Structure used by VDUSE_IOTLB_GET_INFO ioctl to get information of + * one IOVA region. + */ +struct vduse_iova_info { + __u64 start; + __u64 last; +#define VDUSE_IOVA_CAP_UMEM (1 << 0) + __u64 capability; + __u64 reserved[3]; +}; + +/* + * Find the first IOVA region that overlaps with the range [start, last] + * and return some information on it. Caller should set start and last fields. + */ +#define VDUSE_IOTLB_GET_INFO _IOWR(VDUSE_BASE, 0x1a, struct vduse_iova_info) + /* The control messages definition for read(2)/write(2) on /dev/vduse/$NAME */ /** diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index e9f7795c39..ede44b5572 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -643,7 +643,7 @@ enum { }; /** - * VFIO_DEVICE_GET_PCI_HOT_RESET_INFO - _IORW(VFIO_TYPE, VFIO_BASE + 12, + * VFIO_DEVICE_GET_PCI_HOT_RESET_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 12, * struct vfio_pci_hot_reset_info) * * Return: 0 on success, -errno on failure: @@ -770,7 +770,7 @@ struct vfio_device_ioeventfd { #define VFIO_DEVICE_IOEVENTFD _IO(VFIO_TYPE, VFIO_BASE + 16) /** - * VFIO_DEVICE_FEATURE - _IORW(VFIO_TYPE, VFIO_BASE + 17, + * VFIO_DEVICE_FEATURE - _IOWR(VFIO_TYPE, VFIO_BASE + 17, * struct vfio_device_feature) * * Get, set, or probe feature data of the device. The feature is selected diff --git a/linux-headers/linux/vfio_zdev.h b/linux-headers/linux/vfio_zdev.h index b4309397b6..77f2aff1f2 100644 --- a/linux-headers/linux/vfio_zdev.h +++ b/linux-headers/linux/vfio_zdev.h @@ -29,6 +29,9 @@ struct vfio_device_info_cap_zpci_base { __u16 fmb_length; /* Measurement Block Length (in bytes) */ __u8 pft; /* PCI Function Type */ __u8 gid; /* PCI function group ID */ + /* End of version 1 */ + __u32 fh; /* PCI function handle */ + /* End of version 2 */ }; /** @@ -47,6 +50,10 @@ struct vfio_device_info_cap_zpci_group { __u16 noi; /* Maximum number of MSIs */ __u16 maxstbl; /* Maximum Store Block Length */ __u8 version; /* Supported PCI Version */ + /* End of version 1 */ + __u8 reserved; + __u16 imaxstbl; /* Maximum Interpreted Store Block Length */ + /* End of version 2 */ }; /** diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index 5d99e7c242..f9f115a7c7 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -89,11 +89,6 @@ /* Set or get vhost backend capability */ -/* Use message type V2 */ -#define VHOST_BACKEND_F_IOTLB_MSG_V2 0x1 -/* IOTLB can accept batching hints */ -#define VHOST_BACKEND_F_IOTLB_BATCH 0x2 - #define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64) #define VHOST_GET_BACKEND_FEATURES _IOR(VHOST_VIRTIO, 0x26, __u64) @@ -150,11 +145,39 @@ /* Get the valid iova range */ #define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ struct vhost_vdpa_iova_range) - /* Get the config size */ #define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) /* Get the count of all virtqueues */ #define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) +/* Get the number of virtqueue groups. */ +#define VHOST_VDPA_GET_GROUP_NUM _IOR(VHOST_VIRTIO, 0x81, __u32) + +/* Get the number of address spaces. */ +#define VHOST_VDPA_GET_AS_NUM _IOR(VHOST_VIRTIO, 0x7A, unsigned int) + +/* Get the group for a virtqueue: read index, write group in num, + * The virtqueue index is stored in the index field of + * vhost_vring_state. The group for this specific virtqueue is + * returned via num field of vhost_vring_state. + */ +#define VHOST_VDPA_GET_VRING_GROUP _IOWR(VHOST_VIRTIO, 0x7B, \ + struct vhost_vring_state) +/* Set the ASID for a virtqueue group. The group index is stored in + * the index field of vhost_vring_state, the ASID associated with this + * group is stored at num field of vhost_vring_state. + */ +#define VHOST_VDPA_SET_GROUP_ASID _IOW(VHOST_VIRTIO, 0x7C, \ + struct vhost_vring_state) + +/* Suspend a device so it does not process virtqueue requests anymore + * + * After the return of ioctl the device must preserve all the necessary state + * (the virtqueue vring base plus the possible device specific states) that is + * required for restoring in the future. The device must not change its + * configuration after that point. + */ +#define VHOST_VDPA_SUSPEND _IO(VHOST_VIRTIO, 0x7D) + #endif diff --git a/linux-user/aarch64/target_mman.h b/linux-user/aarch64/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/aarch64/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/alpha/target_mman.h b/linux-user/alpha/target_mman.h new file mode 100644 index 0000000000..cd6e3d70a6 --- /dev/null +++ b/linux-user/alpha/target_mman.h @@ -0,0 +1,8 @@ +#ifndef ALPHA_TARGET_MMAN_H +#define ALPHA_TARGET_MMAN_H + +#define TARGET_MADV_DONTNEED 6 + +#include "../generic/target_mman.h" + +#endif diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h index 709d19bc9e..89ba274cfc 100644 --- a/linux-user/arm/target_cpu.h +++ b/linux-user/arm/target_cpu.h @@ -34,9 +34,9 @@ static inline unsigned long arm_max_reserved_va(CPUState *cs) } else { /* * We need to be able to map the commpage. - * See validate_guest_space in linux-user/elfload.c. + * See init_guest_commpage in linux-user/elfload.c. */ - return 0xffff0000ul; + return 0xfffffffful; } } #define MAX_RESERVED_VA arm_max_reserved_va diff --git a/linux-user/arm/target_mman.h b/linux-user/arm/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/arm/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/cpu_loop-common.h b/linux-user/cpu_loop-common.h index dc0042e4de..36ff5b14f2 100644 --- a/linux-user/cpu_loop-common.h +++ b/linux-user/cpu_loop-common.h @@ -27,9 +27,11 @@ do { \ CPUState *cs = env_cpu(env); \ fprintf(stderr, fmt , ## __VA_ARGS__); \ + fprintf(stderr, "Failing executable: %s\n", exec_path); \ cpu_dump_state(cs, stderr, 0); \ if (qemu_log_separate()) { \ qemu_log(fmt, ## __VA_ARGS__); \ + qemu_log("Failing executable: %s\n", exec_path); \ log_cpu_state(cs, 0); \ } \ } while (0) diff --git a/linux-user/cris/target_mman.h b/linux-user/cris/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/cris/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ce902dbd56..20894b633f 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -195,6 +195,27 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff); } +#if ULONG_MAX > UINT32_MAX +#define INIT_GUEST_COMMPAGE +static bool init_guest_commpage(void) +{ + /* + * The vsyscall page is at a high negative address aka kernel space, + * which means that we cannot actually allocate it with target_mmap. + * We still should be able to use page_set_flags, unless the user + * has specified -R reserved_va, which would trigger an assert(). + */ + if (reserved_va != 0 && + TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE >= reserved_va) { + error_report("Cannot allocate vsyscall page"); + exit(EXIT_FAILURE); + } + page_set_flags(TARGET_VSYSCALL_PAGE, + TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE, + PAGE_EXEC | PAGE_VALID); + return true; +} +#endif #else #define ELF_START_MMAP 0x80000000 @@ -211,6 +232,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en #define ELF_ARCH EM_386 #define ELF_PLATFORM get_elf_platform() +#define EXSTACK_DEFAULT true static const char *get_elf_platform(void) { @@ -287,6 +309,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en #define ELF_ARCH EM_ARM #define ELF_CLASS ELFCLASS32 +#define EXSTACK_DEFAULT true static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) @@ -398,7 +421,8 @@ enum { static bool init_guest_commpage(void) { - void *want = g2h_untagged(HI_COMMPAGE & -qemu_host_page_size); + abi_ptr commpage = HI_COMMPAGE & -qemu_host_page_size; + void *want = g2h_untagged(commpage); void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); @@ -417,6 +441,9 @@ static bool init_guest_commpage(void) perror("Protecting guest commpage"); exit(EXIT_FAILURE); } + + page_set_flags(commpage, commpage + qemu_host_page_size, + PAGE_READ | PAGE_EXEC | PAGE_VALID); return true; } @@ -751,6 +778,7 @@ static inline void init_thread(struct target_pt_regs *regs, #else #define ELF_CLASS ELFCLASS32 +#define EXSTACK_DEFAULT true #endif @@ -948,6 +976,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en #define ELF_CLASS ELFCLASS64 #define ELF_ARCH EM_LOONGARCH +#define EXSTACK_DEFAULT true #define elf_check_arch(x) ((x) == EM_LOONGARCH) @@ -1043,6 +1072,7 @@ static uint32_t get_elf_hwcap(void) #define ELF_CLASS ELFCLASS32 #endif #define ELF_ARCH EM_MIPS +#define EXSTACK_DEFAULT true #ifdef TARGET_ABI_MIPSN32 #define elf_check_abi(x) ((x) & EF_MIPS_ABI2) @@ -1050,6 +1080,37 @@ static uint32_t get_elf_hwcap(void) #define elf_check_abi(x) (!((x) & EF_MIPS_ABI2)) #endif +#define ELF_BASE_PLATFORM get_elf_base_platform() + +#define MATCH_PLATFORM_INSN(_flags, _base_platform) \ + do { if ((cpu->env.insn_flags & (_flags)) == _flags) \ + { return _base_platform; } } while (0) + +static const char *get_elf_base_platform(void) +{ + MIPSCPU *cpu = MIPS_CPU(thread_cpu); + + /* 64 bit ISAs goes first */ + MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6"); + MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5"); + MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2"); + MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64"); + MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5"); + MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4"); + MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3"); + + /* 32 bit ISAs */ + MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6"); + MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5"); + MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2"); + MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32"); + MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2"); + + /* Fallback */ + return "mips"; +} +#undef MATCH_PLATFORM_INSN + static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { @@ -1642,6 +1703,34 @@ static inline void init_thread(struct target_pt_regs *regs, regs->gr[31] = infop->entry; } +#define LO_COMMPAGE 0 + +static bool init_guest_commpage(void) +{ + void *want = g2h_untagged(LO_COMMPAGE); + void *addr = mmap(want, qemu_host_page_size, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + + if (addr == MAP_FAILED) { + perror("Allocating guest commpage"); + exit(EXIT_FAILURE); + } + if (addr != want) { + return false; + } + + /* + * On Linux, page zero is normally marked execute only + gateway. + * Normal read or write is supposed to fail (thus PROT_NONE above), + * but specific offsets have kernel code mapped to raise permissions + * and implement syscalls. Here, simply mark the page executable. + * Special case the entry points during translation (see do_page_zero). + */ + page_set_flags(LO_COMMPAGE, LO_COMMPAGE + TARGET_PAGE_SIZE, + PAGE_EXEC | PAGE_VALID); + return true; +} + #endif /* TARGET_HPPA */ #ifdef TARGET_XTENSA @@ -1718,6 +1807,10 @@ static inline void init_thread(struct target_pt_regs *regs, #endif /* TARGET_HEXAGON */ +#ifndef ELF_BASE_PLATFORM +#define ELF_BASE_PLATFORM (NULL) +#endif + #ifndef ELF_PLATFORM #define ELF_PLATFORM (NULL) #endif @@ -1753,6 +1846,10 @@ static inline void init_thread(struct target_pt_regs *regs, #define bswaptls(ptr) bswap32s(ptr) #endif +#ifndef EXSTACK_DEFAULT +#define EXSTACK_DEFAULT false +#endif + #include "elf.h" /* We must delay the following stanzas until after "elf.h". */ @@ -2028,17 +2125,28 @@ static abi_ulong setup_arg_pages(struct linux_binprm *bprm, struct image_info *info) { abi_ulong size, error, guard; + int prot; size = guest_stack_size; if (size < STACK_LOWER_LIMIT) { size = STACK_LOWER_LIMIT; } - guard = TARGET_PAGE_SIZE; - if (guard < qemu_real_host_page_size()) { - guard = qemu_real_host_page_size(); + + if (STACK_GROWS_DOWN) { + guard = TARGET_PAGE_SIZE; + if (guard < qemu_real_host_page_size()) { + guard = qemu_real_host_page_size(); + } + } else { + /* no guard page for hppa target where stack grows upwards. */ + guard = 0; } - error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE, + prot = PROT_READ | PROT_WRITE; + if (info->exec_stack) { + prot |= PROT_EXEC; + } + error = target_mmap(0, size + guard, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (error == -1) { perror("mmap stack"); @@ -2051,7 +2159,6 @@ static abi_ulong setup_arg_pages(struct linux_binprm *bprm, info->stack_limit = error + guard; return info->stack_limit + size - sizeof(void *); } else { - target_mprotect(error + size, guard, PROT_NONE); info->stack_limit = error + size; return error; } @@ -2148,8 +2255,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, int i; abi_ulong u_rand_bytes; uint8_t k_rand_bytes[16]; - abi_ulong u_platform; - const char *k_platform; + abi_ulong u_platform, u_base_platform; + const char *k_platform, *k_base_platform; const int n = sizeof(elf_addr_t); sp = p; @@ -2171,6 +2278,22 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, } } + u_base_platform = 0; + k_base_platform = ELF_BASE_PLATFORM; + if (k_base_platform) { + size_t len = strlen(k_base_platform) + 1; + if (STACK_GROWS_DOWN) { + sp -= (len + n - 1) & ~(n - 1); + u_base_platform = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(sp, k_base_platform, len); + } else { + memcpy_to_target(sp, k_base_platform, len); + u_base_platform = sp; + sp += len + 1; + } + } + u_platform = 0; k_platform = ELF_PLATFORM; if (k_platform) { @@ -2212,6 +2335,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, } size = (DLINFO_ITEMS + 1) * 2; + if (k_base_platform) + size += 2; if (k_platform) size += 2; #ifdef DLINFO_ARCH_ITEMS @@ -2289,6 +2414,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2); #endif + if (u_base_platform) { + NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform); + } if (u_platform) { NEW_AUX_ENT(AT_PLATFORM, u_platform); } @@ -2322,14 +2450,16 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, } #if defined(HI_COMMPAGE) -#define LO_COMMPAGE 0 +#define LO_COMMPAGE -1 #elif defined(LO_COMMPAGE) #define HI_COMMPAGE 0 #else #define HI_COMMPAGE 0 -#define LO_COMMPAGE 0 +#define LO_COMMPAGE -1 +#ifndef INIT_GUEST_COMMPAGE #define init_guest_commpage() true #endif +#endif static void pgb_fail_in_use(const char *image_name) { @@ -2551,7 +2681,7 @@ static void pgb_static(const char *image_name, abi_ulong orig_loaddr, } else { offset = -(HI_COMMPAGE & -align); } - } else if (LO_COMMPAGE != 0) { + } else if (LO_COMMPAGE != -1) { loaddr = MIN(loaddr, LO_COMMPAGE & -align); } @@ -2866,6 +2996,7 @@ static void load_elf_image(const char *image_name, int image_fd, */ loaddr = -1, hiaddr = 0; info->alignment = 0; + info->exec_stack = EXSTACK_DEFAULT; for (i = 0; i < ehdr->e_phnum; ++i) { struct elf_phdr *eppnt = phdr + i; if (eppnt->p_type == PT_LOAD) { @@ -2908,6 +3039,8 @@ static void load_elf_image(const char *image_name, int image_fd, if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) { goto exit_errmsg; } + } else if (eppnt->p_type == PT_GNU_STACK) { + info->exec_stack = eppnt->p_flags & PF_X; } } diff --git a/linux-user/flatload.c b/linux-user/flatload.c index e4c2f89a22..e99570ca18 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -808,7 +808,7 @@ int load_flt_binary(struct linux_binprm *bprm, struct image_info *info) /* Stash our initial stack pointer into the mm structure */ info->start_code = libinfo[0].start_code; - info->end_code = libinfo[0].start_code = libinfo[0].text_len; + info->end_code = libinfo[0].start_code + libinfo[0].text_len; info->start_data = libinfo[0].start_data; info->end_data = libinfo[0].end_data; info->start_brk = libinfo[0].start_brk; diff --git a/linux-user/generic/target_mman.h b/linux-user/generic/target_mman.h new file mode 100644 index 0000000000..1436a3c543 --- /dev/null +++ b/linux-user/generic/target_mman.h @@ -0,0 +1,92 @@ +#ifndef LINUX_USER_TARGET_MMAN_H +#define LINUX_USER_TARGET_MMAN_H + +#ifndef TARGET_MADV_NORMAL +#define TARGET_MADV_NORMAL 0 +#endif + +#ifndef TARGET_MADV_RANDOM +#define TARGET_MADV_RANDOM 1 +#endif + +#ifndef TARGET_MADV_SEQUENTIAL +#define TARGET_MADV_SEQUENTIAL 2 +#endif + +#ifndef TARGET_MADV_WILLNEED +#define TARGET_MADV_WILLNEED 3 +#endif + +#ifndef TARGET_MADV_DONTNEED +#define TARGET_MADV_DONTNEED 4 +#endif + +#ifndef TARGET_MADV_FREE +#define TARGET_MADV_FREE 8 +#endif + +#ifndef TARGET_MADV_REMOVE +#define TARGET_MADV_REMOVE 9 +#endif + +#ifndef TARGET_MADV_DONTFORK +#define TARGET_MADV_DONTFORK 10 +#endif + +#ifndef TARGET_MADV_DOFORK +#define TARGET_MADV_DOFORK 11 +#endif + +#ifndef TARGET_MADV_MERGEABLE +#define TARGET_MADV_MERGEABLE 12 +#endif + +#ifndef TARGET_MADV_UNMERGEABLE +#define TARGET_MADV_UNMERGEABLE 13 +#endif + +#ifndef TARGET_MADV_HUGEPAGE +#define TARGET_MADV_HUGEPAGE 14 +#endif + +#ifndef TARGET_MADV_NOHUGEPAGE +#define TARGET_MADV_NOHUGEPAGE 15 +#endif + +#ifndef TARGET_MADV_DONTDUMP +#define TARGET_MADV_DONTDUMP 16 +#endif + +#ifndef TARGET_MADV_DODUMP +#define TARGET_MADV_DODUMP 17 +#endif + +#ifndef TARGET_MADV_WIPEONFORK +#define TARGET_MADV_WIPEONFORK 18 +#endif + +#ifndef TARGET_MADV_KEEPONFORK +#define TARGET_MADV_KEEPONFORK 19 +#endif + +#ifndef TARGET_MADV_COLD +#define TARGET_MADV_COLD 20 +#endif + +#ifndef TARGET_MADV_PAGEOUT +#define TARGET_MADV_PAGEOUT 21 +#endif + +#ifndef TARGET_MADV_POPULATE_READ +#define TARGET_MADV_POPULATE_READ 22 +#endif + +#ifndef TARGET_MADV_POPULATE_WRITE +#define TARGET_MADV_POPULATE_WRITE 23 +#endif + +#ifndef TARGET_MADV_DONTNEED_LOCKED +#define TARGET_MADV_DONTNEED_LOCKED 24 +#endif + +#endif diff --git a/linux-user/hexagon/target_mman.h b/linux-user/hexagon/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/hexagon/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index 64263c3dc4..1ef3b46191 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -147,12 +147,15 @@ void cpu_loop(CPUHPPAState *env) force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f); break; case EXCP_ILL: + EXCP_DUMP(env, "qemu: got CPU exception 0x%x - aborting\n", trapnr); force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->iaoq_f); break; case EXCP_PRIV_OPR: + EXCP_DUMP(env, "qemu: got CPU exception 0x%x - aborting\n", trapnr); force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->iaoq_f); break; case EXCP_PRIV_REG: + EXCP_DUMP(env, "qemu: got CPU exception 0x%x - aborting\n", trapnr); force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVREG, env->iaoq_f); break; case EXCP_OVERFLOW: @@ -171,7 +174,8 @@ void cpu_loop(CPUHPPAState *env) /* just indicate that signals should be handled asap */ break; default: - g_assert_not_reached(); + EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); + abort(); } process_pending_signals(env); } diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c index 962f551c04..f253a15864 100644 --- a/linux-user/hppa/signal.c +++ b/linux-user/hppa/signal.c @@ -41,7 +41,7 @@ struct target_ucontext { }; struct target_rt_sigframe { - abi_uint tramp[9]; + abi_uint tramp[2]; /* syscall restart return address */ target_siginfo_t info; struct target_ucontext uc; /* hidden location of upper halves of pa2.0 64-bit gregs */ @@ -49,23 +49,13 @@ struct target_rt_sigframe { static void setup_sigcontext(struct target_sigcontext *sc, CPUArchState *env) { - int flags = 0; int i; - /* ??? if on_sig_stack, flags |= 1 (PARISC_SC_FLAG_ONSTACK). */ - - if (env->iaoq_f < TARGET_PAGE_SIZE) { - /* In the gateway page, executing a syscall. */ - flags |= 2; /* PARISC_SC_FLAG_IN_SYSCALL */ - __put_user(env->gr[31], &sc->sc_iaoq[0]); - __put_user(env->gr[31] + 4, &sc->sc_iaoq[1]); - } else { - __put_user(env->iaoq_f, &sc->sc_iaoq[0]); - __put_user(env->iaoq_b, &sc->sc_iaoq[1]); - } + __put_user(env->iaoq_f, &sc->sc_iaoq[0]); + __put_user(env->iaoq_b, &sc->sc_iaoq[1]); __put_user(0, &sc->sc_iasq[0]); __put_user(0, &sc->sc_iasq[1]); - __put_user(flags, &sc->sc_flags); + __put_user(0, &sc->sc_flags); __put_user(cpu_hppa_get_psw(env), &sc->sc_gr[0]); for (i = 1; i < 32; ++i) { @@ -101,9 +91,15 @@ static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc) __get_user(env->cr[CR_SAR], &sc->sc_sar); } -/* No, this doesn't look right, but it's copied straight from the kernel. */ +#if TARGET_ABI_BITS == 32 +#define SIGFRAME 64 +#define FUNCTIONCALLFRAME 48 +#else +#define SIGFRAME 128 +#define FUNCTIONCALLFRAME 96 +#endif #define PARISC_RT_SIGFRAME_SIZE32 \ - ((sizeof(struct target_rt_sigframe) + 48 + 64) & -64) + ((sizeof(struct target_rt_sigframe) + FUNCTIONCALLFRAME + SIGFRAME) & -SIGFRAME) void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, @@ -118,7 +114,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) { sp = (ts->sigaltstack_used.ss_sp + 0x7f) & ~0x3f; } - frame_addr = QEMU_ALIGN_UP(sp, 64); + frame_addr = QEMU_ALIGN_UP(sp, SIGFRAME); sp = frame_addr + PARISC_RT_SIGFRAME_SIZE32; trace_user_setup_rt_frame(env, frame_addr); @@ -139,14 +135,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, setup_sigcontext(&frame->uc.tuc_mcontext, env); - __put_user(0x34190000, frame->tramp + 0); /* ldi 0,%r25 */ - __put_user(0x3414015a, frame->tramp + 1); /* ldi __NR_rt_sigreturn,%r20 */ - __put_user(0xe4008200, frame->tramp + 2); /* be,l 0x100(%sr2,%r0) */ - __put_user(0x08000240, frame->tramp + 3); /* nop */ - unlock_user_struct(frame, frame_addr, 1); - env->gr[2] = h2g(frame->tramp); + env->gr[2] = default_rt_sigreturn; env->gr[30] = sp; env->gr[26] = sig; env->gr[25] = h2g(&frame->info); @@ -197,3 +188,23 @@ long do_rt_sigreturn(CPUArchState *env) force_sig(TARGET_SIGSEGV); return -QEMU_ESIGRETURN; } + +void setup_sigtramp(abi_ulong sigtramp_page) +{ + uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6*4, 0); + abi_ulong SIGFRAME_CONTEXT_REGS32; + assert(tramp != NULL); + + SIGFRAME_CONTEXT_REGS32 = offsetof(struct target_rt_sigframe, uc.tuc_mcontext); + SIGFRAME_CONTEXT_REGS32 -= PARISC_RT_SIGFRAME_SIZE32; + + __put_user(SIGFRAME_CONTEXT_REGS32, tramp + 0); + __put_user(0x08000240, tramp + 1); /* nop - b/c dwarf2 unwind routines */ + __put_user(0x34190000, tramp + 2); /* ldi 0, %r25 (in_syscall=0) */ + __put_user(0x3414015a, tramp + 3); /* ldi __NR_rt_sigreturn, %r20 */ + __put_user(0xe4008200, tramp + 4); /* ble 0x100(%sr2, %r0) */ + __put_user(0x08000240, tramp + 5); /* nop */ + + default_rt_sigreturn = (sigtramp_page + 8) | 3; + unlock_user(tramp, sigtramp_page, 6*4); +} diff --git a/linux-user/hppa/target_mman.h b/linux-user/hppa/target_mman.h new file mode 100644 index 0000000000..66dd9f7941 --- /dev/null +++ b/linux-user/hppa/target_mman.h @@ -0,0 +1,15 @@ +#ifndef HPPA_TARGET_MMAN_H +#define HPPA_TARGET_MMAN_H + +#define TARGET_MADV_MERGEABLE 65 +#define TARGET_MADV_UNMERGEABLE 66 +#define TARGET_MADV_HUGEPAGE 67 +#define TARGET_MADV_NOHUGEPAGE 68 +#define TARGET_MADV_DONTDUMP 69 +#define TARGET_MADV_DODUMP 70 +#define TARGET_MADV_WIPEONFORK 71 +#define TARGET_MADV_KEEPONFORK 72 + +#include "../generic/target_mman.h" + +#endif diff --git a/linux-user/hppa/target_signal.h b/linux-user/hppa/target_signal.h index af6c2fce58..190bb3d653 100644 --- a/linux-user/hppa/target_signal.h +++ b/linux-user/hppa/target_signal.h @@ -70,18 +70,6 @@ typedef struct target_sigaltstack { /* mask for all SS_xxx flags */ #define TARGET_SS_FLAG_BITS TARGET_SS_AUTODISARM -/* - * We cannot use a bare sigtramp page for hppa-linux. - * - * Unlike other guests where we use the instructions at PC to validate - * an offset from SP, the hppa libgcc signal frame fallback unwinding uses - * the PC address itself to find the frame. This is due to the fact that - * the hppa grows the stack upward, and the frame is of unknown size. - * - * TODO: We should be able to use a VDSO to address this, by providing - * proper unwind info for the sigtramp code, at which point the fallback - * unwinder will not be used. - */ -#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0 +#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1 #endif /* HPPA_TARGET_SIGNAL_H */ diff --git a/linux-user/hppa/target_syscall.h b/linux-user/hppa/target_syscall.h index 4b382c1fcf..9a8f8ca628 100644 --- a/linux-user/hppa/target_syscall.h +++ b/linux-user/hppa/target_syscall.h @@ -26,4 +26,6 @@ struct target_pt_regs { #define TARGET_MCL_FUTURE 2 #define TARGET_MCL_ONFAULT 4 +#define TARGET_DEFAULT_STACK_SIZE 80 * 1024 * 1024UL + #endif /* HPPA_TARGET_SYSCALL_H */ diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 2e39fc2f9f..a3ed4b4f6f 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -137,7 +137,7 @@ static void emulate_vsyscall(CPUX86State *env) } /* - * Validate the the pointer arguments. + * Validate the pointer arguments. */ switch (syscall) { case TARGET_NR_gettimeofday: diff --git a/linux-user/i386/target_elf.h b/linux-user/i386/target_elf.h index 1c6142e7da..238a9aba73 100644 --- a/linux-user/i386/target_elf.h +++ b/linux-user/i386/target_elf.h @@ -9,6 +9,6 @@ #define I386_TARGET_ELF_H static inline const char *cpu_get_model(uint32_t eflags) { - return "qemu32"; + return "max"; } #endif diff --git a/linux-user/i386/target_mman.h b/linux-user/i386/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/i386/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/include/host/s390/host-signal.h b/linux-user/include/host/s390/host-signal.h index 25fefa00bd..e6d3ec26dc 100644 --- a/linux-user/include/host/s390/host-signal.h +++ b/linux-user/include/host/s390/host-signal.h @@ -87,6 +87,31 @@ static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc) return true; } break; + case 0xe6: + switch (pinsn[2] & 0xff) { + case 0x09: /* VSTEBRH */ + case 0x0a: /* VSTEBRG */ + case 0x0b: /* VSTEBRF */ + case 0x0e: /* VSTBR */ + case 0x0f: /* VSTER */ + case 0x3f: /* VSTRLR */ + return true; + } + break; + case 0xe7: + switch (pinsn[2] & 0xff) { + case 0x08: /* VSTEB */ + case 0x09: /* VSTEH */ + case 0x0a: /* VSTEG */ + case 0x0b: /* VSTEF */ + case 0x0e: /* VST */ + case 0x1a: /* VSCEG */ + case 0x1b: /* VSCEF */ + case 0x3e: /* VSTM */ + case 0x3f: /* VSTL */ + return true; + } + break; case 0xeb: /* RSY format insns */ switch (pinsn[2] & 0xff) { case 0x14: /* CSY */ diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c index 65fd5f3857..7c7afb652e 100644 --- a/linux-user/loongarch64/signal.c +++ b/linux-user/loongarch64/signal.c @@ -71,26 +71,6 @@ struct extctx_layout { struct ctx_layout end; }; -/* The kernel's sc_save_fcc macro is a sequence of MOVCF2GR+BSTRINS. */ -static uint64_t read_all_fcc(CPULoongArchState *env) -{ - uint64_t ret = 0; - - for (int i = 0; i < 8; ++i) { - ret |= (uint64_t)env->cf[i] << (i * 8); - } - - return ret; -} - -/* The kernel's sc_restore_fcc macro is a sequence of BSTRPICK+MOVGR2CF. */ -static void write_all_fcc(CPULoongArchState *env, uint64_t val) -{ - for (int i = 0; i < 8; ++i) { - env->cf[i] = (val >> (i * 8)) & 1; - } -} - static abi_ptr extframe_alloc(struct extctx_layout *extctx, struct ctx_layout *sctx, unsigned size, unsigned align, abi_ptr orig_sp) @@ -150,7 +130,7 @@ static void setup_sigframe(CPULoongArchState *env, for (i = 0; i < 32; ++i) { __put_user(env->fpr[i], &fpu_ctx->regs[i]); } - __put_user(read_all_fcc(env), &fpu_ctx->fcc); + __put_user(read_fcc(env), &fpu_ctx->fcc); __put_user(env->fcsr0, &fpu_ctx->fcsr); /* @@ -216,7 +196,7 @@ static void restore_sigframe(CPULoongArchState *env, __get_user(env->fpr[i], &fpu_ctx->regs[i]); } __get_user(fcc, &fpu_ctx->fcc); - write_all_fcc(env, fcc); + write_fcc(env, fcc); __get_user(env->fcsr0, &fpu_ctx->fcsr); restore_fp_status(env); } diff --git a/linux-user/loongarch64/target_mman.h b/linux-user/loongarch64/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/loongarch64/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/m68k/target_mman.h b/linux-user/m68k/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/m68k/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/main.c b/linux-user/main.c index 0656c80b85..1bb4261c07 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -124,10 +124,14 @@ static void usage(int exitcode); static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; +#if !defined(TARGET_DEFAULT_STACK_SIZE) /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example by remapping the process stack directly at the right place */ -unsigned long guest_stack_size = 8 * 1024 * 1024UL; +#define TARGET_DEFAULT_STACK_SIZE 8 * 1024 * 1024UL +#endif + +unsigned long guest_stack_size = TARGET_DEFAULT_STACK_SIZE; /***********************************************************/ /* Helper routines for implementing atomic operations. */ @@ -138,10 +142,12 @@ void fork_start(void) start_exclusive(); mmap_fork_start(); cpu_list_lock(); + qemu_plugin_user_prefork_lock(); } void fork_end(int child) { + qemu_plugin_user_postfork(child); mmap_fork_end(child); if (child) { CPUState *cpu, *next_cpu; @@ -713,7 +719,8 @@ int main(int argc, char **argv, char **envp) struct rlimit lim; if (getrlimit(RLIMIT_STACK, &lim) == 0 && lim.rlim_cur != RLIM_INFINITY - && lim.rlim_cur == (target_long)lim.rlim_cur) { + && lim.rlim_cur == (target_long)lim.rlim_cur + && lim.rlim_cur > guest_stack_size) { guest_stack_size = lim.rlim_cur; } } diff --git a/linux-user/microblaze/target_mman.h b/linux-user/microblaze/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/microblaze/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/mips/target_mman.h b/linux-user/mips/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/mips/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/mips64/target_mman.h b/linux-user/mips64/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/mips64/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 4e7a6be6ee..28f3bc85ed 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -22,6 +22,7 @@ #include "qemu.h" #include "user-internals.h" #include "user-mmap.h" +#include "target_mman.h" static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; static __thread int mmap_lock_count; @@ -105,6 +106,8 @@ static int validate_prot_to_pageflags(int *host_prot, int prot) page_flags |= PAGE_MTE; } } +#elif defined(TARGET_HPPA) + valid |= PROT_GROWSDOWN | PROT_GROWSUP; #endif return prot & ~valid ? 0 : page_flags; @@ -177,9 +180,11 @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot) goto error; } } + page_set_flags(start, start + len, page_flags); - mmap_unlock(); - return 0; + tb_invalidate_phys_range(start, start + len); + ret = 0; + error: mmap_unlock(); return ret; @@ -251,8 +256,12 @@ static int mmap_frag(abi_ulong real_start, # define TASK_UNMAPPED_BASE (1ul << 38) #endif #else +#ifdef TARGET_HPPA +# define TASK_UNMAPPED_BASE 0xfa000000 +#else # define TASK_UNMAPPED_BASE 0x40000000 #endif +#endif abi_ulong mmap_next_start = TASK_UNMAPPED_BASE; unsigned long last_brk; @@ -424,7 +433,8 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align) abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, int flags, int fd, abi_ulong offset) { - abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; + abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len, + passthrough_start = -1, passthrough_end = -1; int page_flags, host_prot; mmap_lock(); @@ -537,6 +547,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, host_start += offset - host_offset; } start = h2g(host_start); + passthrough_start = start; + passthrough_end = start + len; } else { if (start & ~TARGET_PAGE_MASK) { errno = EINVAL; @@ -619,6 +631,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, host_prot, flags, fd, offset1); if (p == MAP_FAILED) goto fail; + passthrough_start = real_start; + passthrough_end = real_end; } } the_end1: @@ -626,7 +640,18 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, page_flags |= PAGE_ANON; } page_flags |= PAGE_RESET; - page_set_flags(start, start + len, page_flags); + if (passthrough_start == passthrough_end) { + page_set_flags(start, start + len, page_flags); + } else { + if (start < passthrough_start) { + page_set_flags(start, passthrough_start, page_flags); + } + page_set_flags(passthrough_start, passthrough_end, + page_flags | PAGE_PASSTHROUGH); + if (passthrough_end < start + len) { + page_set_flags(passthrough_end, start + len, page_flags); + } + } the_end: trace_target_mmap_complete(start); if (qemu_loglevel_mask(CPU_LOG_PAGE)) { @@ -845,7 +870,7 @@ static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end) } for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) { - if (!(page_get_flags(addr) & PAGE_ANON)) { + if (!(page_get_flags(addr) & PAGE_PASSTHROUGH)) { return false; } } @@ -887,13 +912,17 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) * This is a hint, so ignoring and returning success is ok. * * This breaks MADV_DONTNEED, completely implementing which is quite - * complicated. However, there is one low-hanging fruit: host-page-aligned - * anonymous mappings. In this case passthrough is safe, so do it. + * complicated. However, there is one low-hanging fruit: mappings that are + * known to have the same semantics in the host and the guest. In this case + * passthrough is safe, so do it. */ mmap_lock(); - if ((advice & MADV_DONTNEED) && + if (advice == TARGET_MADV_DONTNEED && can_passthrough_madv_dontneed(start, end)) { ret = get_errno(madvise(g2h_untagged(start), len, MADV_DONTNEED)); + if (ret == 0) { + page_reset_target_data(start, start + len); + } } mmap_unlock(); diff --git a/linux-user/nios2/target_mman.h b/linux-user/nios2/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/nios2/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/openrisc/target_mman.h b/linux-user/openrisc/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/openrisc/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/ppc/target_mman.h b/linux-user/ppc/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/ppc/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 7d90de1b15..e2e93fbd1d 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -48,6 +48,7 @@ struct image_info { uint32_t elf_flags; int personality; abi_ulong alignment; + bool exec_stack; /* Generic semihosting knows about these pointers. */ abi_ulong arg_strings; /* strings for argv */ diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c index 296e39fbf0..eaa168199a 100644 --- a/linux-user/riscv/signal.c +++ b/linux-user/riscv/signal.c @@ -64,9 +64,7 @@ static abi_ulong get_sigframe(struct target_sigaction *ka, /* This is the X/Open sanctioned signal stack switching. */ sp = target_sigsp(sp, ka) - framesize; - - /* XXX: kernel aligns with 0xf ? */ - sp &= ~3UL; /* align sp on 4-byte boundary */ + sp &= ~0xf; return sp; } diff --git a/linux-user/riscv/target_mman.h b/linux-user/riscv/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/riscv/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 4979c4b017..f72165576f 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -146,6 +146,7 @@ static void save_sigregs(CPUS390XState *env, target_sigregs *sregs) * We have to store the fp registers to current->thread.fp_regs * to merge them with the emulated registers. */ + __put_user(env->fpc, &sregs->fpregs.fpc); for (i = 0; i < 16; i++) { __put_user(*get_freg(env, i), &sregs->fpregs.fprs[i]); } @@ -331,6 +332,7 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) for (i = 0; i < 16; i++) { __get_user(env->aregs[i], &sc->regs.acrs[i]); } + __get_user(env->fpc, &sc->fpregs.fpc); for (i = 0; i < 16; i++) { __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]); } diff --git a/linux-user/s390x/target_mman.h b/linux-user/s390x/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/s390x/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index f6a18bc6b5..c4ba962708 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -161,7 +161,7 @@ static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc) __get_user(regs->fpul, &sc->sc_fpul); regs->tra = -1; /* disable syscall checks */ - regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); + regs->flags = 0; } void setup_frame(int sig, struct target_sigaction *ka, @@ -199,7 +199,7 @@ void setup_frame(int sig, struct target_sigaction *ka, regs->gregs[5] = 0; regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc); regs->pc = (unsigned long) ka->_sa_handler; - regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); + regs->flags &= ~(TB_FLAG_DELAY_SLOT_MASK | TB_FLAG_GUSA_MASK); unlock_user_struct(frame, frame_addr, 1); return; @@ -251,7 +251,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info); regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc); regs->pc = (unsigned long) ka->_sa_handler; - regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); + regs->flags &= ~(TB_FLAG_DELAY_SLOT_MASK | TB_FLAG_GUSA_MASK); unlock_user_struct(frame, frame_addr, 1); return; diff --git a/linux-user/sh4/target_mman.h b/linux-user/sh4/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/sh4/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index 6a7e4a93fc..3e2dc604c2 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -118,4 +118,50 @@ static inline void finish_sigsuspend_mask(int ret) } } +#if defined(SIGSTKFLT) && defined(TARGET_SIGSTKFLT) +#define MAKE_SIG_ENTRY_SIGSTKFLT MAKE_SIG_ENTRY(SIGSTKFLT) +#else +#define MAKE_SIG_ENTRY_SIGSTKFLT +#endif + +#if defined(SIGIOT) && defined(TARGET_SIGIOT) +#define MAKE_SIG_ENTRY_SIGIOT MAKE_SIG_ENTRY(SIGIOT) +#else +#define MAKE_SIG_ENTRY_SIGIOT +#endif + +#define MAKE_SIGNAL_LIST \ + MAKE_SIG_ENTRY(SIGHUP) \ + MAKE_SIG_ENTRY(SIGINT) \ + MAKE_SIG_ENTRY(SIGQUIT) \ + MAKE_SIG_ENTRY(SIGILL) \ + MAKE_SIG_ENTRY(SIGTRAP) \ + MAKE_SIG_ENTRY(SIGABRT) \ + MAKE_SIG_ENTRY(SIGBUS) \ + MAKE_SIG_ENTRY(SIGFPE) \ + MAKE_SIG_ENTRY(SIGKILL) \ + MAKE_SIG_ENTRY(SIGUSR1) \ + MAKE_SIG_ENTRY(SIGSEGV) \ + MAKE_SIG_ENTRY(SIGUSR2) \ + MAKE_SIG_ENTRY(SIGPIPE) \ + MAKE_SIG_ENTRY(SIGALRM) \ + MAKE_SIG_ENTRY(SIGTERM) \ + MAKE_SIG_ENTRY(SIGCHLD) \ + MAKE_SIG_ENTRY(SIGCONT) \ + MAKE_SIG_ENTRY(SIGSTOP) \ + MAKE_SIG_ENTRY(SIGTSTP) \ + MAKE_SIG_ENTRY(SIGTTIN) \ + MAKE_SIG_ENTRY(SIGTTOU) \ + MAKE_SIG_ENTRY(SIGURG) \ + MAKE_SIG_ENTRY(SIGXCPU) \ + MAKE_SIG_ENTRY(SIGXFSZ) \ + MAKE_SIG_ENTRY(SIGVTALRM) \ + MAKE_SIG_ENTRY(SIGPROF) \ + MAKE_SIG_ENTRY(SIGWINCH) \ + MAKE_SIG_ENTRY(SIGIO) \ + MAKE_SIG_ENTRY(SIGPWR) \ + MAKE_SIG_ENTRY(SIGSYS) \ + MAKE_SIG_ENTRY_SIGSTKFLT \ + MAKE_SIG_ENTRY_SIGIOT + #endif diff --git a/linux-user/signal.c b/linux-user/signal.c index cb2c4a6482..bf559f8b3e 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -53,40 +53,9 @@ abi_ulong default_rt_sigreturn; QEMU_BUILD_BUG_ON(__SIGRTMAX + 1 != _NSIG); #endif static uint8_t host_to_target_signal_table[_NSIG] = { - [SIGHUP] = TARGET_SIGHUP, - [SIGINT] = TARGET_SIGINT, - [SIGQUIT] = TARGET_SIGQUIT, - [SIGILL] = TARGET_SIGILL, - [SIGTRAP] = TARGET_SIGTRAP, - [SIGABRT] = TARGET_SIGABRT, -/* [SIGIOT] = TARGET_SIGIOT,*/ - [SIGBUS] = TARGET_SIGBUS, - [SIGFPE] = TARGET_SIGFPE, - [SIGKILL] = TARGET_SIGKILL, - [SIGUSR1] = TARGET_SIGUSR1, - [SIGSEGV] = TARGET_SIGSEGV, - [SIGUSR2] = TARGET_SIGUSR2, - [SIGPIPE] = TARGET_SIGPIPE, - [SIGALRM] = TARGET_SIGALRM, - [SIGTERM] = TARGET_SIGTERM, -#ifdef SIGSTKFLT - [SIGSTKFLT] = TARGET_SIGSTKFLT, -#endif - [SIGCHLD] = TARGET_SIGCHLD, - [SIGCONT] = TARGET_SIGCONT, - [SIGSTOP] = TARGET_SIGSTOP, - [SIGTSTP] = TARGET_SIGTSTP, - [SIGTTIN] = TARGET_SIGTTIN, - [SIGTTOU] = TARGET_SIGTTOU, - [SIGURG] = TARGET_SIGURG, - [SIGXCPU] = TARGET_SIGXCPU, - [SIGXFSZ] = TARGET_SIGXFSZ, - [SIGVTALRM] = TARGET_SIGVTALRM, - [SIGPROF] = TARGET_SIGPROF, - [SIGWINCH] = TARGET_SIGWINCH, - [SIGIO] = TARGET_SIGIO, - [SIGPWR] = TARGET_SIGPWR, - [SIGSYS] = TARGET_SIGSYS, +#define MAKE_SIG_ENTRY(sig) [sig] = TARGET_##sig, + MAKE_SIGNAL_LIST +#undef MAKE_SIG_ENTRY /* next signals stay the same */ }; diff --git a/linux-user/sparc/target_mman.h b/linux-user/sparc/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/sparc/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/strace.c b/linux-user/strace.c index 7d882526da..37bc96df9b 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -17,6 +17,8 @@ #include "qemu.h" #include "user-internals.h" #include "strace.h" +#include "signal-common.h" +#include "target_mman.h" struct syscallname { int nr; @@ -81,6 +83,7 @@ UNUSED static void print_buf(abi_long addr, abi_long len, int last); UNUSED static void print_raw_param(const char *, abi_long, int); UNUSED static void print_timeval(abi_ulong, int); UNUSED static void print_timespec(abi_ulong, int); +UNUSED static void print_timespec64(abi_ulong, int); UNUSED static void print_timezone(abi_ulong, int); UNUSED static void print_itimerval(abi_ulong, int); UNUSED static void print_number(abi_long, int); @@ -141,30 +144,21 @@ if( cmd == val ) { \ qemu_log("%d", cmd); } +static const char * const target_signal_name[] = { +#define MAKE_SIG_ENTRY(sig) [TARGET_##sig] = #sig, + MAKE_SIGNAL_LIST +#undef MAKE_SIG_ENTRY +}; + static void print_signal(abi_ulong arg, int last) { const char *signal_name = NULL; - switch(arg) { - case TARGET_SIGHUP: signal_name = "SIGHUP"; break; - case TARGET_SIGINT: signal_name = "SIGINT"; break; - case TARGET_SIGQUIT: signal_name = "SIGQUIT"; break; - case TARGET_SIGILL: signal_name = "SIGILL"; break; - case TARGET_SIGABRT: signal_name = "SIGABRT"; break; - case TARGET_SIGFPE: signal_name = "SIGFPE"; break; - case TARGET_SIGKILL: signal_name = "SIGKILL"; break; - case TARGET_SIGSEGV: signal_name = "SIGSEGV"; break; - case TARGET_SIGPIPE: signal_name = "SIGPIPE"; break; - case TARGET_SIGALRM: signal_name = "SIGALRM"; break; - case TARGET_SIGTERM: signal_name = "SIGTERM"; break; - case TARGET_SIGUSR1: signal_name = "SIGUSR1"; break; - case TARGET_SIGUSR2: signal_name = "SIGUSR2"; break; - case TARGET_SIGCHLD: signal_name = "SIGCHLD"; break; - case TARGET_SIGCONT: signal_name = "SIGCONT"; break; - case TARGET_SIGSTOP: signal_name = "SIGSTOP"; break; - case TARGET_SIGTTIN: signal_name = "SIGTTIN"; break; - case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break; + + if (arg < ARRAY_SIZE(target_signal_name)) { + signal_name = target_signal_name[arg]; } + if (signal_name == NULL) { print_raw_param("%ld", arg, last); return; @@ -803,6 +797,24 @@ print_syscall_ret_clock_gettime(CPUArchState *cpu_env, const struct syscallname #define print_syscall_ret_clock_getres print_syscall_ret_clock_gettime #endif +#if defined(TARGET_NR_clock_gettime64) +static void +print_syscall_ret_clock_gettime64(CPUArchState *cpu_env, const struct syscallname *name, + abi_long ret, abi_long arg0, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5) +{ + if (!print_syscall_err(ret)) { + qemu_log(TARGET_ABI_FMT_ld, ret); + qemu_log(" ("); + print_timespec64(arg1, 1); + qemu_log(")"); + } + + qemu_log("\n"); +} +#endif + #ifdef TARGET_NR_gettimeofday static void print_syscall_ret_gettimeofday(CPUArchState *cpu_env, const struct syscallname *name, @@ -1494,6 +1506,11 @@ print_file_mode(abi_long mode, int last) const char *sep = ""; const struct flags *m; + if (mode == 0) { + qemu_log("000%s", get_comma(last)); + return; + } + for (m = &mode_flags[0]; m->f_string != NULL; m++) { if ((m->f_value & mode) == m->f_value) { qemu_log("%s%s", m->f_string, sep); @@ -1660,6 +1677,27 @@ print_timespec(abi_ulong ts_addr, int last) } } +static void +print_timespec64(abi_ulong ts_addr, int last) +{ + if (ts_addr) { + struct target__kernel_timespec *ts; + + ts = lock_user(VERIFY_READ, ts_addr, sizeof(*ts), 1); + if (!ts) { + print_pointer(ts_addr, last); + return; + } + qemu_log("{tv_sec = %lld" + ",tv_nsec = %lld}%s", + (long long)tswap64(ts->tv_sec), (long long)tswap64(ts->tv_nsec), + get_comma(last)); + unlock_user(ts, ts_addr, 0); + } else { + qemu_log("NULL%s", get_comma(last)); + } +} + static void print_timezone(abi_ulong tz_addr, int last) { @@ -2275,6 +2313,19 @@ print_clock_gettime(CPUArchState *cpu_env, const struct syscallname *name, #define print_clock_getres print_clock_gettime #endif +#if defined(TARGET_NR_clock_gettime64) +static void +print_clock_gettime64(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_enums(clockids, arg0, 0); + print_pointer(arg1, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_clock_settime static void print_clock_settime(CPUArchState *cpu_env, const struct syscallname *name, @@ -2969,6 +3020,46 @@ print_stat(CPUArchState *cpu_env, const struct syscallname *name, #define print_lstat64 print_stat #endif +#if defined(TARGET_NR_madvise) +static struct enums madvise_advice[] = { + ENUM_TARGET(MADV_NORMAL), + ENUM_TARGET(MADV_RANDOM), + ENUM_TARGET(MADV_SEQUENTIAL), + ENUM_TARGET(MADV_WILLNEED), + ENUM_TARGET(MADV_DONTNEED), + ENUM_TARGET(MADV_FREE), + ENUM_TARGET(MADV_REMOVE), + ENUM_TARGET(MADV_DONTFORK), + ENUM_TARGET(MADV_DOFORK), + ENUM_TARGET(MADV_MERGEABLE), + ENUM_TARGET(MADV_UNMERGEABLE), + ENUM_TARGET(MADV_HUGEPAGE), + ENUM_TARGET(MADV_NOHUGEPAGE), + ENUM_TARGET(MADV_DONTDUMP), + ENUM_TARGET(MADV_DODUMP), + ENUM_TARGET(MADV_WIPEONFORK), + ENUM_TARGET(MADV_KEEPONFORK), + ENUM_TARGET(MADV_COLD), + ENUM_TARGET(MADV_PAGEOUT), + ENUM_TARGET(MADV_POPULATE_READ), + ENUM_TARGET(MADV_POPULATE_WRITE), + ENUM_TARGET(MADV_DONTNEED_LOCKED), + ENUM_END, +}; + +static void +print_madvise(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_pointer(arg0, 0); + print_raw_param("%d", arg1, 0); + print_enums(madvise_advice, arg2, 1); + print_syscall_epilogue(name); +} +#endif + #if defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) static void print_fstat(CPUArchState *cpu_env, const struct syscallname *name, @@ -3272,6 +3363,34 @@ print_openat(CPUArchState *cpu_env, const struct syscallname *name, } #endif +#ifdef TARGET_NR_pidfd_send_signal +static void +print_pidfd_send_signal(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + void *p; + target_siginfo_t uinfo; + + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + print_signal(arg1, 0); + + p = lock_user(VERIFY_READ, arg2, sizeof(target_siginfo_t), 1); + if (p) { + get_target_siginfo(&uinfo, p); + print_siginfo(&uinfo); + + unlock_user(p, arg2, 0); + } else { + print_pointer(arg2, 1); + } + + print_raw_param("%u", arg3, 0); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_mq_unlink static void print_mq_unlink(CPUArchState *cpu_env, const struct syscallname *name, @@ -3489,6 +3608,21 @@ print_unshare(CPUArchState *cpu_env, const struct syscallname *name, } #endif +#ifdef TARGET_NR_clock_nanosleep +static void +print_clock_nanosleep(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_enums(clockids, arg0, 0); + print_raw_param("%d", arg1, 0); + print_timespec(arg2, 0); + print_timespec(arg3, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_utime static void print_utime(CPUArchState *cpu_env, const struct syscallname *name, @@ -3576,44 +3710,37 @@ print_munmap(CPUArchState *cpu_env, const struct syscallname *name, #endif #ifdef TARGET_NR_futex -static void print_futex_op(abi_long tflag, int last) +static void print_futex_op(int cmd, int last) { -#define print_op(val) \ -if( cmd == val ) { \ - qemu_log(#val); \ - return; \ -} + static const char * const futex_names[] = { +#define NAME(X) [X] = #X + NAME(FUTEX_WAIT), + NAME(FUTEX_WAKE), + NAME(FUTEX_FD), + NAME(FUTEX_REQUEUE), + NAME(FUTEX_CMP_REQUEUE), + NAME(FUTEX_WAKE_OP), + NAME(FUTEX_LOCK_PI), + NAME(FUTEX_UNLOCK_PI), + NAME(FUTEX_TRYLOCK_PI), + NAME(FUTEX_WAIT_BITSET), + NAME(FUTEX_WAKE_BITSET), + NAME(FUTEX_WAIT_REQUEUE_PI), + NAME(FUTEX_CMP_REQUEUE_PI), + NAME(FUTEX_LOCK_PI2), +#undef NAME + }; - int cmd = (int)tflag; -#ifdef FUTEX_PRIVATE_FLAG - if (cmd & FUTEX_PRIVATE_FLAG) { - qemu_log("FUTEX_PRIVATE_FLAG|"); - cmd &= ~FUTEX_PRIVATE_FLAG; + unsigned base_cmd = cmd & FUTEX_CMD_MASK; + + if (base_cmd < ARRAY_SIZE(futex_names)) { + qemu_log("%s%s%s", + (cmd & FUTEX_PRIVATE_FLAG ? "FUTEX_PRIVATE_FLAG|" : ""), + (cmd & FUTEX_CLOCK_REALTIME ? "FUTEX_CLOCK_REALTIME|" : ""), + futex_names[base_cmd]); + } else { + qemu_log("0x%x", cmd); } -#endif -#ifdef FUTEX_CLOCK_REALTIME - if (cmd & FUTEX_CLOCK_REALTIME) { - qemu_log("FUTEX_CLOCK_REALTIME|"); - cmd &= ~FUTEX_CLOCK_REALTIME; - } -#endif - print_op(FUTEX_WAIT) - print_op(FUTEX_WAKE) - print_op(FUTEX_FD) - print_op(FUTEX_REQUEUE) - print_op(FUTEX_CMP_REQUEUE) - print_op(FUTEX_WAKE_OP) - print_op(FUTEX_LOCK_PI) - print_op(FUTEX_UNLOCK_PI) - print_op(FUTEX_TRYLOCK_PI) -#ifdef FUTEX_WAIT_BITSET - print_op(FUTEX_WAIT_BITSET) -#endif -#ifdef FUTEX_WAKE_BITSET - print_op(FUTEX_WAKE_BITSET) -#endif - /* unknown values */ - qemu_log("%d", cmd); } static void @@ -3621,11 +3748,23 @@ print_futex(CPUArchState *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5) { + abi_long op = arg1 & FUTEX_CMD_MASK; print_syscall_prologue(name); print_pointer(arg0, 0); print_futex_op(arg1, 0); print_raw_param(",%d", arg2, 0); - print_pointer(arg3, 0); /* struct timespec */ + switch (op) { + case FUTEX_WAIT: + case FUTEX_WAIT_BITSET: + case FUTEX_LOCK_PI: + case FUTEX_LOCK_PI2: + case FUTEX_WAIT_REQUEUE_PI: + print_timespec(arg3, 0); + break; + default: + print_pointer(arg3, 0); + break; + } print_pointer(arg4, 0); print_raw_param("%d", arg4, 1); print_syscall_epilogue(name); @@ -3780,26 +3919,37 @@ print_syscall(CPUArchState *cpu_env, int num, abi_long arg4, abi_long arg5, abi_long arg6) { int i; - const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")"; + FILE *f; + const char *format = "%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," + TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," + TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")"; - qemu_log("%d ", getpid()); + f = qemu_log_trylock(); + if (!f) { + return; + } + fprintf(f, "%d ", getpid()); - for(i=0;i #include #include + +#ifdef HAVE_SYS_MOUNT_FSCONFIG +/* + * glibc >= 2.36 linux/mount.h conflicts with sys/mount.h, + * which in turn prevents use of linux/fs.h. So we have to + * define the constants ourselves for now. + */ +#define FS_IOC_GETFLAGS _IOR('f', 1, long) +#define FS_IOC_SETFLAGS _IOW('f', 2, long) +#define FS_IOC_GETVERSION _IOR('v', 1, long) +#define FS_IOC_SETVERSION _IOW('v', 2, long) +#define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap) +#define FS_IOC32_GETFLAGS _IOR('f', 1, int) +#define FS_IOC32_SETFLAGS _IOW('f', 2, int) +#define FS_IOC32_GETVERSION _IOR('v', 1, int) +#define FS_IOC32_SETVERSION _IOW('v', 2, int) +#else #include +#endif #include #if defined(CONFIG_FIEMAP) #include @@ -328,6 +346,16 @@ _syscall6(int,sys_futex,int *,uaddr,int,op,int,val, _syscall6(int,sys_futex_time64,int *,uaddr,int,op,int,val, const struct timespec *,timeout,int *,uaddr2,int,val3) #endif +#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open) +_syscall2(int, pidfd_open, pid_t, pid, unsigned int, flags); +#endif +#if defined(__NR_pidfd_send_signal) && defined(TARGET_NR_pidfd_send_signal) +_syscall4(int, pidfd_send_signal, int, pidfd, int, sig, siginfo_t *, info, + unsigned int, flags); +#endif +#if defined(__NR_pidfd_getfd) && defined(TARGET_NR_pidfd_getfd) +_syscall3(int, pidfd_getfd, int, pidfd, int, targetfd, unsigned int, flags); +#endif #define __NR_sys_sched_getaffinity __NR_sched_getaffinity _syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len, unsigned long *, user_mask_ptr); @@ -497,20 +525,25 @@ _syscall4(int, sys_prlimit64, pid_t, pid, int, resource, #if defined(TARGET_NR_timer_create) /* Maximum of 32 active POSIX timers allowed at any one time. */ -static timer_t g_posix_timers[32] = { 0, } ; +#define GUEST_TIMER_MAX 32 +static timer_t g_posix_timers[GUEST_TIMER_MAX]; +static int g_posix_timer_allocated[GUEST_TIMER_MAX]; static inline int next_free_host_timer(void) { - int k ; - /* FIXME: Does finding the next free slot require a lock? */ - for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) { - if (g_posix_timers[k] == 0) { - g_posix_timers[k] = (timer_t) 1; + int k; + for (k = 0; k < ARRAY_SIZE(g_posix_timer_allocated); k++) { + if (qatomic_xchg(g_posix_timer_allocated + k, 1) == 0) { return k; } } return -1; } + +static inline void free_host_timer_slot(int id) +{ + qatomic_store_release(g_posix_timer_allocated + id, 0); +} #endif static inline int host_to_target_errno(int host_errno) @@ -7771,15 +7804,16 @@ static int do_safe_futex(int *uaddr, int op, int val, futexes locally would make futexes shared between multiple processes tricky. However they're probably useless because guest atomic operations won't work either. */ -#if defined(TARGET_NR_futex) -static int do_futex(CPUState *cpu, target_ulong uaddr, int op, int val, - target_ulong timeout, target_ulong uaddr2, int val3) +#if defined(TARGET_NR_futex) || defined(TARGET_NR_futex_time64) +static int do_futex(CPUState *cpu, bool time64, target_ulong uaddr, + int op, int val, target_ulong timeout, + target_ulong uaddr2, int val3) { - struct timespec ts, *pts; + struct timespec ts, *pts = NULL; + void *haddr2 = NULL; int base_op; - /* ??? We assume FUTEX_* constants are the same on both host - and target. */ + /* We assume FUTEX_* constants are the same on both host and target. */ #ifdef FUTEX_CMD_MASK base_op = op & FUTEX_CMD_MASK; #else @@ -7788,85 +7822,53 @@ static int do_futex(CPUState *cpu, target_ulong uaddr, int op, int val, switch (base_op) { case FUTEX_WAIT: case FUTEX_WAIT_BITSET: - if (timeout) { - pts = &ts; - target_to_host_timespec(pts, timeout); - } else { - pts = NULL; - } - return do_safe_futex(g2h(cpu, uaddr), - op, tswap32(val), pts, NULL, val3); + val = tswap32(val); + break; + case FUTEX_WAIT_REQUEUE_PI: + val = tswap32(val); + haddr2 = g2h(cpu, uaddr2); + break; + case FUTEX_LOCK_PI: + case FUTEX_LOCK_PI2: + break; case FUTEX_WAKE: - return do_safe_futex(g2h(cpu, uaddr), - op, val, NULL, NULL, 0); + case FUTEX_WAKE_BITSET: + case FUTEX_TRYLOCK_PI: + case FUTEX_UNLOCK_PI: + timeout = 0; + break; case FUTEX_FD: - return do_safe_futex(g2h(cpu, uaddr), - op, val, NULL, NULL, 0); - case FUTEX_REQUEUE: + val = target_to_host_signal(val); + timeout = 0; + break; case FUTEX_CMP_REQUEUE: + case FUTEX_CMP_REQUEUE_PI: + val3 = tswap32(val3); + /* fall through */ + case FUTEX_REQUEUE: case FUTEX_WAKE_OP: - /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the - TIMEOUT parameter is interpreted as a uint32_t by the kernel. - But the prototype takes a `struct timespec *'; insert casts - to satisfy the compiler. We do not need to tswap TIMEOUT - since it's not compared to guest memory. */ - pts = (struct timespec *)(uintptr_t) timeout; - return do_safe_futex(g2h(cpu, uaddr), op, val, pts, g2h(cpu, uaddr2), - (base_op == FUTEX_CMP_REQUEUE - ? tswap32(val3) : val3)); + /* + * For these, the 4th argument is not TIMEOUT, but VAL2. + * But the prototype of do_safe_futex takes a pointer, so + * insert casts to satisfy the compiler. We do not need + * to tswap VAL2 since it's not compared to guest memory. + */ + pts = (struct timespec *)(uintptr_t)timeout; + timeout = 0; + haddr2 = g2h(cpu, uaddr2); + break; default: return -TARGET_ENOSYS; } -} -#endif - -#if defined(TARGET_NR_futex_time64) -static int do_futex_time64(CPUState *cpu, target_ulong uaddr, int op, - int val, target_ulong timeout, - target_ulong uaddr2, int val3) -{ - struct timespec ts, *pts; - int base_op; - - /* ??? We assume FUTEX_* constants are the same on both host - and target. */ -#ifdef FUTEX_CMD_MASK - base_op = op & FUTEX_CMD_MASK; -#else - base_op = op; -#endif - switch (base_op) { - case FUTEX_WAIT: - case FUTEX_WAIT_BITSET: - if (timeout) { - pts = &ts; - if (target_to_host_timespec64(pts, timeout)) { - return -TARGET_EFAULT; - } - } else { - pts = NULL; + if (timeout) { + pts = &ts; + if (time64 + ? target_to_host_timespec64(pts, timeout) + : target_to_host_timespec(pts, timeout)) { + return -TARGET_EFAULT; } - return do_safe_futex(g2h(cpu, uaddr), op, - tswap32(val), pts, NULL, val3); - case FUTEX_WAKE: - return do_safe_futex(g2h(cpu, uaddr), op, val, NULL, NULL, 0); - case FUTEX_FD: - return do_safe_futex(g2h(cpu, uaddr), op, val, NULL, NULL, 0); - case FUTEX_REQUEUE: - case FUTEX_CMP_REQUEUE: - case FUTEX_WAKE_OP: - /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the - TIMEOUT parameter is interpreted as a uint32_t by the kernel. - But the prototype takes a `struct timespec *'; insert casts - to satisfy the compiler. We do not need to tswap TIMEOUT - since it's not compared to guest memory. */ - pts = (struct timespec *)(uintptr_t) timeout; - return do_safe_futex(g2h(cpu, uaddr), op, val, pts, g2h(cpu, uaddr2), - (base_op == FUTEX_CMP_REQUEUE - ? tswap32(val3) : val3)); - default: - return -TARGET_ENOSYS; } + return do_safe_futex(g2h(cpu, uaddr), op, val, pts, haddr2, val3); } #endif @@ -8044,7 +8046,11 @@ static int open_self_maps(CPUArchState *cpu_env, int fd) continue; } +#ifdef TARGET_HPPA + if (h2g(max) == ts->info->stack_limit) { +#else if (h2g(min) == ts->info->stack_limit) { +#endif path = "[stack]"; } else { path = e->path; @@ -8296,16 +8302,22 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int char filename[PATH_MAX]; int fd, r; - /* create temporary file to map stat to */ - tmpdir = getenv("TMPDIR"); - if (!tmpdir) - tmpdir = "/tmp"; - snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir); - fd = mkstemp(filename); + fd = memfd_create("qemu-open", 0); if (fd < 0) { - return fd; + if (errno != ENOSYS) { + return fd; + } + /* create temporary file to map stat to */ + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir); + fd = mkstemp(filename); + if (fd < 0) { + return fd; + } + unlink(filename); } - unlink(filename); if ((r = fake_open->fill(cpu_env, fd))) { int e = errno; @@ -8695,6 +8707,30 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, ret = do_open_by_handle_at(arg1, arg2, arg3); fd_trans_unregister(ret); return ret; +#endif +#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open) + case TARGET_NR_pidfd_open: + return get_errno(pidfd_open(arg1, arg2)); +#endif +#if defined(__NR_pidfd_send_signal) && defined(TARGET_NR_pidfd_send_signal) + case TARGET_NR_pidfd_send_signal: + { + siginfo_t uinfo; + + p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1); + if (!p) { + return -TARGET_EFAULT; + } + target_to_host_siginfo(&uinfo, p); + unlock_user(p, arg3, 0); + ret = get_errno(pidfd_send_signal(arg1, target_to_host_signal(arg2), + &uinfo, arg4)); + } + return ret; +#endif +#if defined(__NR_pidfd_getfd) && defined(TARGET_NR_pidfd_getfd) + case TARGET_NR_pidfd_getfd: + return get_errno(pidfd_getfd(arg1, arg2, arg3)); #endif case TARGET_NR_close: fd_trans_unregister(arg1); @@ -9702,7 +9738,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, } target_to_host_siginfo(&uinfo, p); unlock_user(p, arg3, 0); - ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); + ret = get_errno(sys_rt_sigqueueinfo(arg1, target_to_host_signal(arg2), &uinfo)); } return ret; case TARGET_NR_rt_tgsigqueueinfo: @@ -9715,7 +9751,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, } target_to_host_siginfo(&uinfo, p); unlock_user(p, arg4, 0); - ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo)); + ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, target_to_host_signal(arg3), &uinfo)); } return ret; #ifdef TARGET_NR_sigreturn @@ -9924,11 +9960,22 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); if (!p || !p2) { ret = -TARGET_EFAULT; + } else if (!arg4) { + /* Short circuit this for the magic exe check. */ + ret = -TARGET_EINVAL; } else if (is_proc_myself((const char *)p, "exe")) { char real[PATH_MAX], *temp; temp = realpath(exec_path, real); - ret = temp == NULL ? get_errno(-1) : strlen(real) ; - snprintf((char *)p2, arg4, "%s", real); + /* Return value is # of bytes that we wrote to the buffer. */ + if (temp == NULL) { + ret = get_errno(-1); + } else { + /* Don't worry about sign mismatch as earlier mapping + * logic would have thrown a bad address error. */ + ret = MIN(strlen(real), arg4); + /* We cannot NUL terminate the string. */ + memcpy(p2, real, ret); + } } else { ret = get_errno(readlinkat(arg1, path(p), p2, arg4)); } @@ -12330,11 +12377,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_futex case TARGET_NR_futex: - return do_futex(cpu, arg1, arg2, arg3, arg4, arg5, arg6); + return do_futex(cpu, false, arg1, arg2, arg3, arg4, arg5, arg6); #endif #ifdef TARGET_NR_futex_time64 case TARGET_NR_futex_time64: - return do_futex_time64(cpu, arg1, arg2, arg3, arg4, arg5, arg6); + return do_futex(cpu, true, arg1, arg2, arg3, arg4, arg5, arg6); #endif #ifdef CONFIG_INOTIFY #if defined(TARGET_NR_inotify_init) @@ -12859,15 +12906,18 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, phost_sevp = &host_sevp; ret = target_to_host_sigevent(phost_sevp, arg2); if (ret != 0) { + free_host_timer_slot(timer_index); return ret; } } ret = get_errno(timer_create(clkid, phost_sevp, phtimer)); if (ret) { - phtimer = NULL; + free_host_timer_slot(timer_index); } else { if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) { + timer_delete(*phtimer); + free_host_timer_slot(timer_index); return -TARGET_EFAULT; } } @@ -13003,7 +13053,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, } else { timer_t htimer = g_posix_timers[timerid]; ret = get_errno(timer_delete(htimer)); - g_posix_timers[timerid] = 0; + free_host_timer_slot(timerid); } return ret; } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 85b0f33e91..01ee10a88f 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1246,7 +1246,7 @@ struct target_winsize { #include "termbits.h" -#if defined(TARGET_MIPS) +#if defined(TARGET_MIPS) || defined(TARGET_XTENSA) #define TARGET_PROT_SEM 0x10 #else #define TARGET_PROT_SEM 0x08 @@ -2699,6 +2699,9 @@ struct target_drm_i915_getparam { #define FUTEX_TRYLOCK_PI 8 #define FUTEX_WAIT_BITSET 9 #define FUTEX_WAKE_BITSET 10 +#define FUTEX_WAIT_REQUEUE_PI 11 +#define FUTEX_CMP_REQUEUE_PI 12 +#define FUTEX_LOCK_PI2 13 #define FUTEX_PRIVATE_FLAG 128 #define FUTEX_CLOCK_REALTIME 256 diff --git a/linux-user/x86_64/target_elf.h b/linux-user/x86_64/target_elf.h index 7b76a90de8..3f628f8d66 100644 --- a/linux-user/x86_64/target_elf.h +++ b/linux-user/x86_64/target_elf.h @@ -9,6 +9,6 @@ #define X86_64_TARGET_ELF_H static inline const char *cpu_get_model(uint32_t eflags) { - return "qemu64"; + return "max"; } #endif diff --git a/linux-user/x86_64/target_mman.h b/linux-user/x86_64/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/x86_64/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/linux-user/xtensa/target_mman.h b/linux-user/xtensa/target_mman.h new file mode 100644 index 0000000000..e7ba6070fe --- /dev/null +++ b/linux-user/xtensa/target_mman.h @@ -0,0 +1 @@ +#include "../generic/target_mman.h" diff --git a/meson b/meson index 12f9f04ba0..3a9b285a55 160000 --- a/meson +++ b/meson @@ -1 +1 @@ -Subproject commit 12f9f04ba0decfda425dbbf9a501084c153a2d18 +Subproject commit 3a9b285a55b91b53b2acda987192274352ecb5be diff --git a/meson.build b/meson.build index 897d16cafa..73c4ec1e5d 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('qemu', ['c'], meson_version: '>=0.59.3', +project('qemu', ['c'], meson_version: '>=0.61.3', default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto', 'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'], version: files('VERSION')) @@ -180,10 +180,17 @@ endif ################## qemu_cflags = config_host['QEMU_CFLAGS'].split() -qemu_cxxflags = config_host['QEMU_CXXFLAGS'].split() qemu_objcflags = config_host['QEMU_OBJCFLAGS'].split() qemu_ldflags = config_host['QEMU_LDFLAGS'].split() +if enable_static + qemu_ldflags += get_option('b_pie') ? '-static-pie' : '-static' +endif + +# Detect support for PT_GNU_RELRO + DT_BIND_NOW. +# The combination is known as "full relro", because .got.plt is read-only too. +qemu_ldflags += cc.get_supported_link_arguments('-Wl,-z,relro', '-Wl,-z,now') + if targetos == 'windows' qemu_ldflags += cc.get_supported_link_arguments('-Wl,--no-seh', '-Wl,--nxcompat') # Disable ASLR for debug builds to allow debugging with gdb @@ -194,7 +201,6 @@ endif if get_option('gprof') qemu_cflags += ['-p'] - qemu_cxxflags += ['-p'] qemu_objcflags += ['-p'] qemu_ldflags += ['-p'] endif @@ -240,8 +246,38 @@ if get_option('fuzzing') endif add_global_arguments(qemu_cflags, native: false, language: ['c']) -add_global_arguments(qemu_cxxflags, native: false, language: ['cpp']) add_global_arguments(qemu_objcflags, native: false, language: ['objc']) + +# Check that the C++ compiler exists and works with the C compiler. +link_language = 'c' +linker = cc +qemu_cxxflags = [] +if add_languages('cpp', required: false, native: false) + cxx = meson.get_compiler('cpp') + add_global_arguments(['-D__STDC_LIMIT_MACROS', '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS'], + native: false, language: 'cpp') + foreach k: qemu_cflags + if k not in ['-Wstrict-prototypes', '-Wmissing-prototypes', '-Wnested-externs', + '-Wold-style-declaration', '-Wold-style-definition', '-Wredundant-decls'] + qemu_cxxflags += [k] + endif + endforeach + add_global_arguments(qemu_cxxflags, native: false, language: 'cpp') + + if cxx.links(files('scripts/main.c'), args: qemu_cflags) + link_language = 'cpp' + linker = cxx + else + message('C++ compiler does not work with C compiler') + message('Disabling C++-specific optional code') + endif +endif + +# Exclude --warn-common with TSan to suppress warnings from the TSan libraries. +if targetos != 'sunos' and not config_host.has_key('CONFIG_TSAN') + qemu_ldflags += linker.get_supported_link_arguments('-Wl,--warn-common') +endif + add_global_link_arguments(qemu_ldflags, native: false, language: ['c', 'cpp', 'objc']) if targetos == 'linux' @@ -255,14 +291,6 @@ add_project_arguments('-iquote', '.', '-iquote', meson.current_source_dir() / 'include', language: ['c', 'cpp', 'objc']) -link_language = meson.get_external_property('link_language', 'cpp') -if link_language == 'cpp' - add_languages('cpp', required: true, native: false) - cxx = meson.get_compiler('cpp') - linker = cxx -else - linker = cc -endif if host_machine.system() == 'darwin' add_languages('objc', required: false, native: false) endif @@ -487,6 +515,7 @@ meson.override_dependency('glib-2.0', glib) gio = not_found gdbus_codegen = not_found +gdbus_codegen_error = '@0@ requires gdbus-codegen, please install libgio' if not get_option('gio').auto() or have_system gio = dependency('gio-2.0', required: get_option('gio'), method: 'pkg-config', kwargs: static_kwargs) @@ -511,6 +540,10 @@ if not get_option('gio').auto() or have_system version: gio.version()) endif endif +if gdbus_codegen.found() and get_option('cfi') + gdbus_codegen = not_found + gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not support control flow integrity' +endif lttng = not_found if 'ust' in get_option('trace_backends') @@ -589,12 +622,6 @@ endif cocoa = dependency('appleframeworks', modules: ['Cocoa', 'CoreVideo'], required: get_option('cocoa')) -if cocoa.found() and get_option('sdl').enabled() - error('Cocoa and SDL cannot be enabled at the same time') -endif -if cocoa.found() and get_option('gtk').enabled() - error('Cocoa and GTK+ cannot be enabled at the same time') -endif vmnet = dependency('appleframeworks', modules: 'vmnet', required: get_option('vmnet')) if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h', @@ -643,6 +670,26 @@ else method: 'pkg-config', kwargs: static_kwargs) endif +slirp = not_found +if not get_option('slirp').auto() or have_system + slirp = dependency('slirp', required: get_option('slirp'), + method: 'pkg-config', kwargs: static_kwargs) + # slirp < 4.7 is incompatible with CFI support in QEMU. This is because + # it passes function pointers within libslirp as callbacks for timers. + # When using a system-wide shared libslirp, the type information for the + # callback is missing and the timer call produces a false positive with CFI. + # Do not use the "version" keyword argument to produce a better error. + # with control-flow integrity. + if get_option('cfi') and slirp.found() and slirp.version().version_compare('<4.7') + if get_option('slirp').enabled() + error('Control-Flow Integrity requires libslirp 4.7.') + else + warning('Cannot use libslirp since Control-Flow Integrity requires libslirp >= 4.7.') + slirp = not_found + endif + endif +endif + vde = not_found if not get_option('vde').auto() or have_system or have_tools vde = cc.find_library('vdeplug', has_headers: ['libvdeplug.h'], @@ -681,6 +728,11 @@ if not get_option('jack').auto() or have_system jack = dependency('jack', required: get_option('jack'), method: 'pkg-config', kwargs: static_kwargs) endif +sndio = not_found +if not get_option('sndio').auto() or have_system + sndio = dependency('sndio', required: get_option('sndio'), + method: 'pkg-config', kwargs: static_kwargs) +endif spice_protocol = not_found if not get_option('spice_protocol').auto() or have_system @@ -825,14 +877,10 @@ if have_system and get_option('curses').allowed() }''' curses_dep_list = targetos == 'windows' ? ['ncurses', 'ncursesw'] : ['ncursesw'] - foreach curses_dep : curses_dep_list - if not curses.found() - curses = dependency(curses_dep, - required: false, - method: 'pkg-config', - kwargs: static_kwargs) - endif - endforeach + curses = dependency(curses_dep_list, + required: false, + method: 'pkg-config', + kwargs: static_kwargs) msg = get_option('curses').enabled() ? 'curses library not found' : '' curses_compile_args = ['-DNCURSES_WIDECHAR=1'] if curses.found() @@ -921,7 +969,7 @@ if not get_option('brlapi').auto() or have_system endif sdl = not_found -if not get_option('sdl').auto() or (have_system and not cocoa.found()) +if not get_option('sdl').auto() or have_system sdl = dependency('sdl2', required: get_option('sdl'), kwargs: static_kwargs) sdl_image = not_found endif @@ -1097,7 +1145,7 @@ if (have_system or have_tools) and (virgl.found() or opengl.found()) gbm = dependency('gbm', method: 'pkg-config', required: false, kwargs: static_kwargs) endif -have_vhost_user_gpu = have_vhost_user_gpu and virgl.found() and gbm.found() +have_vhost_user_gpu = have_vhost_user_gpu and virgl.found() and opengl.found() and gbm.found() gnutls = not_found gnutls_crypto = not_found @@ -1187,7 +1235,7 @@ endif gtk = not_found gtkx11 = not_found vte = not_found -if not get_option('gtk').auto() or (have_system and not cocoa.found()) +if not get_option('gtk').auto() or have_system gtk = dependency('gtk+-3.0', version: '>=3.22.0', method: 'pkg-config', required: get_option('gtk'), @@ -1597,6 +1645,7 @@ if have_system 'oss': oss.found(), 'pa': pulse.found(), 'sdl': sdl.found(), + 'sndio': sndio.found(), } foreach k, v: audio_drivers_available config_host_data.set('CONFIG_AUDIO_' + k.to_upper(), v) @@ -1604,7 +1653,7 @@ if have_system # Default to native drivers first, OSS second, SDL third audio_drivers_priority = \ - [ 'pa', 'coreaudio', 'dsound', 'oss' ] + \ + [ 'pa', 'coreaudio', 'dsound', 'sndio', 'oss' ] + \ (targetos == 'linux' ? [] : [ 'sdl' ]) audio_drivers_default = [] foreach k: audio_drivers_priority @@ -1669,16 +1718,13 @@ endif have_host_block_device = (targetos != 'darwin' or cc.has_header('IOKit/storage/IOMedia.h')) -# FIXME enable_modules shouldn't be necessary, but: https://github.com/mesonbuild/meson/issues/8333 dbus_display = get_option('dbus_display') \ .require(gio.version().version_compare('>=2.64'), error_message: '-display dbus requires glib>=2.64') \ - .require(enable_modules, - error_message: '-display dbus requires --enable-modules') \ .require(gdbus_codegen.found(), - error_message: '-display dbus requires gdbus-codegen') \ - .require(opengl.found(), - error_message: '-display dbus requires epoxy/egl') \ + error_message: gdbus_codegen_error.format('-display dbus')) \ + .require(opengl.found() and gbm.found(), + error_message: '-display dbus requires epoxy/egl and gbm') \ .allowed() have_virtfs = get_option('virtfs') \ @@ -1878,7 +1924,7 @@ config_host_data.set('CONFIG_DEBUG_STACK_USAGE', get_option('debug_stack_usage') config_host_data.set('CONFIG_GPROF', get_option('gprof')) config_host_data.set('CONFIG_LIVE_BLOCK_MIGRATION', get_option('live_block_migration').allowed()) config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug')) -config_host_data.set('CONFIG_REPLICATION', get_option('live_block_migration').allowed()) +config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed()) # has_header config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h')) @@ -1890,6 +1936,9 @@ config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h')) config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h')) config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h')) config_host_data.set('HAVE_SYS_KCOV_H', cc.has_header('sys/kcov.h')) +if targetos == 'windows' + config_host_data.set('HAVE_AFUNIX_H', cc.has_header('afunix.h')) +endif # has_function config_host_data.set('CONFIG_ACCEPT4', cc.has_function('accept4')) @@ -1963,6 +2012,8 @@ config_host_data.set('HAVE_OPTRESET', cc.has_header_symbol('getopt.h', 'optreset')) config_host_data.set('HAVE_IPPROTO_MPTCP', cc.has_header_symbol('netinet/in.h', 'IPPROTO_MPTCP')) +config_host_data.set('HAVE_SYS_MOUNT_FSCONFIG', + cc.has_header_symbol('sys/mount.h', 'FSCONFIG_SET_FLAG')) # has_member config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID', @@ -2612,104 +2663,6 @@ if not get_option('capstone').auto() or have_system or have_user endif endif -slirp = not_found -slirp_opt = 'disabled' -if have_system - slirp_opt = get_option('slirp') - if slirp_opt in ['enabled', 'auto', 'system'] - have_internal = fs.exists(meson.current_source_dir() / 'slirp/meson.build') - slirp_dep_required = (slirp_opt == 'system' or - slirp_opt == 'enabled' and not have_internal) - slirp = dependency('slirp', kwargs: static_kwargs, - method: 'pkg-config', version: '>=4.1.0', - required: slirp_dep_required) - # slirp <4.7 is incompatible with CFI support in QEMU. This is because - # it passes function pointers within libslirp as callbacks for timers. - # When using a system-wide shared libslirp, the type information for the - # callback is missing and the timer call produces a false positive with CFI. - # Do not use the "version" keyword argument to produce a better error. - # with control-flow integrity. - if get_option('cfi') and slirp.found() and slirp.version().version_compare('<4.7') - if slirp_dep_required - error('Control-Flow Integrity requires libslirp 4.7.') - else - warning('Control-Flow Integrity requires libslirp 4.7, not using system-wide libslirp.') - slirp = not_found - endif - endif - if slirp.found() - slirp_opt = 'system' - elif have_internal - slirp_opt = 'internal' - else - slirp_opt = 'disabled' - endif - endif - if slirp_opt == 'internal' - slirp_deps = [] - if targetos == 'windows' - slirp_deps = cc.find_library('iphlpapi') - elif targetos == 'darwin' - slirp_deps = cc.find_library('resolv') - endif - slirp_conf = configuration_data() - slirp_conf.set('SLIRP_MAJOR_VERSION', meson.project_version().split('.')[0]) - slirp_conf.set('SLIRP_MINOR_VERSION', meson.project_version().split('.')[1]) - slirp_conf.set('SLIRP_MICRO_VERSION', meson.project_version().split('.')[2]) - slirp_conf.set_quoted('SLIRP_VERSION_STRING', meson.project_version()) - slirp_cargs = ['-DG_LOG_DOMAIN="Slirp"'] - slirp_files = [ - 'slirp/src/arp_table.c', - 'slirp/src/bootp.c', - 'slirp/src/cksum.c', - 'slirp/src/dhcpv6.c', - 'slirp/src/dnssearch.c', - 'slirp/src/if.c', - 'slirp/src/ip6_icmp.c', - 'slirp/src/ip6_input.c', - 'slirp/src/ip6_output.c', - 'slirp/src/ip_icmp.c', - 'slirp/src/ip_input.c', - 'slirp/src/ip_output.c', - 'slirp/src/mbuf.c', - 'slirp/src/misc.c', - 'slirp/src/ncsi.c', - 'slirp/src/ndp_table.c', - 'slirp/src/sbuf.c', - 'slirp/src/slirp.c', - 'slirp/src/socket.c', - 'slirp/src/state.c', - 'slirp/src/stream.c', - 'slirp/src/tcp_input.c', - 'slirp/src/tcp_output.c', - 'slirp/src/tcp_subr.c', - 'slirp/src/tcp_timer.c', - 'slirp/src/tftp.c', - 'slirp/src/udp.c', - 'slirp/src/udp6.c', - 'slirp/src/util.c', - 'slirp/src/version.c', - 'slirp/src/vmstate.c', - ] - - configure_file( - input : 'slirp/src/libslirp-version.h.in', - output : 'libslirp-version.h', - configuration: slirp_conf) - - slirp_inc = include_directories('slirp', 'slirp/src') - libslirp = static_library('slirp', - build_by_default: false, - sources: slirp_files, - c_args: slirp_cargs, - include_directories: slirp_inc, - pic: 'AS_SHARED_LIB' in config_host) - slirp = declare_dependency(link_with: libslirp, - dependencies: slirp_deps, - include_directories: slirp_inc) - endif -endif - libvfio_user_dep = not_found if have_system and vfio_user_server_allowed have_internal = fs.exists(meson.current_source_dir() / 'subprojects/libvfio-user/meson.build') @@ -2911,6 +2864,7 @@ trace_events_subdirs = [ 'qom', 'monitor', 'util', + 'gdbstub', ] if have_linux_user trace_events_subdirs += [ 'linux-user' ] @@ -3034,6 +2988,7 @@ subdir('authz') subdir('crypto') subdir('ui') subdir('hw') +subdir('gdbstub') if enable_modules @@ -3114,7 +3069,7 @@ common_ss.add(files('cpus-common.c')) subdir('softmmu') common_ss.add(capstone) -specific_ss.add(files('cpu.c', 'disas.c', 'gdbstub.c'), capstone) +specific_ss.add(files('cpu.c', 'disas.c'), capstone) # Work around a gcc bug/misfeature wherein constant propagation looks # through an alias: @@ -3419,7 +3374,6 @@ foreach target : target_dirs target_inc += include_directories('linux-headers', is_system: true) endif if target.endswith('-softmmu') - qemu_target_name = 'qemu-system-' + target_name target_type='system' t = target_softmmu_arch[target_base_arch].apply(config_target, strict: false) arch_srcs += t.sources() @@ -3436,7 +3390,6 @@ foreach target : target_dirs abi = config_target['TARGET_ABI_DIR'] target_type='user' target_inc += common_user_inc - qemu_target_name = 'qemu-' + target_name if target_base_arch in target_user_arch t = target_user_arch[target_base_arch].apply(config_target, strict: false) arch_srcs += t.sources() @@ -3751,7 +3704,7 @@ summary_info += {'genisoimage': config_host['GENISOIMAGE']} if targetos == 'windows' and have_ga summary_info += {'wixl': wixl} endif -if slirp_opt != 'disabled' and have_system +if slirp.found() and have_system summary_info += {'smbd': have_slirp_smbd ? smbd_path : false} endif summary(summary_info, bool_yn: true, section: 'Host binaries') @@ -3848,7 +3801,7 @@ summary(summary_info, bool_yn: true, section: 'Compilation') summary_info = {} have_cross = false foreach target: target_dirs - tcg_mak = meson.current_build_dir() / 'tests/tcg' / 'config-' + target + '.mak' + tcg_mak = meson.current_build_dir() / 'tests/tcg' / target / 'config-target.mak' if fs.exists(tcg_mak) config_cross_tcg = keyval.load(tcg_mak) if 'CC' in config_cross_tcg @@ -3945,7 +3898,7 @@ summary_info += {'SDL image support': sdl_image} summary_info += {'GTK support': gtk} summary_info += {'pixman': pixman} summary_info += {'VTE support': vte} -summary_info += {'slirp support': slirp_opt == 'internal' ? slirp_opt : slirp} +summary_info += {'slirp support': slirp} summary_info += {'libtasn1': tasn1} summary_info += {'PAM': pam} summary_info += {'iconv support': iconv} @@ -3961,6 +3914,7 @@ if vnc.found() endif if targetos not in ['darwin', 'haiku', 'windows'] summary_info += {'OSS support': oss} + summary_info += {'sndio support': sndio} elif targetos == 'darwin' summary_info += {'CoreAudio support': coreaudio} elif targetos == 'windows' diff --git a/meson_options.txt b/meson_options.txt index e58e158396..79c6af18d5 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -21,7 +21,7 @@ option('tls_priority', type : 'string', value : 'NORMAL', option('default_devices', type : 'boolean', value : true, description: 'Include a default selection of devices in emulators') option('audio_drv_list', type: 'array', value: ['default'], - choices: ['alsa', 'coreaudio', 'default', 'dsound', 'jack', 'oss', 'pa', 'sdl'], + choices: ['alsa', 'coreaudio', 'default', 'dsound', 'jack', 'oss', 'pa', 'sdl', 'sndio'], description: 'Set audio driver list') option('block_drv_rw_whitelist', type : 'string', value : '', description: 'set block driver read-write whitelist (by default affects only QEMU, not tools like qemu-img)') @@ -82,9 +82,9 @@ option('tcg', type: 'feature', value: 'enabled', description: 'TCG support') option('tcg_interpreter', type: 'boolean', value: false, description: 'TCG with bytecode interpreter (slow)') -option('cfi', type: 'boolean', value: 'false', +option('cfi', type: 'boolean', value: false, description: 'Control-Flow Integrity (CFI)') -option('cfi_debug', type: 'boolean', value: 'false', +option('cfi_debug', type: 'boolean', value: false, description: 'Verbose errors in case of CFI violation') option('multiprocess', type: 'feature', value: 'auto', description: 'Out of process device emulation support') @@ -199,6 +199,8 @@ option('l2tpv3', type : 'feature', value : 'auto', description: 'l2tpv3 network backend support') option('netmap', type : 'feature', value : 'auto', description: 'netmap network backend support') +option('slirp', type: 'feature', value: 'auto', + description: 'libslirp user mode network backend support') option('vde', type : 'feature', value : 'auto', description: 'vde network backend support') option('vmnet', type : 'feature', value : 'auto', @@ -240,6 +242,8 @@ option('oss', type: 'feature', value: 'auto', description: 'OSS sound support') option('pa', type: 'feature', value: 'auto', description: 'PulseAudio sound support') +option('sndio', type: 'feature', value: 'auto', + description: 'sndio sound support') option('vhost_kernel', type: 'feature', value: 'auto', description: 'vhost kernel backend support') @@ -264,9 +268,6 @@ option('vduse_blk_export', type: 'feature', value: 'auto', option('capstone', type: 'feature', value: 'auto', description: 'Whether and how to find the capstone library') -option('slirp', type: 'combo', value: 'auto', - choices: ['disabled', 'enabled', 'auto', 'system', 'internal'], - description: 'Whether and how to find the slirp library') option('fdt', type: 'combo', value: 'auto', choices: ['disabled', 'enabled', 'auto', 'system', 'internal'], description: 'Whether and how to find the libfdt library') diff --git a/migration/block.c b/migration/block.c index 9e5aae5898..3577c815a9 100644 --- a/migration/block.c +++ b/migration/block.c @@ -28,7 +28,7 @@ #include "sysemu/block-backend.h" #include "trace.h" -#define BLK_MIG_BLOCK_SIZE (1 << 20) +#define BLK_MIG_BLOCK_SIZE (1ULL << 20) #define BDRV_SECTORS_PER_DIRTY_CHUNK (BLK_MIG_BLOCK_SIZE >> BDRV_SECTOR_BITS) #define BLK_MIG_FLAG_DEVICE_BLOCK 0x01 diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index 795fab5c37..d6f1e01a70 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -119,9 +119,9 @@ static DirtyPageRecord *vcpu_dirty_stat_alloc(VcpuStat *stat) } stat->nvcpu = nvcpu; - stat->rates = g_malloc0(sizeof(DirtyRateVcpu) * nvcpu); + stat->rates = g_new0(DirtyRateVcpu, nvcpu); - records = g_malloc0(sizeof(DirtyPageRecord) * nvcpu); + records = g_new0(DirtyPageRecord, nvcpu); return records; } diff --git a/migration/migration.c b/migration/migration.c index e03f698a3c..739bb683f3 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -574,7 +574,8 @@ static void process_incoming_migration_bh(void *opaque) migration_incoming_state_destroy(); } -static void process_incoming_migration_co(void *opaque) +static void coroutine_fn +process_incoming_migration_co(void *opaque) { MigrationIncomingState *mis = migration_incoming_get_current(); PostcopyState ps; @@ -2617,6 +2618,7 @@ MultiFDCompression migrate_multifd_compression(void) s = migrate_get_current(); + assert(s->parameters.multifd_compression < MULTIFD_COMPRESSION__MAX); return s->parameters.multifd_compression; } @@ -4451,6 +4453,7 @@ static void migration_instance_init(Object *obj) /* Set has_* up only for parameter checks */ params->has_compress_level = true; params->has_compress_threads = true; + params->has_compress_wait_thread = true; params->has_decompress_threads = true; params->has_throttle_trigger_threshold = true; params->has_cpu_throttle_initial = true; @@ -4471,6 +4474,9 @@ static void migration_instance_init(Object *obj) params->has_announce_max = true; params->has_announce_rounds = true; params->has_announce_step = true; + params->has_tls_creds = true; + params->has_tls_hostname = true; + params->has_tls_authz = true; qemu_sem_init(&ms->postcopy_pause_sem, 0); qemu_sem_init(&ms->postcopy_pause_rp_sem, 0); diff --git a/migration/ram.c b/migration/ram.c index b94669ba5d..dc1de9ddbc 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1612,7 +1612,6 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset) { struct RAMSrcPageRequest *entry; RAMBlock *block = NULL; - size_t page_size; if (!postcopy_has_request(rs)) { return NULL; @@ -1629,13 +1628,10 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset) entry = QSIMPLEQ_FIRST(&rs->src_page_requests); block = entry->rb; *offset = entry->offset; - page_size = qemu_ram_pagesize(block); - /* Each page request should only be multiple page size of the ramblock */ - assert((entry->len % page_size) == 0); - if (entry->len > page_size) { - entry->len -= page_size; - entry->offset += page_size; + if (entry->len > TARGET_PAGE_SIZE) { + entry->len -= TARGET_PAGE_SIZE; + entry->offset += TARGET_PAGE_SIZE; } else { memory_region_unref(block->mr); QSIMPLEQ_REMOVE_HEAD(&rs->src_page_requests, next_req); @@ -1643,9 +1639,6 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset) migration_consume_urgent_request(); } - trace_unqueue_page(block->idstr, *offset, - test_bit((*offset >> TARGET_PAGE_BITS), block->bmap)); - return block; } @@ -2069,8 +2062,30 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss) { RAMBlock *block; ram_addr_t offset; + bool dirty; - block = unqueue_page(rs, &offset); + do { + block = unqueue_page(rs, &offset); + /* + * We're sending this page, and since it's postcopy nothing else + * will dirty it, and we must make sure it doesn't get sent again + * even if this queue request was received after the background + * search already sent it. + */ + if (block) { + unsigned long page; + + page = offset >> TARGET_PAGE_BITS; + dirty = test_bit(page, block->bmap); + if (!dirty) { + trace_get_queued_page_not_dirty(block->idstr, (uint64_t)offset, + page); + } else { + trace_get_queued_page(block->idstr, (uint64_t)offset, page); + } + } + + } while (block && !dirty); if (block) { /* See comment above postcopy_preempted_contains() */ diff --git a/migration/trace-events b/migration/trace-events index a34afe7b85..57003edcbd 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -85,6 +85,8 @@ put_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)" qemu_file_fclose(void) "" # ram.c +get_queued_page(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx" +get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx" migration_bitmap_sync_start(void) "" migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64 migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx" @@ -110,7 +112,6 @@ ram_save_iterate_big_wait(uint64_t milliconds, int iterations) "big wait: %" PRI ram_load_complete(int ret, uint64_t seq_iter) "exit_code %d seq iteration %" PRIu64 ram_write_tracking_ramblock_start(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu" ram_write_tracking_ramblock_stop(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu" -unqueue_page(char *block, uint64_t offset, bool dirty) "ramblock '%s' offset 0x%"PRIx64" dirty %d" postcopy_preempt_triggered(char *str, unsigned long page) "during sending ramblock %s offset 0x%lx" postcopy_preempt_restored(char *str, unsigned long page) "ramblock %s offset 0x%lx" postcopy_preempt_hit(char *str, uint64_t offset) "ramblock %s offset 0x%"PRIx64 diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index c6cd6f91dd..bab86c5537 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -43,6 +43,8 @@ #include "qapi/qapi-commands-stats.h" #include "qapi/qapi-commands-tpm.h" #include "qapi/qapi-commands-ui.h" +#include "qapi/qapi-commands-virtio.h" +#include "qapi/qapi-visit-virtio.h" #include "qapi/qapi-visit-net.h" #include "qapi/qapi-visit-migration.h" #include "qapi/qmp/qdict.h" @@ -730,7 +732,7 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) monitor_printf(mon, " "); if (dev->class_info->has_desc) { - monitor_printf(mon, "%s", dev->class_info->desc); + monitor_puts(mon, dev->class_info->desc); } else { monitor_printf(mon, "Class %04" PRId64, dev->class_info->q_class); } @@ -2258,12 +2260,12 @@ static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value) if (unit && value->base == 10 && value->exponent >= -18 && value->exponent <= 18 && value->exponent % 3 == 0) { - monitor_printf(mon, "%s", si_prefix(value->exponent)); + monitor_puts(mon, si_prefix(value->exponent)); } else if (unit && value->base == 2 && value->exponent >= 0 && value->exponent <= 60 && value->exponent % 10 == 0) { - monitor_printf(mon, "%s", iec_binary_prefix(value->exponent)); + monitor_puts(mon, iec_binary_prefix(value->exponent)); } else if (value->exponent) { /* Use exponential notation and write the unit's English name */ monitor_printf(mon, "* %d^%d%s", @@ -2273,7 +2275,7 @@ static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value) } if (value->has_unit) { - monitor_printf(mon, "%s", unit ? unit : StatsUnit_str(value->unit)); + monitor_puts(mon, unit ? unit : StatsUnit_str(value->unit)); } /* Print bucket size for linear histograms */ @@ -2472,3 +2474,311 @@ exit: exit_no_print: error_free(err); } + +static void hmp_virtio_dump_protocols(Monitor *mon, + VhostDeviceProtocols *pcol) +{ + strList *pcol_list = pcol->protocols; + while (pcol_list) { + monitor_printf(mon, "\t%s", pcol_list->value); + pcol_list = pcol_list->next; + if (pcol_list != NULL) { + monitor_printf(mon, ",\n"); + } + } + monitor_printf(mon, "\n"); + if (pcol->has_unknown_protocols) { + monitor_printf(mon, " unknown-protocols(0x%016"PRIx64")\n", + pcol->unknown_protocols); + } +} + +static void hmp_virtio_dump_status(Monitor *mon, + VirtioDeviceStatus *status) +{ + strList *status_list = status->statuses; + while (status_list) { + monitor_printf(mon, "\t%s", status_list->value); + status_list = status_list->next; + if (status_list != NULL) { + monitor_printf(mon, ",\n"); + } + } + monitor_printf(mon, "\n"); + if (status->has_unknown_statuses) { + monitor_printf(mon, " unknown-statuses(0x%016"PRIx32")\n", + status->unknown_statuses); + } +} + +static void hmp_virtio_dump_features(Monitor *mon, + VirtioDeviceFeatures *features) +{ + strList *transport_list = features->transports; + while (transport_list) { + monitor_printf(mon, "\t%s", transport_list->value); + transport_list = transport_list->next; + if (transport_list != NULL) { + monitor_printf(mon, ",\n"); + } + } + + monitor_printf(mon, "\n"); + strList *list = features->dev_features; + if (list) { + while (list) { + monitor_printf(mon, "\t%s", list->value); + list = list->next; + if (list != NULL) { + monitor_printf(mon, ",\n"); + } + } + monitor_printf(mon, "\n"); + } + + if (features->has_unknown_dev_features) { + monitor_printf(mon, " unknown-features(0x%016"PRIx64")\n", + features->unknown_dev_features); + } +} + +void hmp_virtio_query(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + VirtioInfoList *list = qmp_x_query_virtio(&err); + VirtioInfoList *node; + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + if (list == NULL) { + monitor_printf(mon, "No VirtIO devices\n"); + return; + } + + node = list; + while (node) { + monitor_printf(mon, "%s [%s]\n", node->value->path, + node->value->name); + node = node->next; + } + qapi_free_VirtioInfoList(list); +} + +void hmp_virtio_status(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + VirtioStatus *s = qmp_x_query_virtio_status(path, &err); + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " device_name: %s %s\n", + s->name, s->has_vhost_dev ? "(vhost)" : ""); + monitor_printf(mon, " device_id: %d\n", s->device_id); + monitor_printf(mon, " vhost_started: %s\n", + s->vhost_started ? "true" : "false"); + monitor_printf(mon, " bus_name: %s\n", s->bus_name); + monitor_printf(mon, " broken: %s\n", + s->broken ? "true" : "false"); + monitor_printf(mon, " disabled: %s\n", + s->disabled ? "true" : "false"); + monitor_printf(mon, " disable_legacy_check: %s\n", + s->disable_legacy_check ? "true" : "false"); + monitor_printf(mon, " started: %s\n", + s->started ? "true" : "false"); + monitor_printf(mon, " use_started: %s\n", + s->use_started ? "true" : "false"); + monitor_printf(mon, " start_on_kick: %s\n", + s->start_on_kick ? "true" : "false"); + monitor_printf(mon, " use_guest_notifier_mask: %s\n", + s->use_guest_notifier_mask ? "true" : "false"); + monitor_printf(mon, " vm_running: %s\n", + s->vm_running ? "true" : "false"); + monitor_printf(mon, " num_vqs: %"PRId64"\n", s->num_vqs); + monitor_printf(mon, " queue_sel: %d\n", + s->queue_sel); + monitor_printf(mon, " isr: %d\n", s->isr); + monitor_printf(mon, " endianness: %s\n", + s->device_endian); + monitor_printf(mon, " status:\n"); + hmp_virtio_dump_status(mon, s->status); + monitor_printf(mon, " Guest features:\n"); + hmp_virtio_dump_features(mon, s->guest_features); + monitor_printf(mon, " Host features:\n"); + hmp_virtio_dump_features(mon, s->host_features); + monitor_printf(mon, " Backend features:\n"); + hmp_virtio_dump_features(mon, s->backend_features); + + if (s->has_vhost_dev) { + monitor_printf(mon, " VHost:\n"); + monitor_printf(mon, " nvqs: %d\n", + s->vhost_dev->nvqs); + monitor_printf(mon, " vq_index: %"PRId64"\n", + s->vhost_dev->vq_index); + monitor_printf(mon, " max_queues: %"PRId64"\n", + s->vhost_dev->max_queues); + monitor_printf(mon, " n_mem_sections: %"PRId64"\n", + s->vhost_dev->n_mem_sections); + monitor_printf(mon, " n_tmp_sections: %"PRId64"\n", + s->vhost_dev->n_tmp_sections); + monitor_printf(mon, " backend_cap: %"PRId64"\n", + s->vhost_dev->backend_cap); + monitor_printf(mon, " log_enabled: %s\n", + s->vhost_dev->log_enabled ? "true" : "false"); + monitor_printf(mon, " log_size: %"PRId64"\n", + s->vhost_dev->log_size); + monitor_printf(mon, " Features:\n"); + hmp_virtio_dump_features(mon, s->vhost_dev->features); + monitor_printf(mon, " Acked features:\n"); + hmp_virtio_dump_features(mon, s->vhost_dev->acked_features); + monitor_printf(mon, " Backend features:\n"); + hmp_virtio_dump_features(mon, s->vhost_dev->backend_features); + monitor_printf(mon, " Protocol features:\n"); + hmp_virtio_dump_protocols(mon, s->vhost_dev->protocol_features); + } + + qapi_free_VirtioStatus(s); +} + +void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + int queue = qdict_get_int(qdict, "queue"); + VirtVhostQueueStatus *s = + qmp_x_query_virtio_vhost_queue_status(path, queue, &err); + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " device_name: %s (vhost)\n", + s->name); + monitor_printf(mon, " kick: %"PRId64"\n", s->kick); + monitor_printf(mon, " call: %"PRId64"\n", s->call); + monitor_printf(mon, " VRing:\n"); + monitor_printf(mon, " num: %"PRId64"\n", s->num); + monitor_printf(mon, " desc: 0x%016"PRIx64"\n", s->desc); + monitor_printf(mon, " desc_phys: 0x%016"PRIx64"\n", + s->desc_phys); + monitor_printf(mon, " desc_size: %"PRId32"\n", s->desc_size); + monitor_printf(mon, " avail: 0x%016"PRIx64"\n", s->avail); + monitor_printf(mon, " avail_phys: 0x%016"PRIx64"\n", + s->avail_phys); + monitor_printf(mon, " avail_size: %"PRId32"\n", s->avail_size); + monitor_printf(mon, " used: 0x%016"PRIx64"\n", s->used); + monitor_printf(mon, " used_phys: 0x%016"PRIx64"\n", + s->used_phys); + monitor_printf(mon, " used_size: %"PRId32"\n", s->used_size); + + qapi_free_VirtVhostQueueStatus(s); +} + +void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + int queue = qdict_get_int(qdict, "queue"); + VirtQueueStatus *s = qmp_x_query_virtio_queue_status(path, queue, &err); + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " device_name: %s\n", s->name); + monitor_printf(mon, " queue_index: %d\n", s->queue_index); + monitor_printf(mon, " inuse: %d\n", s->inuse); + monitor_printf(mon, " used_idx: %d\n", s->used_idx); + monitor_printf(mon, " signalled_used: %d\n", + s->signalled_used); + monitor_printf(mon, " signalled_used_valid: %s\n", + s->signalled_used_valid ? "true" : "false"); + if (s->has_last_avail_idx) { + monitor_printf(mon, " last_avail_idx: %d\n", + s->last_avail_idx); + } + if (s->has_shadow_avail_idx) { + monitor_printf(mon, " shadow_avail_idx: %d\n", + s->shadow_avail_idx); + } + monitor_printf(mon, " VRing:\n"); + monitor_printf(mon, " num: %"PRId32"\n", s->vring_num); + monitor_printf(mon, " num_default: %"PRId32"\n", + s->vring_num_default); + monitor_printf(mon, " align: %"PRId32"\n", + s->vring_align); + monitor_printf(mon, " desc: 0x%016"PRIx64"\n", + s->vring_desc); + monitor_printf(mon, " avail: 0x%016"PRIx64"\n", + s->vring_avail); + monitor_printf(mon, " used: 0x%016"PRIx64"\n", + s->vring_used); + + qapi_free_VirtQueueStatus(s); +} + +void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + int queue = qdict_get_int(qdict, "queue"); + int index = qdict_get_try_int(qdict, "index", -1); + VirtioQueueElement *e; + VirtioRingDescList *list; + + e = qmp_x_query_virtio_queue_element(path, queue, index != -1, + index, &err); + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " device_name: %s\n", e->name); + monitor_printf(mon, " index: %d\n", e->index); + monitor_printf(mon, " desc:\n"); + monitor_printf(mon, " descs:\n"); + + list = e->descs; + while (list) { + monitor_printf(mon, " addr 0x%"PRIx64" len %d", + list->value->addr, list->value->len); + if (list->value->flags) { + strList *flag = list->value->flags; + monitor_printf(mon, " ("); + while (flag) { + monitor_printf(mon, "%s", flag->value); + flag = flag->next; + if (flag) { + monitor_printf(mon, ", "); + } + } + monitor_printf(mon, ")"); + } + list = list->next; + if (list) { + monitor_printf(mon, ",\n"); + } + } + monitor_printf(mon, "\n"); + monitor_printf(mon, " avail:\n"); + monitor_printf(mon, " flags: %d\n", e->avail->flags); + monitor_printf(mon, " idx: %d\n", e->avail->idx); + monitor_printf(mon, " ring: %d\n", e->avail->ring); + monitor_printf(mon, " used:\n"); + monitor_printf(mon, " flags: %d\n", e->used->flags); + monitor_printf(mon, " idx: %d\n", e->used->idx); + + qapi_free_VirtioQueueElement(e); +} diff --git a/monitor/hmp.c b/monitor/hmp.c index 15ca04735c..43fd69f984 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -285,10 +285,15 @@ void help_cmd(Monitor *mon, const char *name) if (!strcmp(name, "log")) { const QEMULogItem *item; monitor_printf(mon, "Log items (comma separated):\n"); - monitor_printf(mon, "%-10s %s\n", "none", "remove all logs"); + monitor_printf(mon, "%-15s %s\n", "none", "remove all logs"); for (item = qemu_log_items; item->mask != 0; item++) { - monitor_printf(mon, "%-10s %s\n", item->name, item->help); + monitor_printf(mon, "%-15s %s\n", item->name, item->help); } +#ifdef CONFIG_TRACE_LOG + monitor_printf(mon, "trace:PATTERN enable trace events\n"); + monitor_printf(mon, "\nUse \"log trace:help\" to get a list of " + "trace events.\n\n"); +#endif return; } @@ -1089,7 +1094,7 @@ static void hmp_info_human_readable_text(Monitor *mon, return; } - monitor_printf(mon, "%s", info->human_readable_text); + monitor_puts(mon, info->human_readable_text); } static void handle_hmp_command_exec(Monitor *mon, diff --git a/monitor/misc.c b/monitor/misc.c index 3d2312ba8d..6436a8786b 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -307,6 +307,7 @@ int monitor_get_cpu_index(Monitor *mon) static void hmp_info_registers(Monitor *mon, const QDict *qdict) { bool all_cpus = qdict_get_try_bool(qdict, "cpustate_all", false); + int vcpu = qdict_get_try_int(qdict, "vcpu", -1); CPUState *cs; if (all_cpus) { @@ -315,13 +316,18 @@ static void hmp_info_registers(Monitor *mon, const QDict *qdict) cpu_dump_state(cs, NULL, CPU_DUMP_FPU); } } else { - cs = mon_get_cpu(mon); + cs = vcpu >= 0 ? qemu_get_cpu(vcpu) : mon_get_cpu(mon); if (!cs) { - monitor_printf(mon, "No CPU available\n"); + if (vcpu >= 0) { + monitor_printf(mon, "CPU#%d not available\n", vcpu); + } else { + monitor_printf(mon, "No CPU available\n"); + } return; } + monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index); cpu_dump_state(cs, NULL, CPU_DUMP_FPU); } } diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index caa2e90ef2..a2cdbbf646 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -174,7 +174,6 @@ extern int mon_refcount; extern HMPCommand hmp_cmds[]; -int monitor_puts(Monitor *mon, const char *str); void monitor_data_init(Monitor *mon, bool is_qmp, bool skip_flush, bool use_io_thread); void monitor_data_destroy(Monitor *mon); diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 7314cd813d..81c8fdadf8 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -135,8 +135,11 @@ void qmp_cont(Error **errp) blk_iostatus_reset(blk); } - for (job = block_job_next(NULL); job; job = block_job_next(job)) { - block_job_iostatus_reset(job); + WITH_JOB_LOCK_GUARD() { + for (job = block_job_next_locked(NULL); job; + job = block_job_next_locked(job)) { + block_job_iostatus_reset_locked(job); + } } /* Continuing after completed migration. Images have been inactivated to diff --git a/net/colo.c b/net/colo.c index 6b0ff562ad..fb2c36a026 100644 --- a/net/colo.c +++ b/net/colo.c @@ -44,21 +44,28 @@ int parse_packet_early(Packet *pkt) { int network_length; static const uint8_t vlan[] = {0x81, 0x00}; - uint8_t *data = pkt->data + pkt->vnet_hdr_len; + uint8_t *data = pkt->data; uint16_t l3_proto; ssize_t l2hdr_len; - if (data == NULL) { - trace_colo_proxy_main_vnet_info("This packet is not parsed correctly, " - "pkt->vnet_hdr_len", pkt->vnet_hdr_len); - return 1; - } - l2hdr_len = eth_get_l2_hdr_length(data); + assert(data); - if (pkt->size < ETH_HLEN + pkt->vnet_hdr_len) { - trace_colo_proxy_main("pkt->size < ETH_HLEN"); + /* Check the received vnet_hdr_len then add the offset */ + if ((pkt->vnet_hdr_len > sizeof(struct virtio_net_hdr_v1_hash)) || + (pkt->size < sizeof(struct eth_header) + sizeof(struct vlan_header) + + pkt->vnet_hdr_len)) { + /* + * The received remote packet maybe misconfiguration here, + * Please enable/disable filter module's the vnet_hdr flag at + * the same time. + */ + trace_colo_proxy_main_vnet_info("This received packet load wrong ", + pkt->vnet_hdr_len, pkt->size); return 1; } + data += pkt->vnet_hdr_len; + + l2hdr_len = eth_get_l2_hdr_length(data); /* * TODO: support vlan. diff --git a/net/colo.h b/net/colo.h index 8b3e8d5a83..22fc3031f7 100644 --- a/net/colo.h +++ b/net/colo.h @@ -18,6 +18,7 @@ #include "qemu/jhash.h" #include "qemu/timer.h" #include "net/eth.h" +#include "standard-headers/linux/virtio_net.h" #define HASHTABLE_MAX_SIZE 16384 diff --git a/net/tap.c b/net/tap.c index b3ddfd4a74..e203d07a12 100644 --- a/net/tap.c +++ b/net/tap.c @@ -686,7 +686,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, tap_set_sndbuf(s->fd, tap, &err); if (err) { error_propagate(errp, err); - return; + goto failed; } if (tap->has_fd || tap->has_fds) { @@ -726,12 +726,12 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, } else { warn_report_err(err); } - return; + goto failed; } if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) { error_setg_errno(errp, errno, "%s: Can't use file descriptor %d", name, fd); - return; + goto failed; } } else { vhostfd = open("/dev/vhost-net", O_RDWR); @@ -743,11 +743,11 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, warn_report("tap: open vhost char device failed: %s", strerror(errno)); } - return; + goto failed; } if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) { error_setg_errno(errp, errno, "Failed to set FD nonblocking"); - return; + goto failed; } } options.opaque = (void *)(uintptr_t)vhostfd; @@ -760,11 +760,17 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, } else { warn_report(VHOST_NET_INIT_FAILED); } - return; + goto failed; } } else if (vhostfdname) { error_setg(errp, "vhostfd(s)= is not valid without vhost"); + goto failed; } + + return; + +failed: + qemu_del_net_client(&s->nc); } static int get_fds(char *str, char *fds[], int max) diff --git a/net/trace-events b/net/trace-events index 6af927b4b9..823a071bdc 100644 --- a/net/trace-events +++ b/net/trace-events @@ -9,7 +9,7 @@ vhost_user_event(const char *chr, int event) "chr: %s got event: %d" # colo.c colo_proxy_main(const char *chr) ": %s" -colo_proxy_main_vnet_info(const char *sta, int size) ": %s = %d" +colo_proxy_main_vnet_info(const char *sta, uint32_t vnet_hdr, int size) ": %s pkt->vnet_hdr_len = %u, pkt->size = %d" # colo-compare.c colo_compare_main(const char *chr) ": %s" diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 6abad276a6..4bc3fd01a8 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -35,7 +35,9 @@ typedef struct VhostVDPAState { VHostNetState *vhost_net; /* Control commands shadow buffers */ - void *cvq_cmd_out_buffer, *cvq_cmd_in_buffer; + void *cvq_cmd_out_buffer; + virtio_net_ctrl_ack *status; + bool started; } VhostVDPAState; @@ -92,6 +94,7 @@ static const uint64_t vdpa_svq_device_features = BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | BIT_ULL(VIRTIO_NET_F_STATUS) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | + BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_F_ANY_LAYOUT) | BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | BIT_ULL(VIRTIO_NET_F_RSC_EXT) | @@ -158,7 +161,7 @@ static void vhost_vdpa_cleanup(NetClientState *nc) struct vhost_dev *dev = &s->vhost_net->dev; qemu_vfree(s->cvq_cmd_out_buffer); - qemu_vfree(s->cvq_cmd_in_buffer); + qemu_vfree(s->status); if (dev->vq_index + dev->nvqs == dev->vq_index_end) { g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); } @@ -244,7 +247,7 @@ static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) error_report("Device cannot unmap: %s(%d)", g_strerror(r), r); } - vhost_iova_tree_remove(tree, map); + vhost_iova_tree_remove(tree, *map); } static size_t vhost_vdpa_net_cvq_cmd_len(void) @@ -263,29 +266,20 @@ static size_t vhost_vdpa_net_cvq_cmd_page_len(void) return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), qemu_real_host_page_size()); } -/** Copy and map a guest buffer. */ -static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, - const struct iovec *out_data, - size_t out_num, size_t data_len, void *buf, - size_t *written, bool write) +/** Map CVQ buffer. */ +static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size, + bool write) { DMAMap map = {}; int r; - if (unlikely(!data_len)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s buffer\n", - __func__, write ? "in" : "out"); - return false; - } - - *written = iov_to_buf(out_data, out_num, 0, buf, data_len); map.translated_addr = (hwaddr)(uintptr_t)buf; - map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1; + map.size = size - 1; map.perm = write ? IOMMU_RW : IOMMU_RO, r = vhost_iova_tree_map_alloc(v->iova_tree, &map); if (unlikely(r != IOVA_OK)) { error_report("Cannot map injected element"); - return false; + return r; } r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), buf, @@ -294,63 +288,195 @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, goto dma_map_err; } - return true; + return 0; dma_map_err: - vhost_iova_tree_remove(v->iova_tree, &map); - return false; + vhost_iova_tree_remove(v->iova_tree, map); + return r; } -/** - * Copy the guest element into a dedicated buffer suitable to be sent to NIC - * - * @iov: [0] is the out buffer, [1] is the in one - */ -static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s, - VirtQueueElement *elem, - struct iovec *iov) +static int vhost_vdpa_net_cvq_start(NetClientState *nc) { - size_t in_copied; - bool ok; + VhostVDPAState *s; + int r; - iov[0].iov_base = s->cvq_cmd_out_buffer; - ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, elem->out_sg, elem->out_num, - vhost_vdpa_net_cvq_cmd_len(), iov[0].iov_base, - &iov[0].iov_len, false); - if (unlikely(!ok)) { - return false; + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + + s = DO_UPCAST(VhostVDPAState, nc, nc); + if (!s->vhost_vdpa.shadow_vqs_enabled) { + return 0; } - iov[1].iov_base = s->cvq_cmd_in_buffer; - ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, NULL, 0, - sizeof(virtio_net_ctrl_ack), iov[1].iov_base, - &in_copied, true); - if (unlikely(!ok)) { + r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer, + vhost_vdpa_net_cvq_cmd_page_len(), false); + if (unlikely(r < 0)) { + return r; + } + + r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->status, + vhost_vdpa_net_cvq_cmd_page_len(), true); + if (unlikely(r < 0)) { vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); - return false; } - iov[1].iov_len = sizeof(virtio_net_ctrl_ack); - return true; + return r; } +static void vhost_vdpa_net_cvq_stop(NetClientState *nc) +{ + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + + if (s->vhost_vdpa.shadow_vqs_enabled) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->status); + } +} + +static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, + size_t in_len) +{ + /* Buffers for the device */ + const struct iovec out = { + .iov_base = s->cvq_cmd_out_buffer, + .iov_len = out_len, + }; + const struct iovec in = { + .iov_base = s->status, + .iov_len = sizeof(virtio_net_ctrl_ack), + }; + VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0); + int r; + + r = vhost_svq_add(svq, &out, 1, &in, 1, NULL); + if (unlikely(r != 0)) { + if (unlikely(r == -ENOSPC)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", + __func__); + } + return r; + } + + /* + * We can poll here since we've had BQL from the time we sent the + * descriptor. Also, we need to take the answer before SVQ pulls by itself, + * when BQL is released + */ + return vhost_svq_poll(svq); +} + +static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, + uint8_t cmd, const void *data, + size_t data_size) +{ + const struct virtio_net_ctrl_hdr ctrl = { + .class = class, + .cmd = cmd, + }; + + assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl)); + + memcpy(s->cvq_cmd_out_buffer, &ctrl, sizeof(ctrl)); + memcpy(s->cvq_cmd_out_buffer + sizeof(ctrl), data, data_size); + + return vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + data_size, + sizeof(virtio_net_ctrl_ack)); +} + +static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) +{ + uint64_t features = n->parent_obj.guest_features; + if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) { + ssize_t dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MAC, + VIRTIO_NET_CTRL_MAC_ADDR_SET, + n->mac, sizeof(n->mac)); + if (unlikely(dev_written < 0)) { + return dev_written; + } + + return *s->status != VIRTIO_NET_OK; + } + + return 0; +} + +static int vhost_vdpa_net_load_mq(VhostVDPAState *s, + const VirtIONet *n) +{ + struct virtio_net_ctrl_mq mq; + uint64_t features = n->parent_obj.guest_features; + ssize_t dev_written; + + if (!(features & BIT_ULL(VIRTIO_NET_F_MQ))) { + return 0; + } + + mq.virtqueue_pairs = cpu_to_le16(n->curr_queue_pairs); + dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MQ, + VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &mq, + sizeof(mq)); + if (unlikely(dev_written < 0)) { + return dev_written; + } + + return *s->status != VIRTIO_NET_OK; +} + +static int vhost_vdpa_net_load(NetClientState *nc) +{ + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + struct vhost_vdpa *v = &s->vhost_vdpa; + const VirtIONet *n; + int r; + + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + + if (!v->shadow_vqs_enabled) { + return 0; + } + + n = VIRTIO_NET(v->dev->vdev); + r = vhost_vdpa_net_load_mac(s, n); + if (unlikely(r < 0)) { + return r; + } + r = vhost_vdpa_net_load_mq(s, n); + if (unlikely(r)) { + return r; + } + + return 0; +} + +static NetClientInfo net_vhost_vdpa_cvq_info = { + .type = NET_CLIENT_DRIVER_VHOST_VDPA, + .size = sizeof(VhostVDPAState), + .receive = vhost_vdpa_receive, + .start = vhost_vdpa_net_cvq_start, + .load = vhost_vdpa_net_load, + .stop = vhost_vdpa_net_cvq_stop, + .cleanup = vhost_vdpa_cleanup, + .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, + .has_ufo = vhost_vdpa_has_ufo, + .check_peer_type = vhost_vdpa_check_peer_type, +}; + /** * Do not forward commands not supported by SVQ. Otherwise, the device could * accept it and qemu would not know how to update the device model. */ -static bool vhost_vdpa_net_cvq_validate_cmd(const struct iovec *out, - size_t out_num) +static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len) { struct virtio_net_ctrl_hdr ctrl; - size_t n; - n = iov_to_buf(out, out_num, 0, &ctrl, sizeof(ctrl)); - if (unlikely(n < sizeof(ctrl))) { + if (unlikely(len < sizeof(ctrl))) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid legnth of out buffer %zu\n", __func__, n); + "%s: invalid legnth of out buffer %zu\n", __func__, len); return false; } + memcpy(&ctrl, out_buf, sizeof(ctrl)); switch (ctrl.class) { case VIRTIO_NET_CTRL_MAC: switch (ctrl.cmd) { @@ -361,6 +487,15 @@ static bool vhost_vdpa_net_cvq_validate_cmd(const struct iovec *out, __func__, ctrl.cmd); }; break; + case VIRTIO_NET_CTRL_MQ: + switch (ctrl.cmd) { + case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: + return true; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mq cmd %u\n", + __func__, ctrl.cmd); + }; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid control class %u\n", __func__, ctrl.class); @@ -380,58 +515,44 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, void *opaque) { VhostVDPAState *s = opaque; - size_t in_len, dev_written; + size_t in_len; virtio_net_ctrl_ack status = VIRTIO_NET_ERR; - /* out and in buffers sent to the device */ - struct iovec dev_buffers[2] = { - { .iov_base = s->cvq_cmd_out_buffer }, - { .iov_base = s->cvq_cmd_in_buffer }, + /* Out buffer sent to both the vdpa device and the device model */ + struct iovec out = { + .iov_base = s->cvq_cmd_out_buffer, }; /* in buffer used for device model */ const struct iovec in = { .iov_base = &status, .iov_len = sizeof(status), }; - int r = -EINVAL; + ssize_t dev_written = -EINVAL; bool ok; - ok = vhost_vdpa_net_cvq_map_elem(s, elem, dev_buffers); + out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, + s->cvq_cmd_out_buffer, + vhost_vdpa_net_cvq_cmd_len()); + ok = vhost_vdpa_net_cvq_validate_cmd(s->cvq_cmd_out_buffer, out.iov_len); if (unlikely(!ok)) { goto out; } - ok = vhost_vdpa_net_cvq_validate_cmd(&dev_buffers[0], 1); - if (unlikely(!ok)) { + dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); + if (unlikely(dev_written < 0)) { goto out; } - r = vhost_svq_add(svq, &dev_buffers[0], 1, &dev_buffers[1], 1, elem); - if (unlikely(r != 0)) { - if (unlikely(r == -ENOSPC)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", - __func__); - } - goto out; - } - - /* - * We can poll here since we've had BQL from the time we sent the - * descriptor. Also, we need to take the answer before SVQ pulls by itself, - * when BQL is released - */ - dev_written = vhost_svq_poll(svq); if (unlikely(dev_written < sizeof(status))) { error_report("Insufficient written data (%zu)", dev_written); goto out; } - memcpy(&status, dev_buffers[1].iov_base, sizeof(status)); - if (status != VIRTIO_NET_OK) { - goto out; + if (*s->status != VIRTIO_NET_OK) { + return VIRTIO_NET_ERR; } status = VIRTIO_NET_ERR; - virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, dev_buffers, 1); + virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, &out, 1); if (status != VIRTIO_NET_OK) { error_report("Bad CVQ processing in model"); } @@ -444,13 +565,7 @@ out: } vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); g_free(elem); - if (dev_buffers[0].iov_base) { - vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[0].iov_base); - } - if (dev_buffers[1].iov_base) { - vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[1].iov_base); - } - return r; + return dev_written < 0 ? dev_written : 0; } static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { @@ -475,7 +590,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name); } else { - nc = qemu_new_net_control_client(&net_vhost_vdpa_info, peer, + nc = qemu_new_net_control_client(&net_vhost_vdpa_cvq_info, peer, device, name); } snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); @@ -489,14 +604,12 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size(), vhost_vdpa_net_cvq_cmd_page_len()); memset(s->cvq_cmd_out_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); - s->cvq_cmd_in_buffer = qemu_memalign(qemu_real_host_page_size(), - vhost_vdpa_net_cvq_cmd_page_len()); - memset(s->cvq_cmd_in_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); + s->status = qemu_memalign(qemu_real_host_page_size(), + vhost_vdpa_net_cvq_cmd_page_len()); + memset(s->status, 0, vhost_vdpa_net_cvq_cmd_page_len()); s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; s->vhost_vdpa.shadow_vq_ops_opaque = s; - error_setg(&s->vhost_vdpa.migration_blocker, - "Migration disabled: vhost-vdpa uses CVQ."); } ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); if (ret) { @@ -566,7 +679,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, g_autofree NetClientState **ncs = NULL; g_autoptr(VhostIOVATree) iova_tree = NULL; NetClientState *nc; - int queue_pairs, r, i, has_cvq = 0; + int queue_pairs, r, i = 0, has_cvq = 0; assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); opts = &netdev->u.vhost_vdpa; @@ -582,7 +695,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); if (unlikely(r < 0)) { - return r; + goto err; } queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, features, diff --git a/pc-bios/README b/pc-bios/README index ba6c15e769..b94f3fb081 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20220110. + built from git tag qemu-slof-20220719. - VOF (Virtual Open Firmware) is a minimalistic firmware to work with -machine pseries,x-vof=on. When enabled, the firmware acts as a slim shim and diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build index 2837eb34f4..06c75e646b 100644 --- a/pc-bios/keymaps/meson.build +++ b/pc-bios/keymaps/meson.build @@ -38,7 +38,6 @@ if meson.is_cross_build() or 'CONFIG_XKBCOMMON' not in config_host else native_qemu_keymap = qemu_keymap endif -cp = find_program('cp') if native_qemu_keymap.found() t = [] diff --git a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin index dba8e8655f..81bab1adc9 100644 Binary files a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin and b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin differ diff --git a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin index f223e56991..5eb0a74326 100644 Binary files a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin and b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin differ diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index e90ca2e1c6..b1fff0ba6c 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -8,53 +8,62 @@ all: multiboot.bin multiboot_dma.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bi CFLAGS = -O2 -g -quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) -cc-option = $(if $(shell $(CC) $1 -c -o /dev/null -xc /dev/null >/dev/null 2>&1 && echo OK), $1, $2) +NULL := +SPACE := $(NULL) # +TARGET_PREFIX := $(patsubst %/,%:$(SPACE),$(TARGET_DIR)) -override CFLAGS += -march=i486 -Wall $(EXTRA_CFLAGS) -m16 - -# If -fcf-protection is enabled in flags or compiler defaults that will -# conflict with -march=i486 -override CFLAGS += $(call cc-option, -fcf-protection=none) +quiet-@ = $(if $(V),,@$(if $1,printf "%s\n" "$(TARGET_PREFIX)$1" && )) +quiet-command = $(call quiet-@,$2 $@)$1 # Flags for dependency generation override CPPFLAGS += -MMD -MP -MT $@ -MF $(@D)/$(*F).d -override CFLAGS += $(filter -W%, $(QEMU_CFLAGS)) -override CFLAGS += $(call cc-option, -fno-pie) +override CFLAGS += -march=i486 -Wall $(EXTRA_CFLAGS) -m16 override CFLAGS += -ffreestanding -I$(TOPSRC_DIR)/include -override CFLAGS += $(call cc-option, -fno-stack-protector) -override CFLAGS += $(call cc-option, -Wno-array-bounds) -Wa = -Wa, -override ASFLAGS += -32 -override CFLAGS += $(call cc-option, $(Wa)-32) +cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>/dev/null +cc-option = if $(call cc-test, $1); then \ + echo "$(TARGET_PREFIX)$1 detected" && echo "override CFLAGS += $1" >&3; else \ + echo "$(TARGET_PREFIX)$1 not detected" $(if $2,&& echo "override CFLAGS += $2" >&3); fi -override LDFLAGS = -m $(LD_I386_EMULATION) -T $(SRC_DIR)/flat.lds +# If -fcf-protection is enabled in flags or compiler defaults that will +# conflict with -march=i486 +config-cc.mak: Makefile + $(quiet-@)($(call cc-option,-fcf-protection=none); \ + $(call cc-option,-fno-pie); \ + $(call cc-option,-no-pie); \ + $(call cc-option,-fno-stack-protector); \ + $(call cc-option,-Wno-array-bounds)) 3> config-cc.mak +-include config-cc.mak + +override LDFLAGS = -nostdlib -Wl,-T,$(SRC_DIR)/flat.lds pvh.img: pvh.o pvh_main.o %.o: %.S - $(call quiet-command,$(CC) $(CPPFLAGS) -E -o - $< | $(AS) $(ASFLAGS) -o $@,"AS","$@") + $(call quiet-command,$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<,Assembling) %.o: %.c - $(call quiet-command,$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@,"CC","$@") + $(call quiet-command,$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@,Compiling) %.img: %.o - $(call quiet-command,$(LD) $(LDFLAGS) -s -o $@ $^,"BUILD","$@") + $(call quiet-command,$(CC) $(CFLAGS) $(LDFLAGS) -s -o $@ $^,Linking) %.raw: %.img - $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"BUILD","$@") + $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,Extracting raw object) %.bin: %.raw - $(call quiet-command,$(PYTHON) $(TOPSRC_DIR)/scripts/signrom.py $< $@,"SIGN","$@") + $(call quiet-command,$(PYTHON) $(TOPSRC_DIR)/scripts/signrom.py $< $@,Computing checksum into) include $(wildcard *.d) clean: rm -f *.o *.d *.raw *.img *.bin *~ +distclean: + rm -f config-cc.mak + # suppress auto-removal of intermediate files .SECONDARY: -.PHONY: all clean +.PHONY: all clean distclean diff --git a/pc-bios/qboot.rom b/pc-bios/qboot.rom old mode 100644 new mode 100755 index 7634106a07..684000f57a Binary files a/pc-bios/qboot.rom and b/pc-bios/qboot.rom differ diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 39f9680a0e..554fcbd1b7 100644 Binary files a/pc-bios/s390-ccw.img and b/pc-bios/s390-ccw.img differ diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index c8784c2a08..10e8f5cb63 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -6,9 +6,12 @@ include config-host.mak CFLAGS = -O2 -g MAKEFLAGS += -rR -quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) -cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ - >/dev/null 2>&1 && echo OK),$2,$3) +NULL := +SPACE := $(NULL) # +TARGET_PREFIX := $(patsubst %/,%:$(SPACE),$(TARGET_DIR)) + +quiet-@ = $(if $(V),,@$(if $1,printf "%s\n" "$(TARGET_PREFIX)$1" && )) +quiet-command = $(call quiet-@,$2 $@)$1 VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.sh %.rc Kconfig% %.json.in set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1))) @@ -19,35 +22,46 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d %.o: %.c $(call quiet-command,$(CC) $(EXTRA_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) \ - -c -o $@ $<,"CC","$(TARGET_DIR)$@") + -c -o $@ $<,Compiling) %.o: %.S $(call quiet-command,$(CCAS) $(EXTRA_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) \ - -c -o $@ $<,"CCAS","$(TARGET_DIR)$@") + -c -o $@ $<,Assembling) -.PHONY : all clean build-all +.PHONY : all clean build-all distclean OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \ virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o dasd-ipl.o -EXTRA_CFLAGS := $(EXTRA_CFLAGS) -Wall -EXTRA_CFLAGS += $(call cc-option,-Werror $(EXTRA_CFLAGS),-Wno-stringop-overflow) +EXTRA_CFLAGS += -Wall EXTRA_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables -EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS), -fno-stack-protector) -EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS), -Wno-array-bounds) EXTRA_CFLAGS += -msoft-float -EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS),-march=z900,-march=z10) EXTRA_CFLAGS += -std=gnu99 LDFLAGS += -Wl,-pie -nostdlib +cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>/dev/null +cc-option = if $(call cc-test, $1); then \ + echo "$(TARGET_PREFIX)$1 detected" && echo "EXTRA_CFLAGS += $1" >&3; else \ + echo "$(TARGET_PREFIX)$1 not detected" $(if $2,&& echo "EXTRA_CFLAGS += $2" >&3); fi + +config-cc.mak: Makefile + $(quiet-@)($(call cc-option,-Wno-stringop-overflow); \ + $(call cc-option,-fno-stack-protector); \ + $(call cc-option,-Wno-array-bounds); \ + $(call cc-option,-Wno-gnu); \ + $(call cc-option,-march=z900,-march=z10)) 3> config-cc.mak +-include config-cc.mak + +LDFLAGS += -Wl,-pie -nostdlib + build-all: s390-ccw.img s390-netboot.img s390-ccw.elf: $(OBJECTS) - $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),Linking) s390-ccw.img: s390-ccw.elf - $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") + $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,Stripping $< into) $(OBJECTS): Makefile @@ -63,3 +77,6 @@ ALL_OBJS = $(sort $(OBJECTS) $(NETOBJS) $(LIBCOBJS) $(LIBNETOBJS)) clean: rm -f *.o *.d *.img *.elf *~ *.a + +distclean: + rm -f config-cc.mak diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index 7639da194c..046aa35587 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -11,55 +11,52 @@ NETLDFLAGS := $(LDFLAGS) -Wl,-Ttext=0x7800000 $(NETOBJS): EXTRA_CFLAGS += $(LIBC_INC) $(LIBNET_INC) s390-netboot.elf: $(NETOBJS) libnet.a libc.a - $(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $^,"BUILD","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $^,Linking) s390-netboot.img: s390-netboot.elf - $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") - -# SLOF is GCC-only, so ignore warnings about GNU extensions with Clang here -NO_GNU_WARN := $(call cc-option,-Werror $(QEMU_CFLAGS),-Wno-gnu) + $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,Stripping $< into) # libc files: -LIBC_CFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(NO_GNU_WARN) $(LIBC_INC) $(LIBNET_INC) \ +LIBC_CFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \ -MMD -MP -MT $@ -MF $(@:%.o=%.d) CTYPE_OBJS = isdigit.o isxdigit.o toupper.o %.o : $(SLOF_DIR)/lib/libc/ctype/%.c - $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling) STRING_OBJS = strcat.o strchr.o strrchr.o strcpy.o strlen.o strncpy.o \ strcmp.o strncmp.o strcasecmp.o strncasecmp.o strstr.o \ memset.o memcpy.o memmove.o memcmp.o %.o : $(SLOF_DIR)/lib/libc/string/%.c - $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling) STDLIB_OBJS = atoi.o atol.o strtoul.o strtol.o rand.o malloc.o free.o %.o : $(SLOF_DIR)/lib/libc/stdlib/%.c - $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling) STDIO_OBJS = sprintf.o snprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \ printf.o putc.o puts.o putchar.o stdchnls.o fileno.o %.o : $(SLOF_DIR)/lib/libc/stdio/%.c - $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling) sbrk.o: $(SLOF_DIR)/slof/sbrk.c - $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling) LIBCOBJS := $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) sbrk.o libc.a: $(LIBCOBJS) - $(call quiet-command,$(AR) -rc $@ $^,"AR","$(TARGET_DIR)$@") + $(call quiet-command,$(AR) -rc $@ $^,Creating static library) # libnet files: LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \ dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o -LIBNETCFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(NO_GNU_WARN) $(LIBC_INC) $(LIBNET_INC) \ +LIBNETCFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \ -DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d) %.o : $(SLOF_DIR)/lib/libnet/%.c - $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,Compiling) libnet.a: $(LIBNETOBJS) - $(call quiet-command,$(AR) -rc $@ $^,"AR","$(TARGET_DIR)$@") + $(call quiet-command,$(AR) -rc $@ $^,Creating static library) diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c index 8271c47296..794f99b42c 100644 --- a/pc-bios/s390-ccw/virtio-blkdev.c +++ b/pc-bios/s390-ccw/virtio-blkdev.c @@ -173,7 +173,7 @@ int virtio_get_block_size(void) switch (vdev->senseid.cu_model) { case VIRTIO_ID_BLOCK: - return vdev->config.blk.blk_size << vdev->config.blk.physical_block_exp; + return vdev->config.blk.blk_size; case VIRTIO_ID_SCSI: return vdev->scsi_block_size; } diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c index 3b7069270c..dcce696a33 100644 --- a/pc-bios/s390-ccw/virtio-scsi.c +++ b/pc-bios/s390-ccw/virtio-scsi.c @@ -195,7 +195,7 @@ static bool scsi_read_capacity(VDev *vdev, /* virtio-scsi routines */ /* - * Tries to locate a SCSI device and and adds the information for the found + * Tries to locate a SCSI device and adds the information for the found * device to the vdev->scsi_device structure. * Returns 0 if SCSI device could be located, or a error code < 0 otherwise */ diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index cbbe23e910..ef9b81d628 100644 Binary files a/pc-bios/slof.bin and b/pc-bios/slof.bin differ diff --git a/pc-bios/vof/Makefile b/pc-bios/vof/Makefile index 8809c82768..d1eb6ced7e 100644 --- a/pc-bios/vof/Makefile +++ b/pc-bios/vof/Makefile @@ -2,21 +2,30 @@ include config.mak VPATH=$(SRC_DIR) all: vof.bin +NULL := +SPACE := $(NULL) # +TARGET_PREFIX := $(patsubst %/,%:$(SPACE),$(TARGET_DIR)) + +quiet-@ = $(if $(V),,@$(if $1,,printf "%s\n" "$(TARGET_PREFIX)$1" && )) +quiet-command = $(call quiet-@,$2 $@)$1 + EXTRA_CFLAGS += -mcpu=power4 %.o: %.S - $(CC) $(EXTRA_CFLAGS) -c -o $@ $< + $(call quiet-command, $(CC) $(EXTRA_CFLAGS) -c -o $@ $<,Assembling) %.o: %.c - $(CC) $(EXTRA_CFLAGS) -c -fno-stack-protector -o $@ $< + $(call quiet-command, $(CC) $(EXTRA_CFLAGS) -c -fno-stack-protector -o $@ $<,Compiling) vof.elf: entry.o main.o ci.o bootmem.o libc.o - $(LD) -nostdlib -e_start -T$(SRC_DIR)/vof.lds -EB -o $@ $^ + $(call quiet-command, $(LD) -nostdlib -e_start -T$(SRC_DIR)/vof.lds -EB -o $@ $^,Linking) %.bin: %.elf - $(OBJCOPY) -O binary -j .text -j .data -j .toc -j .got2 $^ $@ + $(call quiet-command, $(OBJCOPY) -O binary -j .text -j .data -j .toc -j .got2 $^ $@,Extracting raw object) clean: rm -f *.o vof.bin vof.elf *~ -.PHONY: all clean +distclean: clean + +.PHONY: all clean distclean diff --git a/plugins/api.c b/plugins/api.c index 7bf71b189d..2078b16edb 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -289,6 +289,8 @@ struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info, enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info); hwaddr_info.is_store = (rw & QEMU_PLUGIN_MEM_W) != 0; + assert(mmu_idx < NB_MMU_MODES); + if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx, hwaddr_info.is_store, &hwaddr_info)) { error_report("invalid use of qemu_plugin_get_hwaddr"); diff --git a/plugins/core.c b/plugins/core.c index 792262da08..ccb770a485 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -56,7 +56,7 @@ struct qemu_plugin_ctx *plugin_id_to_ctx_locked(qemu_plugin_id_t id) static void plugin_cpu_update__async(CPUState *cpu, run_on_cpu_data data) { bitmap_copy(cpu->plugin_mask, &data.host_ulong, QEMU_PLUGIN_EV_MAX); - cpu_tb_jmp_cache_clear(cpu); + tcg_flush_jmp_cache(cpu); } static void plugin_cpu_update__locked(gpointer k, gpointer v, gpointer udata) @@ -526,6 +526,26 @@ void qemu_plugin_user_exit(void) qemu_plugin_atexit_cb(); } +/* + * Helpers for *-user to ensure locks are sane across fork() events. + */ + +void qemu_plugin_user_prefork_lock(void) +{ + qemu_rec_mutex_lock(&plugin.lock); +} + +void qemu_plugin_user_postfork(bool is_child) +{ + if (is_child) { + /* should we just reset via plugin_init? */ + qemu_rec_mutex_init(&plugin.lock); + } else { + qemu_rec_mutex_unlock(&plugin.lock); + } +} + + /* * Call this function after longjmp'ing to the main loop. It's possible that the * last instruction of a TB might have used helpers, and therefore the diff --git a/plugins/meson.build b/plugins/meson.build index fa12047327..752377c66d 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -2,7 +2,7 @@ plugin_ldflags = [] # Modules need more symbols than just those in plugins/qemu-plugins.symbols if not enable_modules if targetos == 'darwin' - qemu_plugins_symbols_list = configure_file( + configure_file( input: files('qemu-plugins.symbols'), output: 'qemu-plugins-ld64.symbols', capture: true, diff --git a/python/Makefile b/python/Makefile index 3334311362..b170708398 100644 --- a/python/Makefile +++ b/python/Makefile @@ -29,7 +29,7 @@ help: @echo " Performs no environment setup of any kind." @echo "" @echo "make develop:" - @echo " Install deps needed for for 'make check'," + @echo " Install deps needed for 'make check'," @echo " and install the qemu package in editable mode." @echo " (Can be used in or outside of a venv.)" @echo "" diff --git a/python/qemu/utils/__init__.py b/python/qemu/utils/__init__.py index 9fb273b13d..017cfdcda7 100644 --- a/python/qemu/utils/__init__.py +++ b/python/qemu/utils/__init__.py @@ -79,7 +79,7 @@ def add_visual_margin( :param content: The text to wrap and decorate. :param width: The number of columns to use, including for the decoration - itself. The default (None) uses the the available width of the + itself. The default (None) uses the available width of the current terminal, or a fallback of 72 lines. A negative number subtracts a fixed-width from the default size. The default obeys the COLUMNS environment variable, if set. diff --git a/qapi/audio.json b/qapi/audio.json index 8099e3d7f1..1e0a24bdfc 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -106,6 +106,28 @@ '*out': 'AudiodevAlsaPerDirectionOptions', '*threshold': 'uint32' } } +## +# @AudiodevSndioOptions: +# +# Options of the sndio audio backend. +# +# @in: options of the capture stream +# +# @out: options of the playback stream +# +# @dev: the name of the sndio device to use (default 'default') +# +# @latency: play buffer size (in microseconds) +# +# Since: 7.2 +## +{ 'struct': 'AudiodevSndioOptions', + 'data': { + '*in': 'AudiodevPerDirectionOptions', + '*out': 'AudiodevPerDirectionOptions', + '*dev': 'str', + '*latency': 'uint32'} } + ## # @AudiodevCoreaudioPerDirectionOptions: # @@ -387,7 +409,7 @@ ## { 'enum': 'AudiodevDriver', 'data': [ 'none', 'alsa', 'coreaudio', 'dbus', 'dsound', 'jack', 'oss', 'pa', - 'sdl', 'spice', 'wav' ] } + 'sdl', 'sndio', 'spice', 'wav' ] } ## # @Audiodev: @@ -418,5 +440,6 @@ 'oss': 'AudiodevOssOptions', 'pa': 'AudiodevPaOptions', 'sdl': 'AudiodevSdlOptions', + 'sndio': 'AudiodevSndioOptions', 'spice': 'AudiodevGenericOptions', 'wav': 'AudiodevWavOptions' } } diff --git a/qapi/block-core.json b/qapi/block-core.json index 2173e7734a..882b266532 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -5252,7 +5252,7 @@ # # <- { "event": "BLOCK_JOB_READY", # "data": { "device": "drive0", "type": "mirror", "speed": 0, -# "len": 2097152, "offset": 2097152 } +# "len": 2097152, "offset": 2097152 }, # "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } # ## diff --git a/qapi/dump.json b/qapi/dump.json index 90859c5483..6fc215dd47 100644 --- a/qapi/dump.json +++ b/qapi/dump.json @@ -195,7 +195,7 @@ # # -> { "execute": "query-dump-guest-memory-capability" } # <- { "return": { "formats": -# ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] } +# ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] } } # ## { 'command': 'query-dump-guest-memory-capability', diff --git a/qapi/machine.json b/qapi/machine.json index 6afd1936b0..abb2f48808 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -958,9 +958,9 @@ # # -> { "execute": "query-hotpluggable-cpus" } # <- {"return": [ -# { "props": { "core": 8 }, "type": "POWER8-spapr-cpu-core", +# { "props": { "core-id": 8 }, "type": "POWER8-spapr-cpu-core", # "vcpus-count": 1 }, -# { "props": { "core": 0 }, "type": "POWER8-spapr-cpu-core", +# { "props": { "core-id": 0 }, "type": "POWER8-spapr-cpu-core", # "vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"} # ]}' # @@ -1074,7 +1074,7 @@ # # -> { "execute": "query-balloon" } # <- { "return": { -# "actual": 1073741824, +# "actual": 1073741824 # } # } # @@ -1416,7 +1416,7 @@ # # Example: # -# <- { "event": "MEM_UNPLUG_ERROR" +# <- { "event": "MEM_UNPLUG_ERROR", # "data": { "device": "dimm1", # "msg": "acpi: device unplug for unsupported device" # }, diff --git a/qapi/meson.build b/qapi/meson.build index fd5c93d643..9a36c15c04 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -49,6 +49,7 @@ qapi_all_modules = [ 'stats', 'trace', 'transaction', + 'virtio', 'yank', ] if have_system @@ -68,21 +69,6 @@ if have_system or have_tools ] endif -qapi_storage_daemon_modules = [ - 'block-core', - 'block-export', - 'char', - 'common', - 'control', - 'crypto', - 'introspect', - 'job', - 'qom', - 'sockets', - 'pragma', - 'transaction', -] - qapi_nonmodule_outputs = [ 'qapi-introspect.c', 'qapi-introspect.h', 'qapi-types.c', 'qapi-types.h', diff --git a/qapi/migration.json b/qapi/migration.json index 81185d4311..88ecf86ac8 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1995,16 +1995,23 @@ # } # <- { "return": { } } # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1432121972, "microseconds": 744001}, # "data": {"status": "created", "id": "snapsave0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1432122172, "microseconds": 744001}, # "data": {"status": "running", "id": "snapsave0"}} -# <- {"event": "STOP"} -# <- {"event": "RESUME"} +# <- {"event": "STOP", +# "timestamp": {"seconds": 1432122372, "microseconds": 744001} } +# <- {"event": "RESUME", +# "timestamp": {"seconds": 1432122572, "microseconds": 744001} } # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1432122772, "microseconds": 744001}, # "data": {"status": "waiting", "id": "snapsave0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1432122972, "microseconds": 744001}, # "data": {"status": "pending", "id": "snapsave0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1432123172, "microseconds": 744001}, # "data": {"status": "concluded", "id": "snapsave0"}} # -> {"execute": "query-jobs"} # <- {"return": [{"current-progress": 1, @@ -2056,16 +2063,23 @@ # } # <- { "return": { } } # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1472124172, "microseconds": 744001}, # "data": {"status": "created", "id": "snapload0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1472125172, "microseconds": 744001}, # "data": {"status": "running", "id": "snapload0"}} -# <- {"event": "STOP"} -# <- {"event": "RESUME"} +# <- {"event": "STOP", +# "timestamp": {"seconds": 1472125472, "microseconds": 744001} } +# <- {"event": "RESUME", +# "timestamp": {"seconds": 1472125872, "microseconds": 744001} } # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1472126172, "microseconds": 744001}, # "data": {"status": "waiting", "id": "snapload0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1472127172, "microseconds": 744001}, # "data": {"status": "pending", "id": "snapload0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1472128172, "microseconds": 744001}, # "data": {"status": "concluded", "id": "snapload0"}} # -> {"execute": "query-jobs"} # <- {"return": [{"current-progress": 1, @@ -2108,14 +2122,19 @@ # } # <- { "return": { } } # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1442124172, "microseconds": 744001}, # "data": {"status": "created", "id": "snapdelete0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1442125172, "microseconds": 744001}, # "data": {"status": "running", "id": "snapdelete0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1442126172, "microseconds": 744001}, # "data": {"status": "waiting", "id": "snapdelete0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1442127172, "microseconds": 744001}, # "data": {"status": "pending", "id": "snapdelete0"}} # <- {"event": "JOB_STATUS_CHANGE", +# "timestamp": {"seconds": 1442128172, "microseconds": 744001}, # "data": {"status": "concluded", "id": "snapdelete0"}} # -> {"execute": "query-jobs"} # <- {"return": [{"current-progress": 1, diff --git a/qapi/net.json b/qapi/net.json index 75ba2cb989..dd088c09c5 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -757,7 +757,6 @@ # "data": { "name": "vnet0", # "path": "/machine/peripheral/vnet0/virtio-backend" }, # "timestamp": { "seconds": 1368697518, "microseconds": 326866 } } -# } # ## { 'event': 'NIC_RX_FILTER_CHANGED', diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 92d7ecc52c..f000b90744 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -94,3 +94,4 @@ { 'include': 'acpi.json' } { 'include': 'pci.json' } { 'include': 'stats.json' } +{ 'include': 'virtio.json' } diff --git a/qapi/qdev.json b/qapi/qdev.json index 26cd10106b..2708fb4e99 100644 --- a/qapi/qdev.json +++ b/qapi/qdev.json @@ -150,10 +150,9 @@ # # Example: # -# <- { "event": "DEVICE_UNPLUG_GUEST_ERROR" +# <- { "event": "DEVICE_UNPLUG_GUEST_ERROR", # "data": { "device": "core1", # "path": "/machine/peripheral/core1" }, -# }, # "timestamp": { "seconds": 1615570772, "microseconds": 202844 } } # ## diff --git a/qapi/run-state.json b/qapi/run-state.json index 6e2162d7b3..9273ea6516 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -364,10 +364,13 @@ # # @shutdown: Shutdown the VM and exit, according to the shutdown action # +# @exit-failure: Shutdown the VM and exit with nonzero status +# (since 7.1) +# # Since: 6.0 ## { 'enum': 'PanicAction', - 'data': [ 'pause', 'shutdown', 'none' ] } + 'data': [ 'pause', 'shutdown', 'exit-failure', 'none' ] } ## # @watchdog-set-action: diff --git a/qapi/ui.json b/qapi/ui.json index cf58ab4283..286c5731d1 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -667,8 +667,8 @@ # { # "host":"127.0.0.1", # "service":"50401", -# "family":"ipv4" -# "websocket":false, +# "family":"ipv4", +# "websocket":false # } # ] # } diff --git a/qapi/virtio.json b/qapi/virtio.json new file mode 100644 index 0000000000..e47a8fb2e0 --- /dev/null +++ b/qapi/virtio.json @@ -0,0 +1,954 @@ +# -*- Mode: Python -*- +# vim: filetype=python +# + +## +# = Virtio devices +## + +## +# @VirtioInfo: +# +# Basic information about a given VirtIODevice +# +# @path: The VirtIODevice's canonical QOM path +# +# @name: Name of the VirtIODevice +# +# Since: 7.1 +# +## +{ 'struct': 'VirtioInfo', + 'data': { 'path': 'str', + 'name': 'str' } } + +## +# @x-query-virtio: +# +# Returns a list of all realized VirtIODevices +# +# Features: +# @unstable: This command is meant for debugging. +# +# Returns: List of gathered VirtIODevices +# +# Since: 7.1 +# +# Example: +# +# -> { "execute": "x-query-virtio" } +# <- { "return": [ +# { +# "name": "virtio-input", +# "path": "/machine/peripheral-anon/device[4]/virtio-backend" +# }, +# { +# "name": "virtio-crypto", +# "path": "/machine/peripheral/crypto0/virtio-backend" +# }, +# { +# "name": "virtio-scsi", +# "path": "/machine/peripheral-anon/device[2]/virtio-backend" +# }, +# { +# "name": "virtio-net", +# "path": "/machine/peripheral-anon/device[1]/virtio-backend" +# }, +# { +# "name": "virtio-serial", +# "path": "/machine/peripheral-anon/device[0]/virtio-backend" +# } +# ] +# } +# +## + +{ 'command': 'x-query-virtio', + 'returns': [ 'VirtioInfo' ], + 'features': [ 'unstable' ] } + +## +# @VhostStatus: +# +# Information about a vhost device. This information will only be +# displayed if the vhost device is active. +# +# @n-mem-sections: vhost_dev n_mem_sections +# +# @n-tmp-sections: vhost_dev n_tmp_sections +# +# @nvqs: vhost_dev nvqs (number of virtqueues being used) +# +# @vq-index: vhost_dev vq_index +# +# @features: vhost_dev features +# +# @acked-features: vhost_dev acked_features +# +# @backend-features: vhost_dev backend_features +# +# @protocol-features: vhost_dev protocol_features +# +# @max-queues: vhost_dev max_queues +# +# @backend-cap: vhost_dev backend_cap +# +# @log-enabled: vhost_dev log_enabled flag +# +# @log-size: vhost_dev log_size +# +# Since: 7.1 +# +## + +{ 'struct': 'VhostStatus', + 'data': { 'n-mem-sections': 'int', + 'n-tmp-sections': 'int', + 'nvqs': 'uint32', + 'vq-index': 'int', + 'features': 'VirtioDeviceFeatures', + 'acked-features': 'VirtioDeviceFeatures', + 'backend-features': 'VirtioDeviceFeatures', + 'protocol-features': 'VhostDeviceProtocols', + 'max-queues': 'uint64', + 'backend-cap': 'uint64', + 'log-enabled': 'bool', + 'log-size': 'uint64' } } + +## +# @VirtioStatus: +# +# Full status of the virtio device with most VirtIODevice members. +# Also includes the full status of the corresponding vhost device +# if the vhost device is active. +# +# @name: VirtIODevice name +# +# @device-id: VirtIODevice ID +# +# @vhost-started: VirtIODevice vhost_started flag +# +# @guest-features: VirtIODevice guest_features +# +# @host-features: VirtIODevice host_features +# +# @backend-features: VirtIODevice backend_features +# +# @device-endian: VirtIODevice device_endian +# +# @num-vqs: VirtIODevice virtqueue count. This is the number of active +# virtqueues being used by the VirtIODevice. +# +# @status: VirtIODevice configuration status (VirtioDeviceStatus) +# +# @isr: VirtIODevice ISR +# +# @queue-sel: VirtIODevice queue_sel +# +# @vm-running: VirtIODevice vm_running flag +# +# @broken: VirtIODevice broken flag +# +# @disabled: VirtIODevice disabled flag +# +# @use-started: VirtIODevice use_started flag +# +# @started: VirtIODevice started flag +# +# @start-on-kick: VirtIODevice start_on_kick flag +# +# @disable-legacy-check: VirtIODevice disabled_legacy_check flag +# +# @bus-name: VirtIODevice bus_name +# +# @use-guest-notifier-mask: VirtIODevice use_guest_notifier_mask flag +# +# @vhost-dev: Corresponding vhost device info for a given VirtIODevice. +# Present if the given VirtIODevice has an active vhost +# device. +# +# Since: 7.1 +# +## + +{ 'struct': 'VirtioStatus', + 'data': { 'name': 'str', + 'device-id': 'uint16', + 'vhost-started': 'bool', + 'device-endian': 'str', + 'guest-features': 'VirtioDeviceFeatures', + 'host-features': 'VirtioDeviceFeatures', + 'backend-features': 'VirtioDeviceFeatures', + 'num-vqs': 'int', + 'status': 'VirtioDeviceStatus', + 'isr': 'uint8', + 'queue-sel': 'uint16', + 'vm-running': 'bool', + 'broken': 'bool', + 'disabled': 'bool', + 'use-started': 'bool', + 'started': 'bool', + 'start-on-kick': 'bool', + 'disable-legacy-check': 'bool', + 'bus-name': 'str', + 'use-guest-notifier-mask': 'bool', + '*vhost-dev': 'VhostStatus' } } + +## +# @x-query-virtio-status: +# +# Poll for a comprehensive status of a given virtio device +# +# @path: Canonical QOM path of the VirtIODevice +# +# Features: +# @unstable: This command is meant for debugging. +# +# Returns: VirtioStatus of the virtio device +# +# Since: 7.1 +# +# Examples: +# +# 1. Poll for the status of virtio-crypto (no vhost-crypto active) +# +# -> { "execute": "x-query-virtio-status", +# "arguments": { "path": "/machine/peripheral/crypto0/virtio-backend" } +# } +# <- { "return": { +# "device-endian": "little", +# "bus-name": "", +# "disable-legacy-check": false, +# "name": "virtio-crypto", +# "started": true, +# "device-id": 20, +# "backend-features": { +# "transports": [], +# "dev-features": [] +# }, +# "start-on-kick": false, +# "isr": 1, +# "broken": false, +# "status": { +# "statuses": [ +# "VIRTIO_CONFIG_S_ACKNOWLEDGE: Valid virtio device found", +# "VIRTIO_CONFIG_S_DRIVER: Guest OS compatible with device", +# "VIRTIO_CONFIG_S_FEATURES_OK: Feature negotiation complete", +# "VIRTIO_CONFIG_S_DRIVER_OK: Driver setup and ready" +# ] +# }, +# "num-vqs": 2, +# "guest-features": { +# "dev-features": [], +# "transports": [ +# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled", +# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported", +# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)" +# ] +# }, +# "host-features": { +# "unknown-dev-features": 1073741824, +# "dev-features": [], +# "transports": [ +# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled", +# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported", +# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)", +# "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts", +# "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. descs. on VQ" +# ] +# }, +# "use-guest-notifier-mask": true, +# "vm-running": true, +# "queue-sel": 1, +# "disabled": false, +# "vhost-started": false, +# "use-started": true +# } +# } +# +# 2. Poll for the status of virtio-net (vhost-net is active) +# +# -> { "execute": "x-query-virtio-status", +# "arguments": { "path": "/machine/peripheral-anon/device[1]/virtio-backend" } +# } +# <- { "return": { +# "device-endian": "little", +# "bus-name": "", +# "disabled-legacy-check": false, +# "name": "virtio-net", +# "started": true, +# "device-id": 1, +# "vhost-dev": { +# "n-tmp-sections": 4, +# "n-mem-sections": 4, +# "max-queues": 1, +# "backend-cap": 2, +# "log-size": 0, +# "backend-features": { +# "dev-features": [], +# "transports": [] +# }, +# "nvqs": 2, +# "protocol-features": { +# "protocols": [] +# }, +# "vq-index": 0, +# "log-enabled": false, +# "acked-features": { +# "dev-features": [ +# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers" +# ], +# "transports": [ +# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled", +# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported", +# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)" +# ] +# }, +# "features": { +# "dev-features": [ +# "VHOST_F_LOG_ALL: Logging write descriptors supported", +# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers" +# ], +# "transports": [ +# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled", +# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported", +# "VIRTIO_F_IOMMU_PLATFORM: Device can be used on IOMMU platform", +# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)", +# "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts", +# "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. descs. on VQ" +# ] +# } +# }, +# "backend-features": { +# "dev-features": [ +# "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features negotation supported", +# "VIRTIO_NET_F_GSO: Handling GSO-type packets supported", +# "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control channel", +# "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets supported", +# "VIRTIO_NET_F_CTRL_RX_EXTRA: Extra RX mode control supported", +# "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported", +# "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported", +# "VIRTIO_NET_F_CTRL_VQ: Control channel available", +# "VIRTIO_NET_F_STATUS: Configuration status field available", +# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers", +# "VIRTIO_NET_F_HOST_UFO: Device can receive UFO", +# "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN", +# "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6", +# "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4", +# "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO", +# "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN", +# "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6", +# "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4", +# "VIRTIO_NET_F_MAC: Device has given MAC address", +# "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading reconfig. supported", +# "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial checksum supported", +# "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum supported" +# ], +# "transports": [ +# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled", +# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported", +# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)", +# "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts", +# "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. descs. on VQ" +# ] +# }, +# "start-on-kick": false, +# "isr": 1, +# "broken": false, +# "status": { +# "statuses": [ +# "VIRTIO_CONFIG_S_ACKNOWLEDGE: Valid virtio device found", +# "VIRTIO_CONFIG_S_DRIVER: Guest OS compatible with device", +# "VIRTIO_CONFIG_S_FEATURES_OK: Feature negotiation complete", +# "VIRTIO_CONFIG_S_DRIVER_OK: Driver setup and ready" +# ] +# }, +# "num-vqs": 3, +# "guest-features": { +# "dev-features": [ +# "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control channel", +# "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets supported", +# "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported", +# "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported", +# "VIRTIO_NET_F_CTRL_VQ: Control channel available", +# "VIRTIO_NET_F_STATUS: Configuration status field available", +# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers", +# "VIRTIO_NET_F_HOST_UFO: Device can receive UFO", +# "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN", +# "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6", +# "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4", +# "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO", +# "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN", +# "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6", +# "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4", +# "VIRTIO_NET_F_MAC: Device has given MAC address", +# "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading reconfig. supported", +# "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial checksum supported", +# "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum supported" +# ], +# "transports": [ +# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled", +# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported", +# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)" +# ] +# }, +# "host-features": { +# "dev-features": [ +# "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features negotation supported", +# "VIRTIO_NET_F_GSO: Handling GSO-type packets supported", +# "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control channel", +# "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets supported", +# "VIRTIO_NET_F_CTRL_RX_EXTRA: Extra RX mode control supported", +# "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported", +# "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported", +# "VIRTIO_NET_F_CTRL_VQ: Control channel available", +# "VIRTIO_NET_F_STATUS: Configuration status field available", +# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers", +# "VIRTIO_NET_F_HOST_UFO: Device can receive UFO", +# "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN", +# "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6", +# "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4", +# "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO", +# "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN", +# "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6", +# "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4", +# "VIRTIO_NET_F_MAC: Device has given MAC address", +# "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading reconfig. supported", +# "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial checksum supported", +# "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum supported" +# ], +# "transports": [ +# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled", +# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported", +# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)", +# "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts", +# "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. descs. on VQ" +# ] +# }, +# "use-guest-notifier-mask": true, +# "vm-running": true, +# "queue-sel": 2, +# "disabled": false, +# "vhost-started": true, +# "use-started": true +# } +# } +# +## + +{ 'command': 'x-query-virtio-status', + 'data': { 'path': 'str' }, + 'returns': 'VirtioStatus', + 'features': [ 'unstable' ] } + +## +# @VirtioDeviceStatus: +# +# A structure defined to list the configuration statuses of a virtio +# device +# +# @statuses: List of decoded configuration statuses of the virtio +# device +# +# @unknown-statuses: Virtio device statuses bitmap that have not been decoded +# +# Since: 7.1 +## + +{ 'struct': 'VirtioDeviceStatus', + 'data': { 'statuses': [ 'str' ], + '*unknown-statuses': 'uint8' } } + +## +# @VhostDeviceProtocols: +# +# A structure defined to list the vhost user protocol features of a +# Vhost User device +# +# @protocols: List of decoded vhost user protocol features of a vhost +# user device +# +# @unknown-protocols: Vhost user device protocol features bitmap that +# have not been decoded +# +# Since: 7.1 +## + +{ 'struct': 'VhostDeviceProtocols', + 'data': { 'protocols': [ 'str' ], + '*unknown-protocols': 'uint64' } } + +## +# @VirtioDeviceFeatures: +# +# The common fields that apply to most Virtio devices. Some devices +# may not have their own device-specific features (e.g. virtio-rng). +# +# @transports: List of transport features of the virtio device +# +# @dev-features: List of device-specific features (if the device has +# unique features) +# +# @unknown-dev-features: Virtio device features bitmap that have not +# been decoded +# +# Since: 7.1 +## + +{ 'struct': 'VirtioDeviceFeatures', + 'data': { 'transports': [ 'str' ], + '*dev-features': [ 'str' ], + '*unknown-dev-features': 'uint64' } } + +## +# @VirtQueueStatus: +# +# Information of a VirtIODevice VirtQueue, including most members of +# the VirtQueue data structure. +# +# @name: Name of the VirtIODevice that uses this VirtQueue +# +# @queue-index: VirtQueue queue_index +# +# @inuse: VirtQueue inuse +# +# @vring-num: VirtQueue vring.num +# +# @vring-num-default: VirtQueue vring.num_default +# +# @vring-align: VirtQueue vring.align +# +# @vring-desc: VirtQueue vring.desc (descriptor area) +# +# @vring-avail: VirtQueue vring.avail (driver area) +# +# @vring-used: VirtQueue vring.used (device area) +# +# @last-avail-idx: VirtQueue last_avail_idx or return of vhost_dev +# vhost_get_vring_base (if vhost active) +# +# @shadow-avail-idx: VirtQueue shadow_avail_idx +# +# @used-idx: VirtQueue used_idx +# +# @signalled-used: VirtQueue signalled_used +# +# @signalled-used-valid: VirtQueue signalled_used_valid flag +# +# Since: 7.1 +# +## + +{ 'struct': 'VirtQueueStatus', + 'data': { 'name': 'str', + 'queue-index': 'uint16', + 'inuse': 'uint32', + 'vring-num': 'uint32', + 'vring-num-default': 'uint32', + 'vring-align': 'uint32', + 'vring-desc': 'uint64', + 'vring-avail': 'uint64', + 'vring-used': 'uint64', + '*last-avail-idx': 'uint16', + '*shadow-avail-idx': 'uint16', + 'used-idx': 'uint16', + 'signalled-used': 'uint16', + 'signalled-used-valid': 'bool' } } + +## +# @x-query-virtio-queue-status: +# +# Return the status of a given VirtIODevice's VirtQueue +# +# @path: VirtIODevice canonical QOM path +# +# @queue: VirtQueue index to examine +# +# Features: +# @unstable: This command is meant for debugging. +# +# Returns: VirtQueueStatus of the VirtQueue +# +# Notes: last_avail_idx will not be displayed in the case where +# the selected VirtIODevice has a running vhost device and +# the VirtIODevice VirtQueue index (queue) does not exist for +# the corresponding vhost device vhost_virtqueue. Also, +# shadow_avail_idx will not be displayed in the case where +# the selected VirtIODevice has a running vhost device. +# +# Since: 7.1 +# +# Examples: +# +# 1. Get VirtQueueStatus for virtio-vsock (vhost-vsock running) +# +# -> { "execute": "x-query-virtio-queue-status", +# "arguments": { "path": "/machine/peripheral/vsock0/virtio-backend", +# "queue": 1 } +# } +# <- { "return": { +# "signalled-used": 0, +# "inuse": 0, +# "name": "vhost-vsock", +# "vring-align": 4096, +# "vring-desc": 5217370112, +# "signalled-used-valid": false, +# "vring-num-default": 128, +# "vring-avail": 5217372160, +# "queue-index": 1, +# "last-avail-idx": 0, +# "vring-used": 5217372480, +# "used-idx": 0, +# "vring-num": 128 +# } +# } +# +# 2. Get VirtQueueStatus for virtio-serial (no vhost) +# +# -> { "execute": "x-query-virtio-queue-status", +# "arguments": { "path": "/machine/peripheral-anon/device[0]/virtio-backend", +# "queue": 20 } +# } +# <- { "return": { +# "signalled-used": 0, +# "inuse": 0, +# "name": "virtio-serial", +# "vring-align": 4096, +# "vring-desc": 5182074880, +# "signalled-used-valid": false, +# "vring-num-default": 128, +# "vring-avail": 5182076928, +# "queue-index": 20, +# "last-avail-idx": 0, +# "vring-used": 5182077248, +# "used-idx": 0, +# "shadow-avail-idx": 0, +# "vring-num": 128 +# } +# } +# +## + +{ 'command': 'x-query-virtio-queue-status', + 'data': { 'path': 'str', 'queue': 'uint16' }, + 'returns': 'VirtQueueStatus', + 'features': [ 'unstable' ] } + +## +# @VirtVhostQueueStatus: +# +# Information of a vhost device's vhost_virtqueue, including most +# members of the vhost_dev vhost_virtqueue data structure. +# +# @name: Name of the VirtIODevice that uses this vhost_virtqueue +# +# @kick: vhost_virtqueue kick +# +# @call: vhost_virtqueue call +# +# @desc: vhost_virtqueue desc +# +# @avail: vhost_virtqueue avail +# +# @used: vhost_virtqueue used +# +# @num: vhost_virtqueue num +# +# @desc-phys: vhost_virtqueue desc_phys (descriptor area phys. addr.) +# +# @desc-size: vhost_virtqueue desc_size +# +# @avail-phys: vhost_virtqueue avail_phys (driver area phys. addr.) +# +# @avail-size: vhost_virtqueue avail_size +# +# @used-phys: vhost_virtqueue used_phys (device area phys. addr.) +# +# @used-size: vhost_virtqueue used_size +# +# Since: 7.1 +# +## + +{ 'struct': 'VirtVhostQueueStatus', + 'data': { 'name': 'str', + 'kick': 'int', + 'call': 'int', + 'desc': 'uint64', + 'avail': 'uint64', + 'used': 'uint64', + 'num': 'int', + 'desc-phys': 'uint64', + 'desc-size': 'uint32', + 'avail-phys': 'uint64', + 'avail-size': 'uint32', + 'used-phys': 'uint64', + 'used-size': 'uint32' } } + +## +# @x-query-virtio-vhost-queue-status: +# +# Return information of a given vhost device's vhost_virtqueue +# +# @path: VirtIODevice canonical QOM path +# +# @queue: vhost_virtqueue index to examine +# +# Features: +# @unstable: This command is meant for debugging. +# +# Returns: VirtVhostQueueStatus of the vhost_virtqueue +# +# Since: 7.1 +# +# Examples: +# +# 1. Get vhost_virtqueue status for vhost-crypto +# +# -> { "execute": "x-query-virtio-vhost-queue-status", +# "arguments": { "path": "/machine/peripheral/crypto0/virtio-backend", +# "queue": 0 } +# } +# <- { "return": { +# "avail-phys": 5216124928, +# "name": "virtio-crypto", +# "used-phys": 5216127040, +# "avail-size": 2054, +# "desc-size": 16384, +# "used-size": 8198, +# "desc": 140141447430144, +# "num": 1024, +# "call": 0, +# "avail": 140141447446528, +# "desc-phys": 5216108544, +# "used": 140141447448640, +# "kick": 0 +# } +# } +# +# 2. Get vhost_virtqueue status for vhost-vsock +# +# -> { "execute": "x-query-virtio-vhost-queue-status", +# "arguments": { "path": "/machine/peripheral/vsock0/virtio-backend", +# "queue": 0 } +# } +# <- { "return": { +# "avail-phys": 5182261248, +# "name": "vhost-vsock", +# "used-phys": 5182261568, +# "avail-size": 262, +# "desc-size": 2048, +# "used-size": 1030, +# "desc": 140141413580800, +# "num": 128, +# "call": 0, +# "avail": 140141413582848, +# "desc-phys": 5182259200, +# "used": 140141413583168, +# "kick": 0 +# } +# } +# +## + +{ 'command': 'x-query-virtio-vhost-queue-status', + 'data': { 'path': 'str', 'queue': 'uint16' }, + 'returns': 'VirtVhostQueueStatus', + 'features': [ 'unstable' ] } + +## +# @VirtioRingDesc: +# +# Information regarding the vring descriptor area +# +# @addr: Guest physical address of the descriptor area +# +# @len: Length of the descriptor area +# +# @flags: List of descriptor flags +# +# Since: 7.1 +# +## + +{ 'struct': 'VirtioRingDesc', + 'data': { 'addr': 'uint64', + 'len': 'uint32', + 'flags': [ 'str' ] } } + +## +# @VirtioRingAvail: +# +# Information regarding the avail vring (a.k.a. driver area) +# +# @flags: VRingAvail flags +# +# @idx: VRingAvail index +# +# @ring: VRingAvail ring[] entry at provided index +# +# Since: 7.1 +# +## + +{ 'struct': 'VirtioRingAvail', + 'data': { 'flags': 'uint16', + 'idx': 'uint16', + 'ring': 'uint16' } } + +## +# @VirtioRingUsed: +# +# Information regarding the used vring (a.k.a. device area) +# +# @flags: VRingUsed flags +# +# @idx: VRingUsed index +# +# Since: 7.1 +# +## + +{ 'struct': 'VirtioRingUsed', + 'data': { 'flags': 'uint16', + 'idx': 'uint16' } } + +## +# @VirtioQueueElement: +# +# Information regarding a VirtQueue's VirtQueueElement including +# descriptor, driver, and device areas +# +# @name: Name of the VirtIODevice that uses this VirtQueue +# +# @index: Index of the element in the queue +# +# @descs: List of descriptors (VirtioRingDesc) +# +# @avail: VRingAvail info +# +# @used: VRingUsed info +# +# Since: 7.1 +# +## + +{ 'struct': 'VirtioQueueElement', + 'data': { 'name': 'str', + 'index': 'uint32', + 'descs': [ 'VirtioRingDesc' ], + 'avail': 'VirtioRingAvail', + 'used': 'VirtioRingUsed' } } + +## +# @x-query-virtio-queue-element: +# +# Return the information about a VirtQueue's VirtQueueElement +# +# @path: VirtIODevice canonical QOM path +# +# @queue: VirtQueue index to examine +# +# @index: Index of the element in the queue +# (default: head of the queue) +# +# Features: +# @unstable: This command is meant for debugging. +# +# Returns: VirtioQueueElement information +# +# Since: 7.1 +# +# Examples: +# +# 1. Introspect on virtio-net's VirtQueue 0 at index 5 +# +# -> { "execute": "x-query-virtio-queue-element", +# "arguments": { "path": "/machine/peripheral-anon/device[1]/virtio-backend", +# "queue": 0, +# "index": 5 } +# } +# <- { "return": { +# "index": 5, +# "name": "virtio-net", +# "descs": [ +# { +# "flags": ["write"], +# "len": 1536, +# "addr": 5257305600 +# } +# ], +# "avail": { +# "idx": 256, +# "flags": 0, +# "ring": 5 +# }, +# "used": { +# "idx": 13, +# "flags": 0 +# } +# } +# } +# +# 2. Introspect on virtio-crypto's VirtQueue 1 at head +# +# -> { "execute": "x-query-virtio-queue-element", +# "arguments": { "path": "/machine/peripheral/crypto0/virtio-backend", +# "queue": 1 } +# } +# <- { "return": { +# "index": 0, +# "name": "virtio-crypto", +# "descs": [ +# { +# "flags": [], +# "len": 0, +# "addr": 8080268923184214134 +# } +# ], +# "avail": { +# "idx": 280, +# "flags": 0, +# "ring": 0 +# }, +# "used": { +# "idx": 280, +# "flags": 0 +# } +# } +# } +# +# 3. Introspect on virtio-scsi's VirtQueue 2 at head +# +# -> { "execute": "x-query-virtio-queue-element", +# "arguments": { "path": "/machine/peripheral-anon/device[2]/virtio-backend", +# "queue": 2 } +# } +# <- { "return": { +# "index": 19, +# "name": "virtio-scsi", +# "descs": [ +# { +# "flags": ["used", "indirect", "write"], +# "len": 4099327944, +# "addr": 12055409292258155293 +# } +# ], +# "avail": { +# "idx": 1147, +# "flags": 0, +# "ring": 19 +# }, +# "used": { +# "idx": 280, +# "flags": 0 +# } +# } +# } +# +## + +{ 'command': 'x-query-virtio-queue-element', + 'data': { 'path': 'str', 'queue': 'uint16', '*index': 'uint16' }, + 'returns': 'VirtioQueueElement', + 'features': [ 'unstable' ] } diff --git a/qemu-img.c b/qemu-img.c index 7d4b33b3da..ace3adf8ae 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -164,8 +164,8 @@ void help(void) " 'output_filename' is the destination disk image filename\n" " 'output_fmt' is the destination format\n" " 'options' is a comma separated list of format specific options in a\n" - " name=value format. Use -o ? for an overview of the options supported by the\n" - " used format\n" + " name=value format. Use -o help for an overview of the options supported by\n" + " the used format\n" " 'snapshot_param' is param used for internal snapshot, format\n" " is 'snapshot.id=[ID],snapshot.name=[NAME]', or\n" " '[ID_OR_NAME]'\n" @@ -911,10 +911,11 @@ static void run_block_job(BlockJob *job, Error **errp) AioContext *aio_context = block_job_get_aio_context(job); int ret = 0; - aio_context_acquire(aio_context); - job_ref(&job->job); + job_lock(); + job_ref_locked(&job->job); do { float progress = 0.0f; + job_unlock(); aio_poll(aio_context, true); progress_get_snapshot(&job->job.progress, &progress_current, @@ -923,15 +924,17 @@ static void run_block_job(BlockJob *job, Error **errp) progress = (float)progress_current / progress_total * 100.f; } qemu_progress_print(progress, 0); - } while (!job_is_ready(&job->job) && !job_is_completed(&job->job)); + job_lock(); + } while (!job_is_ready_locked(&job->job) && + !job_is_completed_locked(&job->job)); - if (!job_is_completed(&job->job)) { - ret = job_complete_sync(&job->job, errp); + if (!job_is_completed_locked(&job->job)) { + ret = job_complete_sync_locked(&job->job, errp); } else { ret = job->job.ret; } - job_unref(&job->job); - aio_context_release(aio_context); + job_unref_locked(&job->job); + job_unlock(); /* publish completion progress only when success */ if (!ret) { diff --git a/qemu-options.hx b/qemu-options.hx index 79e00916a1..c0bb74655c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -37,7 +37,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ " memory-encryption=@var{} memory encryption object to use (default=none)\n" " hmat=on|off controls ACPI HMAT support (default=off)\n" " memory-backend='backend-id' specifies explicitly provided backend for main RAM (default=none)\n" - " cxl-fmw.0.targets.0=firsttarget,cxl-fmw.0.targets.1=secondtarget,cxl-fmw.0.size=size[,cxl-fmw.0.interleave-granularity=granularity]\n", + " cxl-fmw.0.targets.0=firsttarget,cxl-fmw.0.targets.1=secondtarget,cxl-fmw.0.size=size[,cxl-fmw.0.interleave-granularity=granularity]\n" + " zpcii-disable=on|off disables zPCI interpretation facilities (default=off)\n", QEMU_ARCH_ALL) SRST ``-machine [type=]name[,prop=value[,...]]`` @@ -157,6 +158,11 @@ SRST :: -machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512k + + ``zpcii-disable=on|off`` + Disables zPCI interpretation facilties on s390-ccw hosts. + This feature can be used to disable hardware virtual assists + related to zPCI devices. The default is off. ERST DEF("M", HAS_ARG, QEMU_OPTION_M, @@ -704,10 +710,11 @@ SRST ``-audio [driver=]driver,model=value[,prop[=value][,...]]`` This option is a shortcut for configuring both the guest audio hardware and the host audio backend in one go. - The host backend options are the same as with the corresponding - ``-audiodev`` options below. The guest hardware model can be set with - ``model=modelname``. Use ``model=help`` to list the available device - types. + The driver option is the same as with the corresponding ``-audiodev`` option below. + The guest hardware model can be set with ``model=modelname``. + + Use ``driver=help`` to list the available drivers, + and ``model=help`` to list the available device types. The following two example do exactly the same, to show how ``-audio`` can be used to shorten the command line length: @@ -721,6 +728,7 @@ ERST DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev, "-audiodev [driver=]driver,id=id[,prop[=value][,...]]\n" " specifies the audio backend to use\n" + " Use ``-audiodev help`` to list the available drivers\n" " id= identifier of the backend\n" " timer-period= timer period in microseconds\n" " in|out.mixing-engine= use mixing engine to mix streams inside QEMU\n" @@ -767,6 +775,9 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev, "-audiodev sdl,id=id[,prop[=value][,...]]\n" " in|out.buffer-count= number of buffers\n" #endif +#ifdef CONFIG_AUDIO_SNDIO + "-audiodev sndio,id=id[,prop[=value][,...]]\n" +#endif #ifdef CONFIG_SPICE "-audiodev spice,id=id[,prop[=value][,...]]\n" #endif @@ -933,6 +944,19 @@ SRST ``in|out.buffer-count=count`` Sets the count of the buffers. +``-audiodev sndio,id=id[,prop[=value][,...]]`` + Creates a backend using SNDIO. This backend is available on + OpenBSD and most other Unix-like systems. + + Sndio specific options are: + + ``in|out.dev=device`` + Specify the sndio device to use for input and/or output. Default + is ``default``. + + ``in|out.latency=usecs`` + Sets the desired period length in microseconds. + ``-audiodev spice,id=id[,prop[=value][,...]]`` Creates a backend that sends audio through SPICE. This backend requires ``-spice`` and automatically selected in that case, so @@ -1105,6 +1129,19 @@ DEFHEADING() DEFHEADING(Block device options:) +SRST +The QEMU block device handling options have a long history and +have gone through several iterations as the feature set and complexity +of the block layer have grown. Many online guides to QEMU often +reference older and deprecated options, which can lead to confusion. + +The recommended modern way to describe disks is to use a combination of +``-device`` to specify the hardware device and ``-blockdev`` to +describe the backend. The device defines what the guest sees and the +backend describes how QEMU handles the data. + +ERST + DEF("fda", HAS_ARG, QEMU_OPTION_fda, "-fda/-fdb file use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL) DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL) @@ -1585,13 +1622,6 @@ SRST Use file as SecureDigital card image. ERST -DEF("pflash", HAS_ARG, QEMU_OPTION_pflash, - "-pflash file use 'file' as a parallel flash image\n", QEMU_ARCH_ALL) -SRST -``-pflash file`` - Use file as a parallel flash image. -ERST - DEF("snapshot", 0, QEMU_OPTION_snapshot, "-snapshot write to temporary files instead of disk image files\n", QEMU_ARCH_ALL) @@ -2542,6 +2572,8 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, " [,asset=str][,part=str][,max-speed=%d][,current-speed=%d]\n" " [,processor-id=%d]\n" " specify SMBIOS type 4 fields\n" + "-smbios type=8[,external_reference=str][,internal_reference=str][,connector_type=%d][,port_type=%d]\n" + " specify SMBIOS type 8 fields\n" "-smbios type=11[,value=str][,path=filename]\n" " specify SMBIOS type 11 fields\n" "-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str]\n" @@ -3684,12 +3716,67 @@ DEFHEADING() #endif -DEFHEADING(Linux/Multiboot boot specific:) +DEFHEADING(Boot Image or Kernel specific:) SRST -When using these options, you can use a given Linux or Multiboot kernel -without installing it in the disk image. It can be useful for easier -testing of various kernels. +There are broadly 4 ways you can boot a system with QEMU. + - specify a firmware and let it control finding a kernel + - specify a firmware and pass a hint to the kernel to boot + - direct kernel image boot + - manually load files into the guest's address space + +The third method is useful for quickly testing kernels but as there is +no firmware to pass configuration information to the kernel the +hardware must either be probeable, the kernel built for the exact +configuration or passed some configuration data (e.g. a DTB blob) +which tells the kernel what drivers it needs. This exact details are +often hardware specific. + +The final method is the most generic way of loading images into the +guest address space and used mostly for ``bare metal`` type +development where the reset vectors of the processor are taken into +account. + +ERST + +SRST + +For x86 machines and some other architectures ``-bios`` will generally +do the right thing with whatever it is given. For other machines the +more strict ``-pflash`` option needs an image that is sized for the +flash device for the given machine type. + +Please see the :ref:`system-targets-ref` section of the manual for +more detailed documentation. + +ERST + +DEF("bios", HAS_ARG, QEMU_OPTION_bios, \ + "-bios file set the filename for the BIOS\n", QEMU_ARCH_ALL) +SRST +``-bios file`` + Set the filename for the BIOS. +ERST + +DEF("pflash", HAS_ARG, QEMU_OPTION_pflash, + "-pflash file use 'file' as a parallel flash image\n", QEMU_ARCH_ALL) +SRST +``-pflash file`` + Use file as a parallel flash image. +ERST + +SRST + +The kernel options were designed to work with Linux kernels although +other things (like hypervisors) can be packaged up as a kernel +executable image. The exact format of a executable image is usually +architecture specific. + +The way in which the kernel is started (what address it is loaded at, +what if any information is passed to it via CPU registers, the state +of the hardware when it is started, and so on) is also architecture +specific. Typically it follows the specification laid down by the +Linux kernel for how kernels for that architecture must be started. ERST @@ -3729,6 +3816,25 @@ SRST kernel on boot. ERST +SRST + +Finally you can also manually load images directly into the address +space of the guest. This is most useful for developers who already +know the layout of their guest and take care to ensure something sane +will happen when the reset vector executes. + +The generic loader can be invoked by using the loader device: + +``-device loader,addr=,data=,data-len=[,data-be=][,cpu-num=]`` + +there is also the guest loader which operates in a similar way but +tweaks the DTB so a hypervisor loaded via ``-kernel`` can find where +the guest image is: + +``-device guest-loader,addr=[,kernel=,[bootargs=]][,initrd=]`` + +ERST + DEFHEADING() DEFHEADING(Debug/Expert options:) @@ -4179,13 +4285,6 @@ SRST To list all the data directories, use ``-L help``. ERST -DEF("bios", HAS_ARG, QEMU_OPTION_bios, \ - "-bios file set the filename for the BIOS\n", QEMU_ARCH_ALL) -SRST -``-bios file`` - Set the filename for the BIOS. -ERST - DEF("enable-kvm", 0, QEMU_OPTION_enable_kvm, \ "-enable-kvm enable KVM full virtualization support\n", QEMU_ARCH_ARM | QEMU_ARCH_I386 | QEMU_ARCH_MIPS | QEMU_ARCH_PPC | @@ -4239,7 +4338,7 @@ DEF("action", HAS_ARG, QEMU_OPTION_action, " action when guest reboots [default=reset]\n" "-action shutdown=poweroff|pause\n" " action when guest shuts down [default=poweroff]\n" - "-action panic=pause|shutdown|none\n" + "-action panic=pause|shutdown|exit-failure|none\n" " action when guest panics [default=shutdown]\n" "-action watchdog=reset|shutdown|poweroff|inject-nmi|pause|debug|none\n" " action when watchdog fires [default=reset]\n", @@ -4255,7 +4354,7 @@ SRST ``-action panic=none`` ``-action reboot=shutdown,shutdown=pause`` - ``-watchdog i6300esb -action watchdog=pause`` + ``-device i6300esb -action watchdog=pause`` ERST @@ -4373,35 +4472,6 @@ SRST specifies the snapshot name used to load the initial VM state. ERST -DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \ - "-watchdog model\n" \ - " enable virtual hardware watchdog [default=none]\n", - QEMU_ARCH_ALL) -SRST -``-watchdog model`` - Create a virtual hardware watchdog device. Once enabled (by a guest - action), the watchdog must be periodically polled by an agent inside - the guest or else the guest will be restarted. Choose a model for - which your guest has drivers. - - The model is the model of hardware watchdog to emulate. Use - ``-watchdog help`` to list available hardware models. Only one - watchdog can be enabled for a guest. - - The following models may be available: - - ``ib700`` - iBASE 700 is a very simple ISA watchdog with a single timer. - - ``i6300esb`` - Intel 6300ESB I/O controller hub is a much more featureful - PCI-based dual-timer watchdog. - - ``diag288`` - A virtual watchdog for s390x backed by the diagnose 288 - hypercall (currently KVM only). -ERST - DEF("watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action, \ "-watchdog-action reset|shutdown|poweroff|inject-nmi|pause|debug|none\n" \ " action when watchdog fires [default=reset]\n", @@ -4423,7 +4493,7 @@ SRST Examples: - ``-watchdog i6300esb -watchdog-action pause``; \ ``-watchdog ib700`` + ``-device i6300esb -watchdog-action pause`` ERST @@ -4554,12 +4624,12 @@ SRST information about the facilities this enables. ERST DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, - "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \ + "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]\n" \ " semihosting configuration\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST -``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]`` +``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]`` Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). @@ -4586,6 +4656,13 @@ SRST Send the output to a chardev backend output for native or auto output when not in gdb + ``userspace=on|off`` + Allows code running in guest userspace to access the semihosting + interface. The default is that only privileged guest code can + make semihosting calls. Note that setting ``userspace=on`` should + only be used if all guest code is trusted (for example, in + bare-metal test case code). + ``arg=str1,arg=str2,...`` Allows the user to pass input arguments, and can be used multiple times to build up a list. The old-style diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 954efed01b..eea819cff0 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -3356,8 +3356,8 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) } #endif -/* add unsupported commands to the blacklist */ -GList *ga_command_blacklist_init(GList *blacklist) +/* add unsupported commands to the list of blocked RPCs */ +GList *ga_command_init_blockedrpcs(GList *blockedrpcs) { #if !defined(__linux__) { @@ -3370,13 +3370,13 @@ GList *ga_command_blacklist_init(GList *blacklist) char **p = (char **)list; while (*p) { - blacklist = g_list_append(blacklist, g_strdup(*p++)); + blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++)); } } #endif #if !defined(HAVE_GETIFADDRS) - blacklist = g_list_append(blacklist, + blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-network-get-interfaces")); #endif @@ -3390,18 +3390,18 @@ GList *ga_command_blacklist_init(GList *blacklist) char **p = (char **)list; while (*p) { - blacklist = g_list_append(blacklist, g_strdup(*p++)); + blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++)); } } #endif #if !defined(CONFIG_FSTRIM) - blacklist = g_list_append(blacklist, g_strdup("guest-fstrim")); + blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-fstrim")); #endif - blacklist = g_list_append(blacklist, g_strdup("guest-get-devices")); + blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-get-devices")); - return blacklist; + return blockedrpcs; } /* register init/cleanup routines for stateful command groups */ diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 7ed7664715..ec9f55b453 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -2005,8 +2005,8 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp) return NULL; } -/* add unsupported commands to the blacklist */ -GList *ga_command_blacklist_init(GList *blacklist) +/* add unsupported commands to the list of blocked RPCs */ +GList *ga_command_init_blockedrpcs(GList *blockedrpcs) { const char *list_unsupported[] = { "guest-suspend-hybrid", @@ -2017,7 +2017,7 @@ GList *ga_command_blacklist_init(GList *blacklist) char **p = (char **)list_unsupported; while (*p) { - blacklist = g_list_append(blacklist, g_strdup(*p++)); + blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++)); } if (!vss_init(true)) { @@ -2028,11 +2028,11 @@ GList *ga_command_blacklist_init(GList *blacklist) p = (char **)list; while (*p) { - blacklist = g_list_append(blacklist, g_strdup(*p++)); + blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++)); } } - return blacklist; + return blockedrpcs; } /* register init/cleanup routines for stateful command groups */ diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index 29cd50402f..b4e7c52c61 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -24,7 +24,7 @@ typedef struct GACommandState GACommandState; extern GAState *ga_state; extern QmpCommandList ga_commands; -GList *ga_command_blacklist_init(GList *blacklist); +GList *ga_command_init_blockedrpcs(GList *blockedrpcs); void ga_command_state_init(GAState *s, GACommandState *cs); void ga_command_state_add(GACommandState *cs, void (*init)(void), diff --git a/qga/main.c b/qga/main.c index 5f1efa2333..5a9d8252e0 100644 --- a/qga/main.c +++ b/qga/main.c @@ -87,7 +87,7 @@ struct GAState { #endif bool delimit_response; bool frozen; - GList *blacklist; + GList *blockedrpcs; char *state_filepath_isfrozen; struct { const char *log_filepath; @@ -107,7 +107,7 @@ struct GAState *ga_state; QmpCommandList ga_commands; /* commands that are safe to issue while filesystems are frozen */ -static const char *ga_freeze_whitelist[] = { +static const char *ga_freeze_allowlist[] = { "guest-ping", "guest-info", "guest-sync", @@ -260,8 +260,8 @@ QEMU_COPYRIGHT "\n" #ifdef _WIN32 " -s, --service service commands: install, uninstall, vss-install, vss-uninstall\n" #endif -" -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\"\n" -" to list available RPCs)\n" +" -b, --block-rpcs comma-separated list of RPCs to disable (no spaces,\n" +" use \"help\" to list available RPCs)\n" " -D, --dump-conf dump a qemu-ga config file based on current config\n" " options / command-line parameters to stdout\n" " -r, --retry-path attempt re-opening path if it's unavailable or closed\n" @@ -363,31 +363,31 @@ static gint ga_strcmp(gconstpointer str1, gconstpointer str2) } /* disable commands that aren't safe for fsfreeze */ -static void ga_disable_non_whitelisted(const QmpCommand *cmd, void *opaque) +static void ga_disable_not_allowed(const QmpCommand *cmd, void *opaque) { - bool whitelisted = false; + bool allowed = false; int i = 0; const char *name = qmp_command_name(cmd); - while (ga_freeze_whitelist[i] != NULL) { - if (strcmp(name, ga_freeze_whitelist[i]) == 0) { - whitelisted = true; + while (ga_freeze_allowlist[i] != NULL) { + if (strcmp(name, ga_freeze_allowlist[i]) == 0) { + allowed = true; } i++; } - if (!whitelisted) { + if (!allowed) { g_debug("disabling command: %s", name); qmp_disable_command(&ga_commands, name, "the agent is in frozen state"); } } -/* [re-]enable all commands, except those explicitly blacklisted by user */ -static void ga_enable_non_blacklisted(const QmpCommand *cmd, void *opaque) +/* [re-]enable all commands, except those explicitly blocked by user */ +static void ga_enable_non_blocked(const QmpCommand *cmd, void *opaque) { - GList *blacklist = opaque; + GList *blockedrpcs = opaque; const char *name = qmp_command_name(cmd); - if (g_list_find_custom(blacklist, name, ga_strcmp) == NULL && + if (g_list_find_custom(blockedrpcs, name, ga_strcmp) == NULL && !qmp_command_is_enabled(cmd)) { g_debug("enabling command: %s", name); qmp_enable_command(&ga_commands, name); @@ -426,8 +426,8 @@ void ga_set_frozen(GAState *s) if (ga_is_frozen(s)) { return; } - /* disable all non-whitelisted (for frozen state) commands */ - qmp_for_each_command(&ga_commands, ga_disable_non_whitelisted, NULL); + /* disable all forbidden (for frozen state) commands */ + qmp_for_each_command(&ga_commands, ga_disable_not_allowed, NULL); g_warning("disabling logging due to filesystem freeze"); ga_disable_logging(s); s->frozen = true; @@ -465,8 +465,8 @@ void ga_unset_frozen(GAState *s) s->deferred_options.pid_filepath = NULL; } - /* enable all disabled, non-blacklisted commands */ - qmp_for_each_command(&ga_commands, ga_enable_non_blacklisted, s->blacklist); + /* enable all disabled, non-blocked commands */ + qmp_for_each_command(&ga_commands, ga_enable_non_blocked, s->blockedrpcs); s->frozen = false; if (!ga_delete_file(s->state_filepath_isfrozen)) { g_warning("unable to delete %s, fsfreeze may not function properly", @@ -896,7 +896,8 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp) int64_t handle; g_assert(s->pstate_filepath); - /* we blacklist commands and avoid operations that potentially require + /* + * We block commands and avoid operations that potentially require * writing to disk when we're in a frozen state. this includes opening * new files, so we should never get here in that situation */ @@ -950,8 +951,8 @@ struct GAConfig { #ifdef _WIN32 const char *service; #endif - gchar *bliststr; /* blacklist may point to this string */ - GList *blacklist; + gchar *bliststr; /* blockedrpcs may point to this string */ + GList *blockedrpcs; int daemonize; GLogLevelFlags log_level; int dumpconf; @@ -963,6 +964,7 @@ static void config_load(GAConfig *config) GError *gerr = NULL; GKeyFile *keyfile; g_autofree char *conf = g_strdup(g_getenv("QGA_CONF")) ?: get_relocated_path(QGA_CONF_DEFAULT); + const gchar *blockrpcs_key = "block-rpcs"; /* read system config */ keyfile = g_key_file_new(); @@ -1009,10 +1011,16 @@ static void config_load(GAConfig *config) config->retry_path = g_key_file_get_boolean(keyfile, "general", "retry-path", &gerr); } + if (g_key_file_has_key(keyfile, "general", "blacklist", NULL)) { + g_warning("config using deprecated 'blacklist' key, should be replaced" + " with the 'block-rpcs' key."); + blockrpcs_key = "blacklist"; + } + if (g_key_file_has_key(keyfile, "general", blockrpcs_key, NULL)) { config->bliststr = - g_key_file_get_string(keyfile, "general", "blacklist", &gerr); - config->blacklist = g_list_concat(config->blacklist, + g_key_file_get_string(keyfile, "general", blockrpcs_key, &gerr); + config->blockedrpcs = g_list_concat(config->blockedrpcs, split_list(config->bliststr, ",")); } @@ -1072,8 +1080,8 @@ static void config_dump(GAConfig *config) config->log_level == G_LOG_LEVEL_MASK); g_key_file_set_boolean(keyfile, "general", "retry-path", config->retry_path); - tmp = list_join(config->blacklist, ','); - g_key_file_set_string(keyfile, "general", "blacklist", tmp); + tmp = list_join(config->blockedrpcs, ','); + g_key_file_set_string(keyfile, "general", "block-rpcs", tmp); g_free(tmp); tmp = g_key_file_to_data(keyfile, NULL, &error); @@ -1105,7 +1113,8 @@ static void config_parse(GAConfig *config, int argc, char **argv) { "method", 1, NULL, 'm' }, { "path", 1, NULL, 'p' }, { "daemonize", 0, NULL, 'd' }, - { "blacklist", 1, NULL, 'b' }, + { "block-rpcs", 1, NULL, 'b' }, + { "blacklist", 1, NULL, 'b' }, /* deprecated alias for 'block-rpcs' */ #ifdef _WIN32 { "service", 1, NULL, 's' }, #endif @@ -1163,8 +1172,8 @@ static void config_parse(GAConfig *config, int argc, char **argv) qmp_for_each_command(&ga_commands, ga_print_cmd, NULL); exit(EXIT_SUCCESS); } - config->blacklist = g_list_concat(config->blacklist, - split_list(optarg, ",")); + config->blockedrpcs = g_list_concat(config->blockedrpcs, + split_list(optarg, ",")); break; } #ifdef _WIN32 @@ -1218,7 +1227,7 @@ static void config_free(GAConfig *config) #ifdef CONFIG_FSFREEZE g_free(config->fsfreeze_hook); #endif - g_list_free_full(config->blacklist, g_free); + g_list_free_full(config->blockedrpcs, g_free); g_free(config); } @@ -1302,7 +1311,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) s->deferred_options.log_filepath = config->log_filepath; } ga_disable_logging(s); - qmp_for_each_command(&ga_commands, ga_disable_non_whitelisted, NULL); + qmp_for_each_command(&ga_commands, ga_disable_not_allowed, NULL); } else { if (config->daemonize) { become_daemon(config->pid_filepath); @@ -1326,10 +1335,10 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) return NULL; } - config->blacklist = ga_command_blacklist_init(config->blacklist); - if (config->blacklist) { - GList *l = config->blacklist; - s->blacklist = config->blacklist; + config->blockedrpcs = ga_command_init_blockedrpcs(config->blockedrpcs); + if (config->blockedrpcs) { + GList *l = config->blockedrpcs; + s->blockedrpcs = config->blockedrpcs; do { g_debug("disabling command: %s", (char *)l->data); qmp_disable_command(&ga_commands, l->data, NULL); diff --git a/qga/meson.build b/qga/meson.build index 65c1e93846..a0ffd6d268 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -138,7 +138,7 @@ else if get_option('guest_agent_msi').enabled() error('MSI guest agent package is available only for MinGW Windows cross-compilation') endif - install_subdir('run', install_dir: get_option('localstatedir')) + install_emptydir(get_option('localstatedir') / 'run') endif alias_target('qemu-ga', all_qga) diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 869399ea1a..026a56f76c 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -16,8 +16,8 @@ { 'pragma': { 'doc-required': true } } -# Whitelists to permit QAPI rule violations; think twice before you -# add to them! +# Lists with items allowed to permit QAPI rule violations; think twice +# before you add to them! { 'pragma': { # Types whose member names may use '_' 'member-name-exceptions': [ diff --git a/replay/replay-char.c b/replay/replay-char.c index d2025948cf..a31aded032 100644 --- a/replay/replay-char.c +++ b/replay/replay-char.c @@ -48,7 +48,7 @@ void replay_register_char_driver(Chardev *chr) char_drivers[drivers_count++] = chr; } -void replay_chr_be_write(Chardev *s, uint8_t *buf, int len) +void replay_chr_be_write(Chardev *s, const uint8_t *buf, int len) { CharEvent *event = g_new0(CharEvent, 1); diff --git a/replay/replay.c b/replay/replay.c index 4c396bb376..9a0dc1cf44 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -366,10 +366,8 @@ void replay_finish(void) fclose(replay_file); replay_file = NULL; } - if (replay_filename) { - g_free(replay_filename); - replay_filename = NULL; - } + g_free(replay_filename); + replay_filename = NULL; g_free(replay_snapshot); replay_snapshot = NULL; diff --git a/roms/SLOF b/roms/SLOF index 5b4c5acdcd..6b6c16b4b4 160000 --- a/roms/SLOF +++ b/roms/SLOF @@ -1 +1 @@ -Subproject commit 5b4c5acdcd552a4e1796aeca6bb700f6cbb0282d +Subproject commit 6b6c16b4b40763507cf1f518096f3c3883c5cf2d diff --git a/roms/opensbi b/roms/opensbi index 48f91ee9c9..4489876e93 160000 --- a/roms/opensbi +++ b/roms/opensbi @@ -1 +1 @@ -Subproject commit 48f91ee9c960f048c4a7d1da4447d31e04931e38 +Subproject commit 4489876e933d8ba0d8bc6c64bae71e295d45faac diff --git a/roms/qboot b/roms/qboot index a5300c4949..8ca302e86d 160000 --- a/roms/qboot +++ b/roms/qboot @@ -1 +1 @@ -Subproject commit a5300c4949b8d4de2d34bedfaed66793f48ec948 +Subproject commit 8ca302e86d685fa05b16e2b208888243da319941 diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh index c6169db69f..23e042dacd 100755 --- a/scripts/archive-source.sh +++ b/scripts/archive-source.sh @@ -26,7 +26,7 @@ sub_file="${sub_tdir}/submodule.tar" # independent of what the developer currently has initialized # in their checkout, because the build environment is completely # different to the host OS. -submodules="dtc slirp meson ui/keycodemapdb" +submodules="dtc meson ui/keycodemapdb" submodules="$submodules tests/fp/berkeley-softfloat-3 tests/fp/berkeley-testfloat-3" sub_deinit="" diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d900d18048..e3e3b43076 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1667,6 +1667,7 @@ sub process { # some scripts we imported from other projects. next if ($realfile =~ /\.(s|S)$/); next if ($realfile =~ /(checkpatch|get_maintainer)\.pl$/); + next if ($realfile =~ /^target\/hexagon\/imported\/*/); if ($rawline =~ /^\+.*\t/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index 232525b91d..b04c2b7cee 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -97,7 +97,7 @@ state: present when: - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] != 's390x' + - ansible_facts['architecture'] == 'aarch64' or ansible_facts['architecture'] == 'x86_64' - name: Install basic packages to build QEMU on Ubuntu 20.04 package: @@ -153,13 +153,13 @@ - make - mesa-libEGL-devel - nettle-devel + - ninja-build - nmap-ncat - perl-Test-Harness - pixman-devel - python36 - rdma-core-devel - spice-glib-devel - - spice-server - systemtap-sdt-devel - tar - zlib-devel @@ -167,3 +167,14 @@ when: - ansible_facts['distribution_file_variety'] == 'RedHat' - ansible_facts['distribution_version'] == '8' + + - name: Install packages only available on x86 and aarch64 + dnf: + # Spice server not available in ppc64le + name: + - spice-server + state: present + when: + - ansible_facts['distribution_file_variety'] == 'RedHat' + - ansible_facts['distribution_version'] == '8' + - ansible_facts['architecture'] == 'aarch64' or ansible_facts['architecture'] == 'x86_64' diff --git a/scripts/coverity-scan/COMPONENTS.md b/scripts/coverity-scan/COMPONENTS.md index de2eb96241..0e6ab4936e 100644 --- a/scripts/coverity-scan/COMPONENTS.md +++ b/scripts/coverity-scan/COMPONENTS.md @@ -22,7 +22,7 @@ i386 ~ (/qemu)?((/include)?/hw/i386/.*|/target/i386/.*|/hw/intc/[^/]*apic[^/]*\.c) m68k - ~ (/qemu)?((/include)?/hw/m68k/.*|/target/m68k/.*|(/include)?/hw(/.*)?/mcf.*) + ~ (/qemu)?((/include)?/hw/m68k/.*|/target/m68k/.*|(/include)?/hw(/.*)?/mcf.*|(/include)?/hw/nubus/.*) microblaze ~ (/qemu)?((/include)?/hw/microblaze/.*|/target/microblaze/.*) @@ -108,8 +108,8 @@ qemu-ga scsi ~ (/qemu)?(/scsi/.*|/hw/scsi/.*|/include/hw/scsi/.*) -slirp - ~ (/qemu)?(/.*slirp.*) +slirp (component should be ignored in analysis) + ~ (/qemu)?(/slirp/.*) tcg ~ (/qemu)?(/accel/tcg/.*|/replay/.*|/(.*/)?softmmu.*) @@ -143,3 +143,9 @@ testlibs tests ~ (/qemu)?(/tests/.*) + +loongarch + ~ (/qemu)?((/include)?/hw/(loongarch/.*|.*/loongarch.*)|/target/loongarch/.*) + +riscv + ~ (/qemu)?((/include)?/hw/riscv/.*|/target/riscv/.*|/hw/.*/(riscv_|ibex_|sifive_).*) diff --git a/scripts/main.c b/scripts/main.c new file mode 100644 index 0000000000..b552c8e4ed --- /dev/null +++ b/scripts/main.c @@ -0,0 +1 @@ +int main(void) {} diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 1eb32c182a..f81aca4d33 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -1,7 +1,7 @@ # This file is generated by meson-buildoptions.py, do not edit! meson_options_help() { - printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices:' - printf "%s\n" ' alsa/coreaudio/default/dsound/jack/oss/pa/sdl)' + printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices: alsa/co' + printf "%s\n" ' reaudio/default/dsound/jack/oss/pa/sdl/sndio)' printf "%s\n" ' --block-drv-ro-whitelist=VALUE' printf "%s\n" ' set block driver read-only whitelist (by default' printf "%s\n" ' affects only QEMU, not tools like qemu-img)' @@ -35,8 +35,6 @@ meson_options_help() { printf "%s\n" ' --enable-qom-cast-debug cast debugging support' printf "%s\n" ' --enable-rng-none dummy RNG, avoid using /dev/(u)random and' printf "%s\n" ' getrandom()' - printf "%s\n" ' --enable-slirp[=CHOICE] Whether and how to find the slirp library' - printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-strip Strip targets on install' printf "%s\n" ' --enable-tcg-interpreter TCG with bytecode interpreter (slow)' printf "%s\n" ' --enable-trace-backends=CHOICES' @@ -141,9 +139,11 @@ meson_options_help() { printf "%s\n" ' sdl-image SDL Image support for icons' printf "%s\n" ' seccomp seccomp support' printf "%s\n" ' selinux SELinux support in qemu-nbd' + printf "%s\n" ' slirp libslirp user mode network backend support' printf "%s\n" ' slirp-smbd use smbd (at path --smbd=*) in slirp networking' printf "%s\n" ' smartcard CA smartcard emulation support' printf "%s\n" ' snappy snappy compression support' + printf "%s\n" ' sndio sndio sound support' printf "%s\n" ' sparse sparse checker' printf "%s\n" ' spice Spice server support' printf "%s\n" ' spice-protocol Spice protocol support' @@ -388,13 +388,14 @@ _meson_option_parse() { --disable-selinux) printf "%s" -Dselinux=disabled ;; --enable-slirp) printf "%s" -Dslirp=enabled ;; --disable-slirp) printf "%s" -Dslirp=disabled ;; - --enable-slirp=*) quote_sh "-Dslirp=$2" ;; --enable-slirp-smbd) printf "%s" -Dslirp_smbd=enabled ;; --disable-slirp-smbd) printf "%s" -Dslirp_smbd=disabled ;; --enable-smartcard) printf "%s" -Dsmartcard=enabled ;; --disable-smartcard) printf "%s" -Dsmartcard=disabled ;; --enable-snappy) printf "%s" -Dsnappy=enabled ;; --disable-snappy) printf "%s" -Dsnappy=disabled ;; + --enable-sndio) printf "%s" -Dsndio=enabled ;; + --disable-sndio) printf "%s" -Dsndio=disabled ;; --enable-sparse) printf "%s" -Dsparse=enabled ;; --disable-sparse) printf "%s" -Dsparse=disabled ;; --sphinx-build=*) quote_sh "-Dsphinx_build=$2" ;; diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 1a1e2a6960..bfea9e9337 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -24,7 +24,7 @@ * * ARM Semihosting is documented in: * Semihosting for AArch32 and AArch64 Release 2.0 - * https://static.docs.arm.com/100863/0200/semihosting.pdf + * https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst * * RISC-V Semihosting is documented in: * RISC-V Semihosting @@ -171,6 +171,12 @@ static LayoutInfo common_semi_find_bases(CPUState *cs) * Read the input value from the argument block; fail the semihosting * call if the memory read fails. Eventually we could use a generic * CPUState helper function here. + * Note that GET_ARG() handles memory access errors by jumping to + * do_fault, so must be used as the first thing done in handling a + * semihosting call, to avoid accidentally leaking allocated resources. + * SET_ARG(), since it unavoidably happens late, instead returns an + * error indication (0 on success, non-0 for error) which the caller + * should check. */ #define GET_ARG(n) do { \ @@ -498,16 +504,25 @@ void do_common_semihosting(CPUState *cs) GET_ARG(1); GET_ARG(2); len = asprintf(&s, "/tmp/qemu-%x%02x", getpid(), (int)arg1 & 0xff); + if (len < 0) { + common_semi_set_ret(cs, -1); + break; + } + + /* Allow for trailing NUL */ + len++; /* Make sure there's enough space in the buffer */ - if (len < 0 || len >= arg2) { + if (len > arg2) { + free(s); common_semi_set_ret(cs, -1); break; } p = lock_user(VERIFY_WRITE, arg0, len, 0); if (!p) { + free(s); goto do_fault; } - memcpy(p, s, len + 1); + memcpy(p, s, len); unlock_user(p, arg0, len); free(s); common_semi_set_ret(cs, 0); @@ -739,10 +754,14 @@ void do_common_semihosting(CPUState *cs) case TARGET_SYS_ELAPSED: elapsed = get_clock() - clock_start; if (sizeof(target_ulong) == 8) { - SET_ARG(0, elapsed); + if (SET_ARG(0, elapsed)) { + goto do_fault; + } } else { - SET_ARG(0, (uint32_t) elapsed); - SET_ARG(1, (uint32_t) (elapsed >> 32)); + if (SET_ARG(0, (uint32_t) elapsed) || + SET_ARG(1, (uint32_t) (elapsed >> 32))) { + goto do_fault; + } } common_semi_set_ret(cs, 0); break; diff --git a/semihosting/config.c b/semihosting/config.c index e171d4d6bc..89a1759687 100644 --- a/semihosting/config.c +++ b/semihosting/config.c @@ -34,6 +34,9 @@ QemuOptsList qemu_semihosting_config_opts = { { .name = "enable", .type = QEMU_OPT_BOOL, + }, { + .name = "userspace", + .type = QEMU_OPT_BOOL, }, { .name = "target", .type = QEMU_OPT_STRING, @@ -50,6 +53,7 @@ QemuOptsList qemu_semihosting_config_opts = { typedef struct SemihostingConfig { bool enabled; + bool userspace_enabled; SemihostingTarget target; char **argv; int argc; @@ -59,9 +63,9 @@ typedef struct SemihostingConfig { static SemihostingConfig semihosting; static const char *semihost_chardev; -bool semihosting_enabled(void) +bool semihosting_enabled(bool is_user) { - return semihosting.enabled; + return semihosting.enabled && (!is_user || semihosting.userspace_enabled); } SemihostingTarget semihosting_get_target(void) @@ -137,6 +141,8 @@ int qemu_semihosting_config_options(const char *optarg) if (opts != NULL) { semihosting.enabled = qemu_opt_get_bool(opts, "enable", true); + semihosting.userspace_enabled = qemu_opt_get_bool(opts, "userspace", + false); const char *target = qemu_opt_get(opts, "target"); /* setup of chardev is deferred until they are initialised */ semihost_chardev = qemu_opt_get(opts, "chardev"); diff --git a/semihosting/console.c b/semihosting/console.c index 5b1ec0a1c3..0f976fe8cb 100644 --- a/semihosting/console.c +++ b/semihosting/console.c @@ -111,7 +111,8 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len) int qemu_semihosting_console_write(void *buf, int len) { if (console.chr) { - return qemu_chr_write_all(console.chr, (uint8_t *)buf, len); + int r = qemu_chr_write_all(console.chr, (uint8_t *)buf, len); + return r < 0 ? 0 : r; } else { return fwrite(buf, 1, len, stderr); } diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c index 4847f66c02..508a0ad88c 100644 --- a/semihosting/syscalls.c +++ b/semihosting/syscalls.c @@ -627,7 +627,7 @@ static void console_write(CPUState *cs, gdb_syscall_complete_cb complete, } ret = qemu_semihosting_console_write(ptr, len); complete(cs, ret ? ret : -1, ret ? 0 : EIO); - unlock_user(ptr, buf, ret); + unlock_user(ptr, buf, 0); } static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete, diff --git a/slirp b/slirp deleted file mode 160000 index 9d59bb775d..0000000000 --- a/slirp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9d59bb775d6294c8b447a88512f7bb43f12a25a8 diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 23b30484b2..61b27ff59d 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -617,6 +617,13 @@ void cpus_register_accel(const AccelOpsClass *ops) cpus_accel = ops; } +const AccelOpsClass *cpus_get_accel(void) +{ + /* broken if we call this early */ + assert(cpus_accel); + return cpus_accel; +} + void qemu_init_vcpu(CPUState *cpu) { MachineState *ms = MACHINE(qdev_get_machine()); diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c index 8d98cb7f2c..12668555f2 100644 --- a/softmmu/dirtylimit.c +++ b/softmmu/dirtylimit.c @@ -154,7 +154,7 @@ void vcpu_dirty_rate_stat_initialize(void) vcpu_dirty_rate_stat->stat.nvcpu = max_cpus; vcpu_dirty_rate_stat->stat.rates = - g_malloc0(sizeof(DirtyRateVcpu) * max_cpus); + g_new0(DirtyRateVcpu, max_cpus); vcpu_dirty_rate_stat->running = false; } @@ -198,7 +198,7 @@ void dirtylimit_state_initialize(void) dirtylimit_state = g_malloc0(sizeof(*dirtylimit_state)); dirtylimit_state->states = - g_malloc0(sizeof(VcpuDirtyLimitState) * max_cpus); + g_new0(VcpuDirtyLimitState, max_cpus); for (i = 0; i < max_cpus; i++) { dirtylimit_state->states[i].cpu_index = i; diff --git a/softmmu/main.c b/softmmu/main.c index f031b486cc..ea17e0d3bd 100644 --- a/softmmu/main.c +++ b/softmmu/main.c @@ -30,20 +30,22 @@ #include #endif -int qemu_main(int argc, char **argv, char **envp) +int qemu_default_main(void) { - qemu_init(argc, argv, envp); - qemu_main_loop(); + int status; + + status = qemu_main_loop(); qemu_cleanup(); - return 0; + return status; } +int (*qemu_main)(void) = qemu_default_main; + #ifndef AS_LIB -#ifndef CONFIG_COCOA int main(int argc, char **argv) { - return qemu_main(argc, argv, NULL); + qemu_init(argc, argv); + return qemu_main(); } #endif -#endif diff --git a/softmmu/physmem.c b/softmmu/physmem.c index dc3c3e5f2e..56e03e07b5 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -1331,13 +1331,6 @@ GString *ram_block_format(void) return buf; } -#ifdef __linux__ -/* - * FIXME TOCTTOU: this iterates over memory backends' mem-path, which - * may or may not name the same files / on the same filesystem now as - * when we actually open and map them. Iterate over the file - * descriptors instead, and use qemu_fd_getpagesize(). - */ static int find_min_backend_pagesize(Object *obj, void *opaque) { long *hpsize_min = opaque; @@ -1391,16 +1384,6 @@ long qemu_maxrampagesize(void) object_child_foreach(memdev_root, find_max_backend_pagesize, &pagesize); return pagesize; } -#else -long qemu_minrampagesize(void) -{ - return qemu_real_host_page_size(); -} -long qemu_maxrampagesize(void) -{ - return qemu_real_host_page_size(); -} -#endif #ifdef CONFIG_POSIX static int64_t get_file_size(int fd) @@ -2460,6 +2443,18 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr) return block->offset + offset; } +ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr) +{ + ram_addr_t ram_addr; + + ram_addr = qemu_ram_addr_from_host(ptr); + if (ram_addr == RAM_ADDR_INVALID) { + error_report("Bad ram pointer %p", ptr); + abort(); + } + return ram_addr; +} + static MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs, void *buf, hwaddr len); static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, diff --git a/softmmu/runstate.c b/softmmu/runstate.c index 168e1b78a0..1e68680b9d 100644 --- a/softmmu/runstate.c +++ b/softmmu/runstate.c @@ -482,7 +482,8 @@ void qemu_system_guest_panicked(GuestPanicInformation *info) qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, !!info, info); vm_stop(RUN_STATE_GUEST_PANICKED); - } else if (panic_action == PANIC_ACTION_SHUTDOWN) { + } else if (panic_action == PANIC_ACTION_SHUTDOWN || + panic_action == PANIC_ACTION_EXIT_FAILURE) { qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_POWEROFF, !!info, info); vm_stop(RUN_STATE_GUEST_PANICKED); @@ -662,7 +663,7 @@ void qemu_system_debug_request(void) qemu_notify_event(); } -static bool main_loop_should_exit(void) +static bool main_loop_should_exit(int *status) { RunState r; ShutdownCause request; @@ -680,6 +681,10 @@ static bool main_loop_should_exit(void) if (shutdown_action == SHUTDOWN_ACTION_PAUSE) { vm_stop(RUN_STATE_SHUTDOWN); } else { + if (request == SHUTDOWN_CAUSE_GUEST_PANIC && + panic_action == PANIC_ACTION_EXIT_FAILURE) { + *status = EXIT_FAILURE; + } return true; } } @@ -715,12 +720,14 @@ static bool main_loop_should_exit(void) return false; } -void qemu_main_loop(void) +int qemu_main_loop(void) { + int status = EXIT_SUCCESS; #ifdef CONFIG_PROFILER int64_t ti; #endif - while (!main_loop_should_exit()) { + + while (!main_loop_should_exit(&status)) { #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif @@ -729,6 +736,8 @@ void qemu_main_loop(void) dev_time += profile_getclock() - ti; #endif } + + return status; } void qemu_add_exit_notifier(Notifier *notify) diff --git a/softmmu/vl.c b/softmmu/vl.c index aabd82e09a..b464da25bc 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -53,7 +53,6 @@ #include "hw/isa/isa.h" #include "hw/scsi/scsi.h" #include "hw/display/vga.h" -#include "sysemu/watchdog.h" #include "hw/firmware/smbios.h" #include "hw/acpi/acpi.h" #include "hw/xen/xen.h" @@ -181,7 +180,6 @@ static Chardev **serial_hds; static const char *log_mask; static const char *log_file; static bool list_data_dirs; -static const char *watchdog; static const char *qtest_chrdev; static const char *qtest_log; @@ -1822,7 +1820,7 @@ static void qemu_apply_machine_options(QDict *qdict) { object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal); - if (semihosting_enabled() && !semihosting_get_argc()) { + if (semihosting_enabled(false) && !semihosting_get_argc()) { /* fall back to the -kernel/-append */ semihosting_arg_fallback(current_machine->kernel_filename, current_machine->kernel_cmdline); } @@ -1885,7 +1883,9 @@ static void qemu_create_early_backends(void) * setting machine properties, so they can be referred to. */ configure_blockdev(&bdo_queue, machine_class, snapshot); - audio_init_audiodevs(); + if (!audio_init_audiodevs()) { + exit(1); + } } @@ -1947,27 +1947,21 @@ static void qemu_resolve_machine_memdev(void) } } -static void parse_memory_options(const char *arg) +static void parse_memory_options(void) { - QemuOpts *opts; + QemuOpts *opts = qemu_find_opts_singleton("memory"); QDict *dict, *prop; const char *mem_str; + Location loc; - opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), arg, true); - if (!opts) { - exit(EXIT_FAILURE); - } + loc_push_none(&loc); + qemu_opts_loc_restore(opts); prop = qdict_new(); if (qemu_opt_get_size(opts, "size", 0) != 0) { - mem_str = qemu_opt_get(opts, "size"); - if (!*mem_str) { - error_report("missing 'size' option value"); - exit(EXIT_FAILURE); - } - /* Fix up legacy suffix-less format */ + mem_str = qemu_opt_get(opts, "size"); if (g_ascii_isdigit(mem_str[strlen(mem_str) - 1])) { g_autofree char *mib_str = g_strdup_printf("%sM", mem_str); qdict_put_str(prop, "size", mib_str); @@ -1987,6 +1981,7 @@ static void parse_memory_options(const char *arg) qdict_put(dict, "memory", prop); keyval_merge(machine_opts_dict, dict, &error_fatal); qobject_unref(dict); + loc_pop(&loc); } static void qemu_create_machine(QDict *qdict) @@ -2053,8 +2048,7 @@ static bool is_qemuopts_group(const char *group) if (g_str_equal(group, "object") || g_str_equal(group, "machine") || g_str_equal(group, "smp-opts") || - g_str_equal(group, "boot-opts") || - g_str_equal(group, "memory")) { + g_str_equal(group, "boot-opts")) { return false; } return true; @@ -2078,8 +2072,6 @@ static void qemu_record_config_group(const char *group, QDict *dict, machine_merge_property("smp", dict, &error_fatal); } else if (g_str_equal(group, "boot-opts")) { machine_merge_property("boot", dict, &error_fatal); - } else if (g_str_equal(group, "memory")) { - machine_merge_property("memory", dict, &error_fatal); } else { abort(); } @@ -2335,12 +2327,6 @@ static void qemu_process_sugar_options(void) } object_register_sugar_prop("memory-backend", "prealloc", "on", false); } - - if (watchdog) { - int i = select_watchdog(watchdog); - if (i > 0) - exit (i == 1 ? 1 : 0); - } } /* -action processing */ @@ -2611,7 +2597,7 @@ void qmp_x_exit_preconfig(Error **errp) } } -void qemu_init(int argc, char **argv, char **envp) +void qemu_init(int argc, char **argv) { QemuOpts *opts; QemuOpts *icount_opts = NULL, *accel_opts = NULL; @@ -2848,11 +2834,16 @@ void qemu_init(int argc, char **argv, char **envp) audio_parse_option(optarg); break; case QEMU_OPTION_audio: { - QDict *dict = keyval_parse(optarg, "driver", NULL, &error_fatal); + bool help; char *model; Audiodev *dev = NULL; Visitor *v; - + QDict *dict = keyval_parse(optarg, "driver", &help, &error_fatal); + if (help || (qdict_haskey(dict, "driver") && + is_help_option(qdict_get_str(dict, "driver")))) { + audio_help(); + exit(EXIT_SUCCESS); + } if (!qdict_haskey(dict, "id")) { qdict_put_str(dict, "id", "audiodev0"); } @@ -2882,7 +2873,10 @@ void qemu_init(int argc, char **argv, char **envp) exit(0); break; case QEMU_OPTION_m: - parse_memory_options(optarg); + opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), optarg, true); + if (opts == NULL) { + exit(1); + } break; #ifdef CONFIG_TPM case QEMU_OPTION_tpmdev: @@ -3105,14 +3099,6 @@ void qemu_init(int argc, char **argv, char **envp) default_monitor = 0; } break; - case QEMU_OPTION_watchdog: - if (watchdog) { - error_report("only one watchdog option may be given"); - exit(1); - } - warn_report("-watchdog is deprecated; use -device instead."); - watchdog = optarg; - break; case QEMU_OPTION_action: olist = qemu_find_opts("action"); if (!qemu_opts_parse_noisily(olist, optarg, false)) { @@ -3515,6 +3501,9 @@ void qemu_init(int argc, char **argv, char **envp) configure_rtc(qemu_find_opts_singleton("rtc")); + /* Transfer QemuOpts options into machine options */ + parse_memory_options(); + qemu_create_machine(machine_opts_dict); suspend_mux_open(); diff --git a/stubs/replay-tools.c b/stubs/replay-tools.c index 43296b3d4e..3e8ca3212d 100644 --- a/stubs/replay-tools.c +++ b/stubs/replay-tools.c @@ -7,13 +7,14 @@ bool replay_events_enabled(void) return false; } -int64_t replay_save_clock(unsigned int kind, int64_t clock, int64_t raw_icount) +int64_t replay_save_clock(ReplayClockKind kind, + int64_t clock, int64_t raw_icount) { abort(); return 0; } -int64_t replay_read_clock(unsigned int kind, int64_t raw_icount) +int64_t replay_read_clock(ReplayClockKind kind, int64_t raw_icount) { abort(); return 0; @@ -48,11 +49,11 @@ void replay_mutex_unlock(void) { } -void replay_register_char_driver(Chardev *chr) +void replay_register_char_driver(struct Chardev *chr) { } -void replay_chr_be_write(Chardev *s, uint8_t *buf, int len) +void replay_chr_be_write(struct Chardev *s, const uint8_t *buf, int len) { abort(); } diff --git a/stubs/semihost.c b/stubs/semihost.c index f486651afb..d65c9fd5dc 100644 --- a/stubs/semihost.c +++ b/stubs/semihost.c @@ -23,7 +23,7 @@ QemuOptsList qemu_semihosting_config_opts = { }; /* Queries to config status default to off */ -bool semihosting_enabled(void) +bool semihosting_enabled(bool is_user) { return false; } diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c index 9a2bcec282..1a5981445c 100644 --- a/subprojects/libvduse/libvduse.c +++ b/subprojects/libvduse/libvduse.c @@ -1193,7 +1193,7 @@ static int vduse_dev_init(VduseDev *dev, const char *name, return 0; } -static inline bool vduse_name_is_valid(const char *name) +static inline bool vduse_name_is_invalid(const char *name) { return strlen(name) >= VDUSE_NAME_MAX || strstr(name, ".."); } @@ -1242,7 +1242,7 @@ VduseDev *vduse_dev_create_by_name(const char *name, uint16_t num_queues, VduseDev *dev; int ret; - if (!name || vduse_name_is_valid(name) || !ops || + if (!name || vduse_name_is_invalid(name) || !ops || !ops->enable_queue || !ops->disable_queue) { fprintf(stderr, "Invalid parameter for vduse\n"); return NULL; @@ -1257,7 +1257,7 @@ VduseDev *vduse_dev_create_by_name(const char *name, uint16_t num_queues, ret = vduse_dev_init(dev, name, num_queues, ops, priv); if (ret < 0) { fprintf(stderr, "Failed to init vduse device %s: %s\n", - name, strerror(ret)); + name, strerror(-ret)); free(dev); return NULL; } @@ -1276,7 +1276,7 @@ VduseDev *vduse_dev_create(const char *name, uint32_t device_id, struct vduse_dev_config *dev_config; size_t size = offsetof(struct vduse_dev_config, config); - if (!name || vduse_name_is_valid(name) || + if (!name || vduse_name_is_invalid(name) || !has_feature(features, VIRTIO_F_VERSION_1) || !config || !config_size || !ops || !ops->enable_queue || !ops->disable_queue) { fprintf(stderr, "Invalid parameter for vduse\n"); @@ -1309,7 +1309,8 @@ VduseDev *vduse_dev_create(const char *name, uint32_t device_id, goto err_dev; } - strcpy(dev_config->name, name); + strncpy(dev_config->name, name, VDUSE_NAME_MAX); + dev_config->name[VDUSE_NAME_MAX - 1] = '\0'; dev_config->device_id = device_id; dev_config->vendor_id = vendor_id; dev_config->features = features; @@ -1330,7 +1331,7 @@ VduseDev *vduse_dev_create(const char *name, uint32_t device_id, ret = vduse_dev_init(dev, name, num_queues, ops, priv); if (ret < 0) { fprintf(stderr, "Failed to init vduse device %s: %s\n", - name, strerror(ret)); + name, strerror(-ret)); goto err; } diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index a8990d401b..979a629d59 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -33,6 +33,14 @@ static void alpha_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.pc = value; } +static vaddr alpha_cpu_get_pc(CPUState *cs) +{ + AlphaCPU *cpu = ALPHA_CPU(cs); + + return cpu->env.pc; +} + + static bool alpha_cpu_has_work(CPUState *cs) { /* Here we are checking to see if the CPU should wake up from HALT. @@ -244,6 +252,7 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = alpha_cpu_has_work; cc->dump_state = alpha_cpu_dump_state; cc->set_pc = alpha_cpu_set_pc; + cc->get_pc = alpha_cpu_get_pc; cc->gdb_read_register = alpha_cpu_gdb_read_register; cc->gdb_write_register = alpha_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 9af1627079..6766350f56 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -3043,10 +3043,11 @@ static const TranslatorOps alpha_tr_ops = { .disas_log = alpha_tr_disas_log, }; -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc; - translator_loop(&alpha_tr_ops, &dc.base, cpu, tb, max_insns); + translator_loop(cpu, tb, max_insns, pc, host_pc, &alpha_tr_ops, &dc.base); } void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c index b1f040e69f..2d8e41ab8a 100644 --- a/target/arm/arch_dump.c +++ b/target/arm/arch_dump.c @@ -232,12 +232,11 @@ static int aarch64_write_elf64_sve(WriteCoreDumpFunction f, #endif int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { struct aarch64_note note; ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; - DumpState *s = opaque; uint64_t pstate, sp; int ret, i; @@ -360,12 +359,11 @@ static int arm_write_elf32_vfp(WriteCoreDumpFunction f, CPUARMState *env, } int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { struct arm_note note; ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; - DumpState *s = opaque; int ret, i; bool fpvalid = cpu_isar_feature(aa32_vfp_simd, cpu); diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index 68ffb12427..08681828ac 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -32,6 +32,6 @@ # define TARGET_PAGE_BITS_MIN 10 #endif -#define NB_MMU_MODES 15 +#define NB_MMU_MODES 8 #endif diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 1b7b3d76bb..94ca6f163f 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -60,6 +60,18 @@ static void arm_cpu_set_pc(CPUState *cs, vaddr value) } } +static vaddr arm_cpu_get_pc(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + if (is_a64(env)) { + return env->pc; + } else { + return env->regs[15]; + } +} + #ifdef CONFIG_TCG void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) @@ -72,9 +84,9 @@ void arm_cpu_synchronize_from_tb(CPUState *cs, * never possible for an AArch64 TB to chain to an AArch32 TB. */ if (is_a64(env)) { - env->pc = tb->pc; + env->pc = tb_pc(tb); } else { - env->regs[15] = tb->pc; + env->regs[15] = tb_pc(tb); } } #endif /* CONFIG_TCG */ @@ -1933,6 +1945,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } #endif + if (tcg_enabled()) { + /* + * Don't report the Statistical Profiling Extension in the ID + * registers, because TCG doesn't implement it yet (not even a + * minimal stub version) and guests will fall over when they + * try to access the non-existent system registers for it. + */ + cpu->isar.id_aa64dfr0 = + FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMSVER, 0); + } + /* MPU can be configured out of a PMSA CPU either by setting has-mpu * to false or by setting pmsav7-dregion to 0. */ @@ -2161,6 +2184,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = arm_cpu_has_work; cc->dump_state = arm_cpu_dump_state; cc->set_pc = arm_cpu_set_pc; + cc->get_pc = arm_cpu_get_pc; cc->gdb_read_register = arm_cpu_gdb_read_register; cc->gdb_write_register = arm_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/arm/cpu.h b/target/arm/cpu.h index e890ee074d..e3dbef5be8 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -975,6 +975,7 @@ struct ArchCPU { uint32_t id_mmfr2; uint32_t id_mmfr3; uint32_t id_mmfr4; + uint32_t id_mmfr5; uint32_t id_pfr0; uint32_t id_pfr1; uint32_t id_pfr2; @@ -982,6 +983,7 @@ struct ArchCPU { uint32_t mvfr1; uint32_t mvfr2; uint32_t id_dfr0; + uint32_t id_dfr1; uint32_t dbgdidr; uint32_t dbgdevid; uint32_t dbgdevid1; @@ -1100,9 +1102,9 @@ int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg); const char *arm_gdb_get_dynamic_xml(CPUState *cpu, const char *xmlname); int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); #ifdef TARGET_AARCH64 int aarch64_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); @@ -1332,8 +1334,15 @@ FIELD(CPTR_EL3, TTA, 20, 1) FIELD(CPTR_EL3, TAM, 30, 1) FIELD(CPTR_EL3, TCPAC, 31, 1) +#define MDCR_MTPME (1U << 28) +#define MDCR_TDCC (1U << 27) +#define MDCR_HLP (1U << 26) /* MDCR_EL2 */ +#define MDCR_SCCD (1U << 23) /* MDCR_EL3 */ +#define MDCR_HCCD (1U << 23) /* MDCR_EL2 */ #define MDCR_EPMAD (1U << 21) #define MDCR_EDAD (1U << 20) +#define MDCR_TTRF (1U << 19) +#define MDCR_STE (1U << 18) /* MDCR_EL3 */ #define MDCR_SPME (1U << 17) /* MDCR_EL3 */ #define MDCR_HPMD (1U << 17) /* MDCR_EL2 */ #define MDCR_SDD (1U << 16) @@ -1348,7 +1357,9 @@ FIELD(CPTR_EL3, TCPAC, 31, 1) #define MDCR_HPMN (0x1fU) /* Not all of the MDCR_EL3 bits are present in the 32-bit SDCR */ -#define SDCR_VALID_MASK (MDCR_EPMAD | MDCR_EDAD | MDCR_SPME | MDCR_SPD) +#define SDCR_VALID_MASK (MDCR_MTPME | MDCR_TDCC | MDCR_SCCD | \ + MDCR_EPMAD | MDCR_EDAD | MDCR_TTRF | \ + MDCR_STE | MDCR_SPME | MDCR_SPD) #define CPSR_M (0x1fU) #define CPSR_T (1U << 5) @@ -1653,33 +1664,33 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) #define HPFAR_NS (1ULL << 63) -#define SCR_NS (1U << 0) -#define SCR_IRQ (1U << 1) -#define SCR_FIQ (1U << 2) -#define SCR_EA (1U << 3) -#define SCR_FW (1U << 4) -#define SCR_AW (1U << 5) -#define SCR_NET (1U << 6) -#define SCR_SMD (1U << 7) -#define SCR_HCE (1U << 8) -#define SCR_SIF (1U << 9) -#define SCR_RW (1U << 10) -#define SCR_ST (1U << 11) -#define SCR_TWI (1U << 12) -#define SCR_TWE (1U << 13) -#define SCR_TLOR (1U << 14) -#define SCR_TERR (1U << 15) -#define SCR_APK (1U << 16) -#define SCR_API (1U << 17) -#define SCR_EEL2 (1U << 18) -#define SCR_EASE (1U << 19) -#define SCR_NMEA (1U << 20) -#define SCR_FIEN (1U << 21) -#define SCR_ENSCXT (1U << 25) -#define SCR_ATA (1U << 26) -#define SCR_FGTEN (1U << 27) -#define SCR_ECVEN (1U << 28) -#define SCR_TWEDEN (1U << 29) +#define SCR_NS (1ULL << 0) +#define SCR_IRQ (1ULL << 1) +#define SCR_FIQ (1ULL << 2) +#define SCR_EA (1ULL << 3) +#define SCR_FW (1ULL << 4) +#define SCR_AW (1ULL << 5) +#define SCR_NET (1ULL << 6) +#define SCR_SMD (1ULL << 7) +#define SCR_HCE (1ULL << 8) +#define SCR_SIF (1ULL << 9) +#define SCR_RW (1ULL << 10) +#define SCR_ST (1ULL << 11) +#define SCR_TWI (1ULL << 12) +#define SCR_TWE (1ULL << 13) +#define SCR_TLOR (1ULL << 14) +#define SCR_TERR (1ULL << 15) +#define SCR_APK (1ULL << 16) +#define SCR_API (1ULL << 17) +#define SCR_EEL2 (1ULL << 18) +#define SCR_EASE (1ULL << 19) +#define SCR_NMEA (1ULL << 20) +#define SCR_FIEN (1ULL << 21) +#define SCR_ENSCXT (1ULL << 25) +#define SCR_ATA (1ULL << 26) +#define SCR_FGTEN (1ULL << 27) +#define SCR_ECVEN (1ULL << 28) +#define SCR_TWEDEN (1ULL << 29) #define SCR_TWEDEL MAKE_64BIT_MASK(30, 4) #define SCR_TME (1ULL << 34) #define SCR_AMVOFFEN (1ULL << 35) @@ -2401,15 +2412,15 @@ static inline bool arm_is_secure(CPUARMState *env) * Return true if the current security state has AArch64 EL2 or AArch32 Hyp. * This corresponds to the pseudocode EL2Enabled() */ +static inline bool arm_is_el2_enabled_secstate(CPUARMState *env, bool secure) +{ + return arm_feature(env, ARM_FEATURE_EL2) + && (!secure || (env->cp15.scr_el3 & SCR_EEL2)); +} + static inline bool arm_is_el2_enabled(CPUARMState *env) { - if (arm_feature(env, ARM_FEATURE_EL2)) { - if (arm_is_secure_below_el3(env)) { - return (env->cp15.scr_el3 & SCR_EEL2) != 0; - } - return true; - } - return false; + return arm_is_el2_enabled_secstate(env, arm_is_secure_below_el3(env)); } #else @@ -2423,6 +2434,11 @@ static inline bool arm_is_secure(CPUARMState *env) return false; } +static inline bool arm_is_el2_enabled_secstate(CPUARMState *env, bool secure) +{ + return false; +} + static inline bool arm_is_el2_enabled(CPUARMState *env) { return false; @@ -2435,6 +2451,7 @@ static inline bool arm_is_el2_enabled(CPUARMState *env) * "for all purposes other than a direct read or write access of HCR_EL2." * Not included here is HCR_RW. */ +uint64_t arm_hcr_el2_eff_secstate(CPUARMState *env, bool secure); uint64_t arm_hcr_el2_eff(CPUARMState *env); uint64_t arm_hcrx_el2_eff(CPUARMState *env); @@ -2873,26 +2890,27 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); * table over and over. * 6. we need separate EL1/EL2 mmu_idx for handling the Privileged Access * Never (PAN) bit within PSTATE. + * 7. we fold together the secure and non-secure regimes for A-profile, + * because there are no banked system registers for aarch64, so the + * process of switching between secure and non-secure is + * already heavyweight. * * This gives us the following list of cases: * - * NS EL0 EL1&0 stage 1+2 (aka NS PL0) - * NS EL1 EL1&0 stage 1+2 (aka NS PL1) - * NS EL1 EL1&0 stage 1+2 +PAN - * NS EL0 EL2&0 - * NS EL2 EL2&0 - * NS EL2 EL2&0 +PAN - * NS EL2 (aka NS PL2) - * S EL0 EL1&0 (aka S PL0) - * S EL1 EL1&0 (not used if EL3 is 32 bit) - * S EL1 EL1&0 +PAN - * S EL3 (aka S PL1) + * EL0 EL1&0 stage 1+2 (aka NS PL0) + * EL1 EL1&0 stage 1+2 (aka NS PL1) + * EL1 EL1&0 stage 1+2 +PAN + * EL0 EL2&0 + * EL2 EL2&0 + * EL2 EL2&0 +PAN + * EL2 (aka NS PL2) + * EL3 (aka S PL1) * - * for a total of 11 different mmu_idx. + * for a total of 8 different mmu_idx. * * R profile CPUs have an MPU, but can use the same set of MMU indexes - * as A profile. They only need to distinguish NS EL0 and NS EL1 (and - * NS EL2 if we ever model a Cortex-R52). + * as A profile. They only need to distinguish EL0 and EL1 (and + * EL2 if we ever model a Cortex-R52). * * M profile CPUs are rather different as they do not have a true MMU. * They have the following different MMU indexes: @@ -2931,9 +2949,6 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); #define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */ #define ARM_MMU_IDX_M 0x40 /* M profile */ -/* Meanings of the bits for A profile mmu idx values */ -#define ARM_MMU_IDX_A_NS 0x8 - /* Meanings of the bits for M profile mmu idx values */ #define ARM_MMU_IDX_M_PRIV 0x1 #define ARM_MMU_IDX_M_NEGPRI 0x2 @@ -2947,22 +2962,14 @@ typedef enum ARMMMUIdx { /* * A-profile. */ - ARMMMUIdx_SE10_0 = 0 | ARM_MMU_IDX_A, - ARMMMUIdx_SE20_0 = 1 | ARM_MMU_IDX_A, - ARMMMUIdx_SE10_1 = 2 | ARM_MMU_IDX_A, - ARMMMUIdx_SE20_2 = 3 | ARM_MMU_IDX_A, - ARMMMUIdx_SE10_1_PAN = 4 | ARM_MMU_IDX_A, - ARMMMUIdx_SE20_2_PAN = 5 | ARM_MMU_IDX_A, - ARMMMUIdx_SE2 = 6 | ARM_MMU_IDX_A, - ARMMMUIdx_SE3 = 7 | ARM_MMU_IDX_A, - - ARMMMUIdx_E10_0 = ARMMMUIdx_SE10_0 | ARM_MMU_IDX_A_NS, - ARMMMUIdx_E20_0 = ARMMMUIdx_SE20_0 | ARM_MMU_IDX_A_NS, - ARMMMUIdx_E10_1 = ARMMMUIdx_SE10_1 | ARM_MMU_IDX_A_NS, - ARMMMUIdx_E20_2 = ARMMMUIdx_SE20_2 | ARM_MMU_IDX_A_NS, - ARMMMUIdx_E10_1_PAN = ARMMMUIdx_SE10_1_PAN | ARM_MMU_IDX_A_NS, - ARMMMUIdx_E20_2_PAN = ARMMMUIdx_SE20_2_PAN | ARM_MMU_IDX_A_NS, - ARMMMUIdx_E2 = ARMMMUIdx_SE2 | ARM_MMU_IDX_A_NS, + ARMMMUIdx_E10_0 = 0 | ARM_MMU_IDX_A, + ARMMMUIdx_E20_0 = 1 | ARM_MMU_IDX_A, + ARMMMUIdx_E10_1 = 2 | ARM_MMU_IDX_A, + ARMMMUIdx_E20_2 = 3 | ARM_MMU_IDX_A, + ARMMMUIdx_E10_1_PAN = 4 | ARM_MMU_IDX_A, + ARMMMUIdx_E20_2_PAN = 5 | ARM_MMU_IDX_A, + ARMMMUIdx_E2 = 6 | ARM_MMU_IDX_A, + ARMMMUIdx_E3 = 7 | ARM_MMU_IDX_A, /* * These are not allocated TLBs and are used only for AT system @@ -2971,9 +2978,6 @@ typedef enum ARMMMUIdx { ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB, ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB, ARMMMUIdx_Stage1_E1_PAN = 2 | ARM_MMU_IDX_NOTLB, - ARMMMUIdx_Stage1_SE0 = 3 | ARM_MMU_IDX_NOTLB, - ARMMMUIdx_Stage1_SE1 = 4 | ARM_MMU_IDX_NOTLB, - ARMMMUIdx_Stage1_SE1_PAN = 5 | ARM_MMU_IDX_NOTLB, /* * Not allocated a TLB: used only for second stage of an S12 page * table walk, or for descriptor loads during first stage of an S1 @@ -2981,8 +2985,8 @@ typedef enum ARMMMUIdx { * then various TLB flush insns which currently are no-ops or flush * only stage 1 MMU indexes will need to change to flush stage 2. */ - ARMMMUIdx_Stage2 = 6 | ARM_MMU_IDX_NOTLB, - ARMMMUIdx_Stage2_S = 7 | ARM_MMU_IDX_NOTLB, + ARMMMUIdx_Stage2 = 3 | ARM_MMU_IDX_NOTLB, + ARMMMUIdx_Stage2_S = 4 | ARM_MMU_IDX_NOTLB, /* * M-profile. @@ -3012,14 +3016,7 @@ typedef enum ARMMMUIdxBit { TO_CORE_BIT(E2), TO_CORE_BIT(E20_2), TO_CORE_BIT(E20_2_PAN), - TO_CORE_BIT(SE10_0), - TO_CORE_BIT(SE20_0), - TO_CORE_BIT(SE10_1), - TO_CORE_BIT(SE20_2), - TO_CORE_BIT(SE10_1_PAN), - TO_CORE_BIT(SE20_2_PAN), - TO_CORE_BIT(SE2), - TO_CORE_BIT(SE3), + TO_CORE_BIT(E3), TO_CORE_BIT(MUser), TO_CORE_BIT(MPriv), @@ -3192,6 +3189,8 @@ FIELD(TBFLAG_M32, NEW_FP_CTXT_NEEDED, 3, 1) /* Not cached. */ FIELD(TBFLAG_M32, FPCCR_S_WRONG, 4, 1) /* Not cached. */ /* Set if MVE insns are definitely not predicated by VPR or LTPSIZE */ FIELD(TBFLAG_M32, MVE_NO_PRED, 5, 1) /* Not cached. */ +/* Set if in secure mode */ +FIELD(TBFLAG_M32, SECURE, 6, 1) /* * Bit usage when in AArch64 state @@ -3387,7 +3386,7 @@ static inline uint64_t *aa64_vfp_qreg(CPUARMState *env, unsigned regno) } /* Shared between translate-sve.c and sve_helper.c. */ -extern const uint64_t pred_esz_masks[4]; +extern const uint64_t pred_esz_masks[5]; /* Helper for the macros below, validating the argument type. */ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x) @@ -3710,20 +3709,27 @@ static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2; } -static inline bool isar_feature_aa32_pmu_8_1(const ARMISARegisters *id) +static inline bool isar_feature_aa32_pmuv3p1(const ARMISARegisters *id) { /* 0xf means "non-standard IMPDEF PMU" */ return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 && FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; } -static inline bool isar_feature_aa32_pmu_8_4(const ARMISARegisters *id) +static inline bool isar_feature_aa32_pmuv3p4(const ARMISARegisters *id) { /* 0xf means "non-standard IMPDEF PMU" */ return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 5 && FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; } +static inline bool isar_feature_aa32_pmuv3p5(const ARMISARegisters *id) +{ + /* 0xf means "non-standard IMPDEF PMU" */ + return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 6 && + FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; +} + static inline bool isar_feature_aa32_hpd(const ARMISARegisters *id) { return FIELD_EX32(id->id_mmfr4, ID_MMFR4, HPDS) != 0; @@ -4036,18 +4042,24 @@ static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0; } -static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) +static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; } -static inline bool isar_feature_aa64_pmu_8_4(const ARMISARegisters *id) +static inline bool isar_feature_aa64_pmuv3p4(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 && FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; } +static inline bool isar_feature_aa64_pmuv3p5(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 6 && + FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; +} + static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0; @@ -4085,6 +4097,39 @@ static inline bool isar_feature_aa64_tgran16_2_lpa2(const ARMISARegisters *id) return t >= 3 || (t == 0 && isar_feature_aa64_tgran16_lpa2(id)); } +static inline bool isar_feature_aa64_tgran4(const ARMISARegisters *id) +{ + return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 0; +} + +static inline bool isar_feature_aa64_tgran16(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 1; +} + +static inline bool isar_feature_aa64_tgran64(const ARMISARegisters *id) +{ + return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN64) >= 0; +} + +static inline bool isar_feature_aa64_tgran4_2(const ARMISARegisters *id) +{ + unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2); + return t >= 2 || (t == 0 && isar_feature_aa64_tgran4(id)); +} + +static inline bool isar_feature_aa64_tgran16_2(const ARMISARegisters *id) +{ + unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2); + return t >= 2 || (t == 0 && isar_feature_aa64_tgran16(id)); +} + +static inline bool isar_feature_aa64_tgran64_2(const ARMISARegisters *id) +{ + unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN64_2); + return t >= 2 || (t == 0 && isar_feature_aa64_tgran64(id)); +} + static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0; @@ -4211,14 +4256,19 @@ static inline bool isar_feature_any_predinv(const ARMISARegisters *id) return isar_feature_aa64_predinv(id) || isar_feature_aa32_predinv(id); } -static inline bool isar_feature_any_pmu_8_1(const ARMISARegisters *id) +static inline bool isar_feature_any_pmuv3p1(const ARMISARegisters *id) { - return isar_feature_aa64_pmu_8_1(id) || isar_feature_aa32_pmu_8_1(id); + return isar_feature_aa64_pmuv3p1(id) || isar_feature_aa32_pmuv3p1(id); } -static inline bool isar_feature_any_pmu_8_4(const ARMISARegisters *id) +static inline bool isar_feature_any_pmuv3p4(const ARMISARegisters *id) { - return isar_feature_aa64_pmu_8_4(id) || isar_feature_aa32_pmu_8_4(id); + return isar_feature_aa64_pmuv3p4(id) || isar_feature_aa32_pmuv3p4(id); +} + +static inline bool isar_feature_any_pmuv3p5(const ARMISARegisters *id) +{ + return isar_feature_aa64_pmuv3p5(id) || isar_feature_aa32_pmuv3p5(id); } static inline bool isar_feature_any_ccidx(const ARMISARegisters *id) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 78e27f778a..85e0d1daf1 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -36,12 +36,11 @@ #include "hw/qdev-properties.h" #include "internals.h" - -static void aarch64_a57_initfn(Object *obj) +static void aarch64_a35_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - cpu->dtb_compatible = "arm,cortex-a57"; + cpu->dtb_compatible = "arm,cortex-a35"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); @@ -50,20 +49,16 @@ static void aarch64_a57_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_EL2); set_feature(&cpu->env, ARM_FEATURE_EL3); set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57; - cpu->midr = 0x411fd070; - cpu->revidr = 0x00000000; - cpu->reset_fpsid = 0x41034070; - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x12111111; - cpu->isar.mvfr2 = 0x00000043; - cpu->ctr = 0x8444c004; - cpu->reset_sctlr = 0x00c50838; + + /* From B2.2 AArch64 identification registers. */ + cpu->midr = 0x411fd040; + cpu->revidr = 0; + cpu->ctr = 0x84448004; cpu->isar.id_pfr0 = 0x00000131; cpu->isar.id_pfr1 = 0x00011011; cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x10101105; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x10201105; cpu->isar.id_mmfr1 = 0x40000000; cpu->isar.id_mmfr2 = 0x01260000; cpu->isar.id_mmfr3 = 0x02102211; @@ -73,277 +68,54 @@ static void aarch64_a57_initfn(Object *obj) cpu->isar.id_isar3 = 0x01112131; cpu->isar.id_isar4 = 0x00011142; cpu->isar.id_isar5 = 0x00011121; - cpu->isar.id_isar6 = 0; cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64pfr1 = 0; cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64dfr1 = 0; cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001124; - cpu->isar.dbgdidr = 0x3516d000; - cpu->isar.dbgdevid = 0x01110f13; - cpu->isar.dbgdevid1 = 0x2; - cpu->isar.reset_pmcr_el0 = 0x41013000; + cpu->isar.id_aa64isar1 = 0; + cpu->isar.id_aa64mmfr0 = 0x00101122; + cpu->isar.id_aa64mmfr1 = 0; cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ - cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */ - cpu->dcz_blocksize = 4; /* 64 bytes */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - define_cortex_a72_a57_a53_cp_reginfo(cpu); -} + cpu->dcz_blocksize = 4; -static void aarch64_a53_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a53"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53; - cpu->midr = 0x410fd034; - cpu->revidr = 0x00000000; - cpu->reset_fpsid = 0x41034070; - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x12111111; - cpu->isar.mvfr2 = 0x00000043; - cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + /* From B2.4 AArch64 Virtual Memory control registers */ cpu->reset_sctlr = 0x00c50838; - cpu->isar.id_pfr0 = 0x00000131; - cpu->isar.id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x10101105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00011142; - cpu->isar.id_isar5 = 0x00011121; - cpu->isar.id_isar6 = 0; - cpu->isar.id_aa64pfr0 = 0x00002222; - cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ - cpu->isar.dbgdidr = 0x3516d000; - cpu->isar.dbgdevid = 0x00110f13; - cpu->isar.dbgdevid1 = 0x1; - cpu->isar.reset_pmcr_el0 = 0x41033000; - cpu->clidr = 0x0a200023; + + /* From B2.10 AArch64 performance monitor registers */ + cpu->isar.reset_pmcr_el0 = 0x410a3000; + + /* From B2.29 Cache ID registers */ cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ - cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */ - cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->ccsidr[2] = 0x703fe03a; /* 512KB L2 cache */ + + /* From B3.5 VGIC Type register */ cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; cpu->gic_pribits = 5; - define_cortex_a72_a57_a53_cp_reginfo(cpu); -} -static void aarch64_a72_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); + /* From C6.4 Debug ID Register */ + cpu->isar.dbgdidr = 0x3516d000; + /* From C6.5 Debug Device ID Register */ + cpu->isar.dbgdevid = 0x00110f13; + /* From C6.6 Debug Device ID Register 1 */ + cpu->isar.dbgdevid1 = 0x2; - cpu->dtb_compatible = "arm,cortex-a72"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->midr = 0x410fd083; - cpu->revidr = 0x00000000; - cpu->reset_fpsid = 0x41034080; + /* From Cortex-A35 SIMD and Floating-point Support r1p0 */ + /* From 3.2 AArch32 register summary */ + cpu->reset_fpsid = 0x41034043; + + /* From 2.2 AArch64 register summary */ cpu->isar.mvfr0 = 0x10110222; cpu->isar.mvfr1 = 0x12111111; cpu->isar.mvfr2 = 0x00000043; - cpu->ctr = 0x8444c004; - cpu->reset_sctlr = 0x00c50838; - cpu->isar.id_pfr0 = 0x00000131; - cpu->isar.id_pfr1 = 0x00011011; - cpu->isar.id_dfr0 = 0x03010066; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02102211; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00011142; - cpu->isar.id_isar5 = 0x00011121; - cpu->isar.id_aa64pfr0 = 0x00002222; - cpu->isar.id_aa64dfr0 = 0x10305106; - cpu->isar.id_aa64isar0 = 0x00011120; - cpu->isar.id_aa64mmfr0 = 0x00001124; - cpu->isar.dbgdidr = 0x3516d000; - cpu->isar.dbgdevid = 0x01110f13; - cpu->isar.dbgdevid1 = 0x2; - cpu->isar.reset_pmcr_el0 = 0x41023000; - cpu->clidr = 0x0a200023; - cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ - cpu->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */ - cpu->dcz_blocksize = 4; /* 64 bytes */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; + + /* These values are the same with A53/A57/A72. */ define_cortex_a72_a57_a53_cp_reginfo(cpu); } -static void aarch64_a76_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,cortex-a76"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - - /* Ordered by B2.4 AArch64 registers by functional group */ - cpu->clidr = 0x82000023; - cpu->ctr = 0x8444C004; - cpu->dcz_blocksize = 4; - cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; - cpu->isar.id_aa64isar0 = 0x0000100010211120ull; - cpu->isar.id_aa64isar1 = 0x0000000000100001ull; - cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; - cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; - cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; - cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ - cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_dfr0 = 0x04010088; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00010142; - cpu->isar.id_isar5 = 0x01011121; - cpu->isar.id_isar6 = 0x00000010; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02122211; - cpu->isar.id_mmfr4 = 0x00021110; - cpu->isar.id_pfr0 = 0x10010131; - cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ - cpu->isar.id_pfr2 = 0x00000011; - cpu->midr = 0x414fd0b1; /* r4p1 */ - cpu->revidr = 0; - - /* From B2.18 CCSIDR_EL1 */ - cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ - cpu->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */ - - /* From B2.93 SCTLR_EL3 */ - cpu->reset_sctlr = 0x30c50838; - - /* From B4.23 ICH_VTR_EL2 */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - - /* From B5.1 AdvSIMD AArch64 register summary */ - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x13211111; - cpu->isar.mvfr2 = 0x00000043; - - /* From D5.1 AArch64 PMU register summary */ - cpu->isar.reset_pmcr_el0 = 0x410b3000; -} - -static void aarch64_neoverse_n1_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,neoverse-n1"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - - /* Ordered by B2.4 AArch64 registers by functional group */ - cpu->clidr = 0x82000023; - cpu->ctr = 0x8444c004; - cpu->dcz_blocksize = 4; - cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; - cpu->isar.id_aa64isar0 = 0x0000100010211120ull; - cpu->isar.id_aa64isar1 = 0x0000000000100001ull; - cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; - cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; - cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; - cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ - cpu->isar.id_aa64pfr1 = 0x0000000000000020ull; - cpu->id_afr0 = 0x00000000; - cpu->isar.id_dfr0 = 0x04010088; - cpu->isar.id_isar0 = 0x02101110; - cpu->isar.id_isar1 = 0x13112111; - cpu->isar.id_isar2 = 0x21232042; - cpu->isar.id_isar3 = 0x01112131; - cpu->isar.id_isar4 = 0x00010142; - cpu->isar.id_isar5 = 0x01011121; - cpu->isar.id_isar6 = 0x00000010; - cpu->isar.id_mmfr0 = 0x10201105; - cpu->isar.id_mmfr1 = 0x40000000; - cpu->isar.id_mmfr2 = 0x01260000; - cpu->isar.id_mmfr3 = 0x02122211; - cpu->isar.id_mmfr4 = 0x00021110; - cpu->isar.id_pfr0 = 0x10010131; - cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ - cpu->isar.id_pfr2 = 0x00000011; - cpu->midr = 0x414fd0c1; /* r4p1 */ - cpu->revidr = 0; - - /* From B2.23 CCSIDR_EL1 */ - cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ - cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ - cpu->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */ - - /* From B2.98 SCTLR_EL3 */ - cpu->reset_sctlr = 0x30c50838; - - /* From B4.23 ICH_VTR_EL2 */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - - /* From B5.1 AdvSIMD AArch64 register summary */ - cpu->isar.mvfr0 = 0x10110222; - cpu->isar.mvfr1 = 0x13211111; - cpu->isar.mvfr2 = 0x00000043; - - /* From D5.1 AArch64 PMU register summary */ - cpu->isar.reset_pmcr_el0 = 0x410c3000; -} - void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { /* @@ -906,6 +678,362 @@ void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) cpu->isar.id_aa64mmfr0 = t; } +static void aarch64_a57_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a57"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57; + cpu->midr = 0x411fd070; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034070; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x12111111; + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; + cpu->isar.id_pfr0 = 0x00000131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001124; + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x2; + cpu->isar.reset_pmcr_el0 = 0x41013000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + define_cortex_a72_a57_a53_cp_reginfo(cpu); +} + +static void aarch64_a53_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a53"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53; + cpu->midr = 0x410fd034; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034070; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x12111111; + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->reset_sctlr = 0x00c50838; + cpu->isar.id_pfr0 = 0x00000131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x00110f13; + cpu->isar.dbgdevid1 = 0x1; + cpu->isar.reset_pmcr_el0 = 0x41033000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ + cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + define_cortex_a72_a57_a53_cp_reginfo(cpu); +} + +static void aarch64_a72_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a72"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x410fd083; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034080; + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x12111111; + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; + cpu->isar.id_pfr0 = 0x00000131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64isar0 = 0x00011120; + cpu->isar.id_aa64mmfr0 = 0x00001124; + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x2; + cpu->isar.reset_pmcr_el0 = 0x41023000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ + cpu->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + define_cortex_a72_a57_a53_cp_reginfo(cpu); +} + +static void aarch64_a76_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a76"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444C004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x414fd0b1; /* r4p1 */ + cpu->revidr = 0; + + /* From B2.18 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */ + + /* From B2.93 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.23 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + /* From B5.1 AdvSIMD AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + + /* From D5.1 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410b3000; +} + +static void aarch64_a64fx_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,a64fx"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x461f0010; + cpu->revidr = 0x00000000; + cpu->ctr = 0x86668006; + cpu->reset_sctlr = 0x30000180; + cpu->isar.id_aa64pfr0 = 0x0000000101111111; /* No RAS Extensions */ + cpu->isar.id_aa64pfr1 = 0x0000000000000000; + cpu->isar.id_aa64dfr0 = 0x0000000010305408; + cpu->isar.id_aa64dfr1 = 0x0000000000000000; + cpu->id_aa64afr0 = 0x0000000000000000; + cpu->id_aa64afr1 = 0x0000000000000000; + cpu->isar.id_aa64mmfr0 = 0x0000000000001122; + cpu->isar.id_aa64mmfr1 = 0x0000000011212100; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011; + cpu->isar.id_aa64isar0 = 0x0000000010211120; + cpu->isar.id_aa64isar1 = 0x0000000000010001; + cpu->isar.id_aa64zfr0 = 0x0000000000000000; + cpu->clidr = 0x0000000080000023; + cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe07c; /* 8MB L2 cache */ + cpu->dcz_blocksize = 6; /* 256 bytes */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + /* The A64FX supports only 128, 256 and 512 bit vector lengths */ + aarch64_add_sve_properties(obj); + cpu->sve_vq.supported = (1 << 0) /* 128bit */ + | (1 << 1) /* 256bit */ + | (1 << 3); /* 512bit */ + + cpu->isar.reset_pmcr_el0 = 0x46014040; + + /* TODO: Add A64FX specific HPC extension registers */ +} + +static void aarch64_neoverse_n1_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,neoverse-n1"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444c004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000020ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00010142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x414fd0c1; /* r4p1 */ + cpu->revidr = 0; + + /* From B2.23 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */ + cpu->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */ + + /* From B2.98 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.23 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + /* From B5.1 AdvSIMD AArch64 register summary */ + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + + /* From D5.1 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410c3000; +} + static void aarch64_host_initfn(Object *obj) { #if defined(CONFIG_KVM) @@ -1043,6 +1171,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */ t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* FEAT_PAN2 */ t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */ + t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 1); /* FEAT_ETS */ t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ cpu->isar.id_aa64mmfr1 = t; @@ -1072,7 +1201,7 @@ static void aarch64_max_initfn(Object *obj) t = cpu->isar.id_aa64dfr0; t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ - t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* FEAT_PMUv3p4 */ + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* FEAT_PMUv3p5 */ cpu->isar.id_aa64dfr0 = t; t = cpu->isar.id_aa64smfr0; @@ -1108,56 +1237,8 @@ static void aarch64_max_initfn(Object *obj) qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property); } -static void aarch64_a64fx_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - - cpu->dtb_compatible = "arm,a64fx"; - set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_NEON); - set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - set_feature(&cpu->env, ARM_FEATURE_EL2); - set_feature(&cpu->env, ARM_FEATURE_EL3); - set_feature(&cpu->env, ARM_FEATURE_PMU); - cpu->midr = 0x461f0010; - cpu->revidr = 0x00000000; - cpu->ctr = 0x86668006; - cpu->reset_sctlr = 0x30000180; - cpu->isar.id_aa64pfr0 = 0x0000000101111111; /* No RAS Extensions */ - cpu->isar.id_aa64pfr1 = 0x0000000000000000; - cpu->isar.id_aa64dfr0 = 0x0000000010305408; - cpu->isar.id_aa64dfr1 = 0x0000000000000000; - cpu->id_aa64afr0 = 0x0000000000000000; - cpu->id_aa64afr1 = 0x0000000000000000; - cpu->isar.id_aa64mmfr0 = 0x0000000000001122; - cpu->isar.id_aa64mmfr1 = 0x0000000011212100; - cpu->isar.id_aa64mmfr2 = 0x0000000000001011; - cpu->isar.id_aa64isar0 = 0x0000000010211120; - cpu->isar.id_aa64isar1 = 0x0000000000010001; - cpu->isar.id_aa64zfr0 = 0x0000000000000000; - cpu->clidr = 0x0000000080000023; - cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */ - cpu->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */ - cpu->ccsidr[2] = 0x70ffe07c; /* 8MB L2 cache */ - cpu->dcz_blocksize = 6; /* 256 bytes */ - cpu->gic_num_lrs = 4; - cpu->gic_vpribits = 5; - cpu->gic_vprebits = 5; - cpu->gic_pribits = 5; - - /* The A64FX supports only 128, 256 and 512 bit vector lengths */ - aarch64_add_sve_properties(obj); - cpu->sve_vq.supported = (1 << 0) /* 128bit */ - | (1 << 1) /* 256bit */ - | (1 << 3); /* 512bit */ - - cpu->isar.reset_pmcr_el0 = 0x46014040; - - /* TODO: Add A64FX specific HPC extension registers */ -} - static const ARMCPUInfo aarch64_cpus[] = { + { .name = "cortex-a35", .initfn = aarch64_a35_initfn }, { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 3099b38e32..98b5ba2160 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -64,9 +64,13 @@ void aa32_max_features(ARMCPU *cpu) t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* FEAT_AA32HPD */ t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */ - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX*/ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */ cpu->isar.id_mmfr4 = t; + t = cpu->isar.id_mmfr5; + t = FIELD_DP32(t, ID_MMFR5, ETS, 1); /* FEAT_ETS */ + cpu->isar.id_mmfr5 = t; + t = cpu->isar.id_pfr0; t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CVS2 */ t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ @@ -81,7 +85,7 @@ void aa32_max_features(ARMCPU *cpu) t = cpu->isar.id_dfr0; t = FIELD_DP32(t, ID_DFR0, COPDBG, 9); /* FEAT_Debugv8p4 */ t = FIELD_DP32(t, ID_DFR0, COPSDBG, 9); /* FEAT_Debugv8p4 */ - t = FIELD_DP32(t, ID_DFR0, PERFMON, 5); /* FEAT_PMUv3p4 */ + t = FIELD_DP32(t, ID_DFR0, PERFMON, 6); /* FEAT_PMUv3p5 */ cpu->isar.id_dfr0 = t; } diff --git a/target/arm/helper.c b/target/arm/helper.c index 1a8b06410e..dde64a487a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -879,16 +879,16 @@ static int64_t instructions_ns_per(uint64_t icount) } #endif -static bool pmu_8_1_events_supported(CPUARMState *env) +static bool pmuv3p1_events_supported(CPUARMState *env) { /* For events which are supported in any v8.1 PMU */ - return cpu_isar_feature(any_pmu_8_1, env_archcpu(env)); + return cpu_isar_feature(any_pmuv3p1, env_archcpu(env)); } -static bool pmu_8_4_events_supported(CPUARMState *env) +static bool pmuv3p4_events_supported(CPUARMState *env) { /* For events which are supported in any v8.1 PMU */ - return cpu_isar_feature(any_pmu_8_4, env_archcpu(env)); + return cpu_isar_feature(any_pmuv3p4, env_archcpu(env)); } static uint64_t zero_event_get_count(CPUARMState *env) @@ -922,17 +922,17 @@ static const pm_event pm_events[] = { }, #endif { .number = 0x023, /* STALL_FRONTEND */ - .supported = pmu_8_1_events_supported, + .supported = pmuv3p1_events_supported, .get_count = zero_event_get_count, .ns_per_count = zero_event_ns_per, }, { .number = 0x024, /* STALL_BACKEND */ - .supported = pmu_8_1_events_supported, + .supported = pmuv3p1_events_supported, .get_count = zero_event_get_count, .ns_per_count = zero_event_ns_per, }, { .number = 0x03c, /* STALL */ - .supported = pmu_8_4_events_supported, + .supported = pmuv3p4_events_supported, .get_count = zero_event_get_count, .ns_per_count = zero_event_ns_per, }, @@ -1079,6 +1079,15 @@ static CPAccessResult pmreg_access_ccntr(CPUARMState *env, return pmreg_access(env, ri, isread); } +/* + * Bits in MDCR_EL2 and MDCR_EL3 which pmu_counter_enabled() looks at. + * We use these to decide whether we need to wrap a write to MDCR_EL2 + * or MDCR_EL3 in pmu_op_start()/pmu_op_finish() calls. + */ +#define MDCR_EL2_PMU_ENABLE_BITS \ + (MDCR_HPME | MDCR_HPMD | MDCR_HPMN | MDCR_HCCD | MDCR_HLP) +#define MDCR_EL3_PMU_ENABLE_BITS (MDCR_SPME | MDCR_SCCD) + /* Returns true if the counter (pass 31 for PMCCNTR) should count events using * the current EL, security state, and register configuration. */ @@ -1086,7 +1095,7 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter) { uint64_t filter; bool e, p, u, nsk, nsu, nsh, m; - bool enabled, prohibited, filtered; + bool enabled, prohibited = false, filtered; bool secure = arm_is_secure(env); int el = arm_current_el(env); uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); @@ -1104,19 +1113,29 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter) } enabled = e && (env->cp15.c9_pmcnten & (1 << counter)); - if (!secure) { - if (el == 2 && (counter < hpmn || counter == 31)) { - prohibited = mdcr_el2 & MDCR_HPMD; - } else { - prohibited = false; - } - } else { - prohibited = arm_feature(env, ARM_FEATURE_EL3) && - !(env->cp15.mdcr_el3 & MDCR_SPME); + /* Is event counting prohibited? */ + if (el == 2 && (counter < hpmn || counter == 31)) { + prohibited = mdcr_el2 & MDCR_HPMD; + } + if (secure) { + prohibited = prohibited || !(env->cp15.mdcr_el3 & MDCR_SPME); } - if (prohibited && counter == 31) { - prohibited = env->cp15.c9_pmcr & PMCRDP; + if (counter == 31) { + /* + * The cycle counter defaults to running. PMCR.DP says "disable + * the cycle counter when event counting is prohibited". + * Some MDCR bits disable the cycle counter specifically. + */ + prohibited = prohibited && env->cp15.c9_pmcr & PMCRDP; + if (cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { + if (secure) { + prohibited = prohibited || (env->cp15.mdcr_el3 & MDCR_SCCD); + } + if (el == 2) { + prohibited = prohibited || (mdcr_el2 & MDCR_HCCD); + } + } } if (counter == 31) { @@ -1164,6 +1183,43 @@ static void pmu_update_irq(CPUARMState *env) (env->cp15.c9_pminten & env->cp15.c9_pmovsr)); } +static bool pmccntr_clockdiv_enabled(CPUARMState *env) +{ + /* + * Return true if the clock divider is enabled and the cycle counter + * is supposed to tick only once every 64 clock cycles. This is + * controlled by PMCR.D, but if PMCR.LC is set to enable the long + * (64-bit) cycle counter PMCR.D has no effect. + */ + return (env->cp15.c9_pmcr & (PMCRD | PMCRLC)) == PMCRD; +} + +static bool pmevcntr_is_64_bit(CPUARMState *env, int counter) +{ + /* Return true if the specified event counter is configured to be 64 bit */ + + /* This isn't intended to be used with the cycle counter */ + assert(counter < 31); + + if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { + return false; + } + + if (arm_feature(env, ARM_FEATURE_EL2)) { + /* + * MDCR_EL2.HLP still applies even when EL2 is disabled in the + * current security state, so we don't use arm_mdcr_el2_eff() here. + */ + bool hlp = env->cp15.mdcr_el2 & MDCR_HLP; + int hpmn = env->cp15.mdcr_el2 & MDCR_HPMN; + + if (hpmn != 0 && counter >= hpmn) { + return hlp; + } + } + return env->cp15.c9_pmcr & PMCRLP; +} + /* * Ensure c15_ccnt is the guest-visible count so that operations such as * enabling/disabling the counter or filtering, modifying the count itself, @@ -1176,8 +1232,7 @@ static void pmccntr_op_start(CPUARMState *env) if (pmu_counter_enabled(env, 31)) { uint64_t eff_cycles = cycles; - if (env->cp15.c9_pmcr & PMCRD) { - /* Increment once every 64 processor clock cycles */ + if (pmccntr_clockdiv_enabled(env)) { eff_cycles /= 64; } @@ -1186,7 +1241,7 @@ static void pmccntr_op_start(CPUARMState *env) uint64_t overflow_mask = env->cp15.c9_pmcr & PMCRLC ? \ 1ull << 63 : 1ull << 31; if (env->cp15.c15_ccnt & ~new_pmccntr & overflow_mask) { - env->cp15.c9_pmovsr |= (1 << 31); + env->cp15.c9_pmovsr |= (1ULL << 31); pmu_update_irq(env); } @@ -1212,16 +1267,18 @@ static void pmccntr_op_finish(CPUARMState *env) int64_t overflow_in = cycles_ns_per(remaining_cycles); if (overflow_in > 0) { - int64_t overflow_at = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - overflow_in; - ARMCPU *cpu = env_archcpu(env); - timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); + int64_t overflow_at; + + if (!sadd64_overflow(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + overflow_in, &overflow_at)) { + ARMCPU *cpu = env_archcpu(env); + timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); + } } #endif uint64_t prev_cycles = env->cp15.c15_ccnt_delta; - if (env->cp15.c9_pmcr & PMCRD) { - /* Increment once every 64 processor clock cycles */ + if (pmccntr_clockdiv_enabled(env)) { prev_cycles /= 64; } env->cp15.c15_ccnt_delta = prev_cycles - env->cp15.c15_ccnt; @@ -1239,9 +1296,11 @@ static void pmevcntr_op_start(CPUARMState *env, uint8_t counter) } if (pmu_counter_enabled(env, counter)) { - uint32_t new_pmevcntr = count - env->cp15.c14_pmevcntr_delta[counter]; + uint64_t new_pmevcntr = count - env->cp15.c14_pmevcntr_delta[counter]; + uint64_t overflow_mask = pmevcntr_is_64_bit(env, counter) ? + 1ULL << 63 : 1ULL << 31; - if (env->cp15.c14_pmevcntr[counter] & ~new_pmevcntr & INT32_MIN) { + if (env->cp15.c14_pmevcntr[counter] & ~new_pmevcntr & overflow_mask) { env->cp15.c9_pmovsr |= (1 << counter); pmu_update_irq(env); } @@ -1256,15 +1315,22 @@ static void pmevcntr_op_finish(CPUARMState *env, uint8_t counter) #ifndef CONFIG_USER_ONLY uint16_t event = env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_EVTCOUNT; uint16_t event_idx = supported_event_map[event]; - uint64_t delta = UINT32_MAX - - (uint32_t)env->cp15.c14_pmevcntr[counter] + 1; - int64_t overflow_in = pm_events[event_idx].ns_per_count(delta); + uint64_t delta = -(env->cp15.c14_pmevcntr[counter] + 1); + int64_t overflow_in; + + if (!pmevcntr_is_64_bit(env, counter)) { + delta = (uint32_t)delta; + } + overflow_in = pm_events[event_idx].ns_per_count(delta); if (overflow_in > 0) { - int64_t overflow_at = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - overflow_in; - ARMCPU *cpu = env_archcpu(env); - timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); + int64_t overflow_at; + + if (!sadd64_overflow(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + overflow_in, &overflow_at)) { + ARMCPU *cpu = env_archcpu(env); + timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); + } } #endif @@ -1342,6 +1408,8 @@ static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { unsigned int i; + uint64_t overflow_mask, new_pmswinc; + for (i = 0; i < pmu_num_counters(env); i++) { /* Increment a counter's count iff: */ if ((value & (1 << i)) && /* counter's bit is set */ @@ -1355,9 +1423,12 @@ static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri, * Detect if this write causes an overflow since we can't predict * PMSWINC overflows like we can for other events */ - uint32_t new_pmswinc = env->cp15.c14_pmevcntr[i] + 1; + new_pmswinc = env->cp15.c14_pmevcntr[i] + 1; - if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & INT32_MIN) { + overflow_mask = pmevcntr_is_64_bit(env, i) ? + 1ULL << 63 : 1ULL << 31; + + if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & overflow_mask) { env->cp15.c9_pmovsr |= (1 << i); pmu_update_irq(env); } @@ -1432,15 +1503,19 @@ static uint64_t pmccfiltr_read_a32(CPUARMState *env, const ARMCPRegInfo *ri) static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + pmu_op_start(env); value &= pmu_counter_mask(env); env->cp15.c9_pmcnten |= value; + pmu_op_finish(env); } static void pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + pmu_op_start(env); value &= pmu_counter_mask(env); env->cp15.c9_pmcnten &= ~value; + pmu_op_finish(env); } static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -1560,6 +1635,10 @@ static uint64_t pmxevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri) static void pmevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value, uint8_t counter) { + if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { + /* Before FEAT_PMUv3p5, top 32 bits of event counters are RES0 */ + value &= MAKE_64BIT_MASK(0, 32); + } if (counter < pmu_num_counters(env)) { pmevcntr_op_start(env, counter); env->cp15.c14_pmevcntr[counter] = value; @@ -1579,6 +1658,10 @@ static uint64_t pmevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri, pmevcntr_op_start(env, counter); ret = env->cp15.c14_pmevcntr[counter]; pmevcntr_op_finish(env, counter); + if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { + /* Before FEAT_PMUv3p5, top 32 bits of event counters are RES0 */ + ret &= MAKE_64BIT_MASK(0, 32); + } return ret; } else { /* We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR @@ -1669,8 +1752,9 @@ static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri, static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { /* Begin with base v8.0 state. */ - uint32_t valid_mask = 0x3fff; + uint64_t valid_mask = 0x3fff; ARMCPU *cpu = env_archcpu(env); + uint64_t changed; /* * Because SCR_EL3 is the "real" cpreg and SCR is the alias, reset always @@ -1706,6 +1790,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_doublefault, cpu)) { valid_mask |= SCR_EASE | SCR_NMEA; } + if (cpu_isar_feature(aa64_sme, cpu)) { + valid_mask |= SCR_ENTP2; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); if (cpu_isar_feature(aa32_ras, cpu)) { @@ -1730,7 +1817,22 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) /* Clear all-context RES0 bits. */ value &= valid_mask; - raw_write(env, ri, value); + changed = env->cp15.scr_el3 ^ value; + env->cp15.scr_el3 = value; + + /* + * If SCR_EL3.NS changes, i.e. arm_is_secure_below_el3, then + * we must invalidate all TLBs below EL3. + */ + if (changed & SCR_NS) { + tlb_flush_by_mmuidx(env_cpu(env), (ARMMMUIdxBit_E10_0 | + ARMMMUIdxBit_E20_0 | + ARMMMUIdxBit_E10_1 | + ARMMMUIdxBit_E20_2 | + ARMMMUIdxBit_E10_1_PAN | + ARMMMUIdxBit_E20_2_PAN | + ARMMMUIdxBit_E2)); + } } static void scr_reset(CPUARMState *env, const ARMCPRegInfo *ri) @@ -1844,12 +1946,12 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { * or PL0_RO as appropriate and then check PMUSERENR in the helper fn. */ { .name = "PMCNTENSET", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 1, - .access = PL0_RW, .type = ARM_CP_ALIAS, + .access = PL0_RW, .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmcnten), .writefn = pmcntenset_write, .accessfn = pmreg_access, .raw_writefn = raw_write }, - { .name = "PMCNTENSET_EL0", .state = ARM_CP_STATE_AA64, + { .name = "PMCNTENSET_EL0", .state = ARM_CP_STATE_AA64, .type = ARM_CP_IO, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 1, .access = PL0_RW, .accessfn = pmreg_access, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten), .resetvalue = 0, @@ -1859,11 +1961,11 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmcnten), .accessfn = pmreg_access, .writefn = pmcntenclr_write, - .type = ARM_CP_ALIAS }, + .type = ARM_CP_ALIAS | ARM_CP_IO }, { .name = "PMCNTENCLR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 2, .access = PL0_RW, .accessfn = pmreg_access, - .type = ARM_CP_ALIAS, + .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten), .writefn = pmcntenclr_write }, { .name = "PMOVSR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 3, @@ -2561,9 +2663,6 @@ static int gt_phys_redir_timeridx(CPUARMState *env) case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: - case ARMMMUIdx_SE20_0: - case ARMMMUIdx_SE20_2: - case ARMMMUIdx_SE20_2_PAN: return GTIMER_HYP; default: return GTIMER_PHYS; @@ -2576,9 +2675,6 @@ static int gt_virt_redir_timeridx(CPUARMState *env) case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: - case ARMMMUIdx_SE20_0: - case ARMMMUIdx_SE20_2: - case ARMMMUIdx_SE20_2_PAN: return GTIMER_HYPVIRT; default: return GTIMER_VIRT; @@ -3105,26 +3201,23 @@ static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri, #ifdef CONFIG_TCG static uint64_t do_ats_write(CPUARMState *env, uint64_t value, - MMUAccessType access_type, ARMMMUIdx mmu_idx) + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool is_secure) { - hwaddr phys_addr; - target_ulong page_size; - int prot; bool ret; uint64_t par64; bool format64 = false; - MemTxAttrs attrs = {}; ARMMMUFaultInfo fi = {}; - ARMCacheAttrs cacheattrs = {}; + GetPhysAddrResult res = {}; - ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, - &prot, &page_size, &fi, &cacheattrs); + ret = get_phys_addr_with_secure(env, value, access_type, mmu_idx, + is_secure, &res, &fi); /* * ATS operations only do S1 or S1+S2 translations, so we never * have to deal with the ARMCacheAttrs format for S2 only. */ - assert(!cacheattrs.is_s2_format); + assert(!res.cacheattrs.is_s2_format); if (ret) { /* @@ -3230,12 +3323,12 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, /* Create a 64-bit PAR */ par64 = (1 << 11); /* LPAE bit always set */ if (!ret) { - par64 |= phys_addr & ~0xfffULL; - if (!attrs.secure) { + par64 |= res.f.phys_addr & ~0xfffULL; + if (!res.f.attrs.secure) { par64 |= (1 << 9); /* NS */ } - par64 |= (uint64_t)cacheattrs.attrs << 56; /* ATTR */ - par64 |= cacheattrs.shareability << 7; /* SH */ + par64 |= (uint64_t)res.cacheattrs.attrs << 56; /* ATTR */ + par64 |= res.cacheattrs.shareability << 7; /* SH */ } else { uint32_t fsr = arm_fi_to_lfsc(&fi); @@ -3255,13 +3348,13 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, */ if (!ret) { /* We do not set any attribute bits in the PAR */ - if (page_size == (1 << 24) + if (res.f.lg_page_size == 24 && arm_feature(env, ARM_FEATURE_V7)) { - par64 = (phys_addr & 0xff000000) | (1 << 1); + par64 = (res.f.phys_addr & 0xff000000) | (1 << 1); } else { - par64 = phys_addr & 0xfffff000; + par64 = res.f.phys_addr & 0xfffff000; } - if (!attrs.secure) { + if (!res.f.attrs.secure) { par64 |= (1 << 9); /* NS */ } } else { @@ -3289,17 +3382,17 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) /* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */ switch (el) { case 3: - mmu_idx = ARMMMUIdx_SE3; + mmu_idx = ARMMMUIdx_E3; + secure = true; break; case 2: g_assert(!secure); /* ARMv8.4-SecEL2 is 64-bit only */ /* fall through */ case 1: if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) { - mmu_idx = (secure ? ARMMMUIdx_Stage1_SE1_PAN - : ARMMMUIdx_Stage1_E1_PAN); + mmu_idx = ARMMMUIdx_Stage1_E1_PAN; } else { - mmu_idx = secure ? ARMMMUIdx_Stage1_SE1 : ARMMMUIdx_Stage1_E1; + mmu_idx = ARMMMUIdx_Stage1_E1; } break; default: @@ -3310,14 +3403,15 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) /* stage 1 current state PL0: ATS1CUR, ATS1CUW */ switch (el) { case 3: - mmu_idx = ARMMMUIdx_SE10_0; + mmu_idx = ARMMMUIdx_E10_0; + secure = true; break; case 2: g_assert(!secure); /* ARMv8.4-SecEL2 is 64-bit only */ mmu_idx = ARMMMUIdx_Stage1_E0; break; case 1: - mmu_idx = secure ? ARMMMUIdx_Stage1_SE0 : ARMMMUIdx_Stage1_E0; + mmu_idx = ARMMMUIdx_Stage1_E0; break; default: g_assert_not_reached(); @@ -3326,16 +3420,18 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) case 4: /* stage 1+2 NonSecure PL1: ATS12NSOPR, ATS12NSOPW */ mmu_idx = ARMMMUIdx_E10_1; + secure = false; break; case 6: /* stage 1+2 NonSecure PL0: ATS12NSOUR, ATS12NSOUW */ mmu_idx = ARMMMUIdx_E10_0; + secure = false; break; default: g_assert_not_reached(); } - par64 = do_ats_write(env, value, access_type, mmu_idx); + par64 = do_ats_write(env, value, access_type, mmu_idx, secure); A32_BANKED_CURRENT_REG_SET(env, par, par64); #else @@ -3351,7 +3447,8 @@ static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri, MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD; uint64_t par64; - par64 = do_ats_write(env, value, access_type, ARMMMUIdx_E2); + /* There is no SecureEL2 for AArch32. */ + par64 = do_ats_write(env, value, access_type, ARMMMUIdx_E2, false); A32_BANKED_CURRENT_REG_SET(env, par, par64); #else @@ -3383,36 +3480,37 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, switch (ri->opc1) { case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */ if (ri->crm == 9 && (env->pstate & PSTATE_PAN)) { - mmu_idx = (secure ? ARMMMUIdx_Stage1_SE1_PAN - : ARMMMUIdx_Stage1_E1_PAN); + mmu_idx = ARMMMUIdx_Stage1_E1_PAN; } else { - mmu_idx = secure ? ARMMMUIdx_Stage1_SE1 : ARMMMUIdx_Stage1_E1; + mmu_idx = ARMMMUIdx_Stage1_E1; } break; case 4: /* AT S1E2R, AT S1E2W */ - mmu_idx = secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2; + mmu_idx = ARMMMUIdx_E2; break; case 6: /* AT S1E3R, AT S1E3W */ - mmu_idx = ARMMMUIdx_SE3; + mmu_idx = ARMMMUIdx_E3; + secure = true; break; default: g_assert_not_reached(); } break; case 2: /* AT S1E0R, AT S1E0W */ - mmu_idx = secure ? ARMMMUIdx_Stage1_SE0 : ARMMMUIdx_Stage1_E0; + mmu_idx = ARMMMUIdx_Stage1_E0; break; case 4: /* AT S12E1R, AT S12E1W */ - mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_E10_1; + mmu_idx = ARMMMUIdx_E10_1; break; case 6: /* AT S12E0R, AT S12E0W */ - mmu_idx = secure ? ARMMMUIdx_SE10_0 : ARMMMUIdx_E10_0; + mmu_idx = ARMMMUIdx_E10_0; break; default: g_assert_not_reached(); } - env->cp15.par_el[1] = do_ats_write(env, value, access_type, mmu_idx); + env->cp15.par_el[1] = do_ats_write(env, value, access_type, + mmu_idx, secure); #else /* Handled by hardware accelerator. */ g_assert_not_reached(); @@ -3675,11 +3773,6 @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, uint16_t mask = ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_E20_2_PAN | ARMMMUIdxBit_E20_0; - - if (arm_is_secure_below_el3(env)) { - mask >>= ARM_MMU_IDX_A_NS; - } - tlb_flush_by_mmuidx(env_cpu(env), mask); } raw_write(env, ri, value); @@ -3699,11 +3792,6 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint16_t mask = ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_1_PAN | ARMMMUIdxBit_E10_0; - - if (arm_is_secure_below_el3(env)) { - mask >>= ARM_MMU_IDX_A_NS; - } - tlb_flush_by_mmuidx(cs, mask); raw_write(env, ri, value); } @@ -3898,7 +3986,7 @@ static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = { }; static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = { - /* We never have a a block transfer operation in progress */ + /* We never have a block transfer operation in progress */ { .name = "BXSR", .cp = 15, .crn = 7, .crm = 12, .opc1 = 0, .opc2 = 4, .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_NO_RAW, .resetvalue = 0 }, @@ -4174,11 +4262,6 @@ static int vae1_tlbmask(CPUARMState *env) ARMMMUIdxBit_E10_1_PAN | ARMMMUIdxBit_E10_0; } - - if (arm_is_secure_below_el3(env)) { - mask >>= ARM_MMU_IDX_A_NS; - } - return mask; } @@ -4205,10 +4288,6 @@ static int vae1_tlbbits(CPUARMState *env, uint64_t addr) mmu_idx = ARMMMUIdx_E10_0; } - if (arm_is_secure_below_el3(env)) { - mmu_idx &= ~ARM_MMU_IDX_A_NS; - } - return tlbbits_for_regime(env, mmu_idx, addr); } @@ -4241,30 +4320,17 @@ static int alle1_tlbmask(CPUARMState *env) * stage 2 translations, whereas most other scopes only invalidate * stage 1 translations. */ - if (arm_is_secure_below_el3(env)) { - return ARMMMUIdxBit_SE10_1 | - ARMMMUIdxBit_SE10_1_PAN | - ARMMMUIdxBit_SE10_0; - } else { - return ARMMMUIdxBit_E10_1 | - ARMMMUIdxBit_E10_1_PAN | - ARMMMUIdxBit_E10_0; - } + return (ARMMMUIdxBit_E10_1 | + ARMMMUIdxBit_E10_1_PAN | + ARMMMUIdxBit_E10_0); } static int e2_tlbmask(CPUARMState *env) { - if (arm_is_secure_below_el3(env)) { - return ARMMMUIdxBit_SE20_0 | - ARMMMUIdxBit_SE20_2 | - ARMMMUIdxBit_SE20_2_PAN | - ARMMMUIdxBit_SE2; - } else { - return ARMMMUIdxBit_E20_0 | - ARMMMUIdxBit_E20_2 | - ARMMMUIdxBit_E20_2_PAN | - ARMMMUIdxBit_E2; - } + return (ARMMMUIdxBit_E20_0 | + ARMMMUIdxBit_E20_2 | + ARMMMUIdxBit_E20_2_PAN | + ARMMMUIdxBit_E2); } static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -4291,7 +4357,7 @@ static void tlbi_aa64_alle3_write(CPUARMState *env, const ARMCPRegInfo *ri, ARMCPU *cpu = env_archcpu(env); CPUState *cs = CPU(cpu); - tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_SE3); + tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_E3); } static void tlbi_aa64_alle1is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -4317,7 +4383,7 @@ static void tlbi_aa64_alle3is_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = env_cpu(env); - tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_SE3); + tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_E3); } static void tlbi_aa64_vae2_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -4345,7 +4411,7 @@ static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri, CPUState *cs = CPU(cpu); uint64_t pageaddr = sextract64(value << 12, 0, 56); - tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_SE3); + tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_E3); } static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -4384,12 +4450,10 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = env_cpu(env); uint64_t pageaddr = sextract64(value << 12, 0, 56); - bool secure = arm_is_secure_below_el3(env); - int mask = secure ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2; - int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2, - pageaddr); + int bits = tlbbits_for_regime(env, ARMMMUIdx_E2, pageaddr); - tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits); + tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, + ARMMMUIdxBit_E2, bits); } static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -4397,10 +4461,10 @@ static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = env_cpu(env); uint64_t pageaddr = sextract64(value << 12, 0, 56); - int bits = tlbbits_for_regime(env, ARMMMUIdx_SE3, pageaddr); + int bits = tlbbits_for_regime(env, ARMMMUIdx_E3, pageaddr); tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, - ARMMMUIdxBit_SE3, bits); + ARMMMUIdxBit_E3, bits); } #ifdef TARGET_AARCH64 @@ -4409,6 +4473,24 @@ typedef struct { uint64_t length; } TLBIRange; +static ARMGranuleSize tlbi_range_tg_to_gran_size(int tg) +{ + /* + * Note that the TLBI range TG field encoding differs from both + * TG0 and TG1 encodings. + */ + switch (tg) { + case 1: + return Gran4K; + case 2: + return Gran16K; + case 3: + return Gran64K; + default: + return GranInvalid; + } +} + static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx, uint64_t value) { @@ -4417,17 +4499,19 @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx, uint64_t select = sextract64(value, 36, 1); ARMVAParameters param = aa64_va_parameters(env, select, mmuidx, true); TLBIRange ret = { }; + ARMGranuleSize gran; page_size_granule = extract64(value, 46, 2); + gran = tlbi_range_tg_to_gran_size(page_size_granule); /* The granule encoded in value must match the granule in use. */ - if (page_size_granule != (param.using64k ? 3 : param.using16k ? 2 : 1)) { + if (gran != param.gran) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid tlbi page size granule %d\n", page_size_granule); return ret; } - page_shift = (page_size_granule - 1) * 2 + 12; + page_shift = arm_granule_bits(gran); num = extract64(value, 39, 5); scale = extract64(value, 44, 2); exponent = (5 * scale) + 1; @@ -4506,8 +4590,7 @@ static void tlbi_aa64_rvae1is_write(CPUARMState *env, static int vae2_tlbmask(CPUARMState *env) { - return (arm_is_secure_below_el3(env) - ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2); + return ARMMMUIdxBit_E2; } static void tlbi_aa64_rvae2_write(CPUARMState *env, @@ -4553,8 +4636,7 @@ static void tlbi_aa64_rvae3_write(CPUARMState *env, * flush-last-level-only. */ - do_rvae_write(env, value, ARMMMUIdxBit_SE3, - tlb_force_broadcast(env)); + do_rvae_write(env, value, ARMMMUIdxBit_E3, tlb_force_broadcast(env)); } static void tlbi_aa64_rvae3is_write(CPUARMState *env, @@ -4568,7 +4650,7 @@ static void tlbi_aa64_rvae3is_write(CPUARMState *env, * flush-last-level-only or inner/outer specific flushes. */ - do_rvae_write(env, value, ARMMMUIdxBit_SE3, true); + do_rvae_write(env, value, ARMMMUIdxBit_E3, true); } #endif @@ -4678,10 +4760,49 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, } } +static void mdcr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* + * Some MDCR_EL3 bits affect whether PMU counters are running: + * if we are trying to change any of those then we must + * bracket this update with PMU start/finish calls. + */ + bool pmu_op = (env->cp15.mdcr_el3 ^ value) & MDCR_EL3_PMU_ENABLE_BITS; + + if (pmu_op) { + pmu_op_start(env); + } + env->cp15.mdcr_el3 = value; + if (pmu_op) { + pmu_op_finish(env); + } +} + static void sdcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - env->cp15.mdcr_el3 = value & SDCR_VALID_MASK; + /* Not all bits defined for MDCR_EL3 exist in the AArch32 SDCR */ + mdcr_el3_write(env, ri, value & SDCR_VALID_MASK); +} + +static void mdcr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* + * Some MDCR_EL2 bits affect whether PMU counters are running: + * if we are trying to change any of those then we must + * bracket this update with PMU start/finish calls. + */ + bool pmu_op = (env->cp15.mdcr_el2 ^ value) & MDCR_EL2_PMU_ENABLE_BITS; + + if (pmu_op) { + pmu_op_start(env); + } + env->cp15.mdcr_el2 = value; + if (pmu_op) { + pmu_op_finish(env); + } } static const ARMCPRegInfo v8_cp_reginfo[] = { @@ -4971,7 +5092,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .fieldoffset = offsetof(CPUARMState, sp_el[0]) }, { .name = "SP_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 1, .opc2 = 0, - .access = PL2_RW, .type = ARM_CP_ALIAS, + .access = PL2_RW, .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_KEEP, .fieldoffset = offsetof(CPUARMState, sp_el[1]) }, { .name = "SPSel", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0, @@ -5012,10 +5133,13 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_FIQ]) }, { .name = "MDCR_EL3", .state = ARM_CP_STATE_AA64, + .type = ARM_CP_IO, .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 3, .opc2 = 1, .resetvalue = 0, - .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el3) }, - { .name = "SDCR", .type = ARM_CP_ALIAS, + .access = PL3_RW, + .writefn = mdcr_el3_write, + .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el3) }, + { .name = "SDCR", .type = ARM_CP_ALIAS | ARM_CP_IO, .cp = 15, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 1, .access = PL1_RW, .accessfn = access_trap_aa32s_el1, .writefn = sdcr_write, @@ -5125,15 +5249,15 @@ static void hcr_writelow(CPUARMState *env, const ARMCPRegInfo *ri, } /* - * Return the effective value of HCR_EL2. + * Return the effective value of HCR_EL2, at the given security state. * Bits that are not included here: * RW (read from SCR_EL3.RW as needed) */ -uint64_t arm_hcr_el2_eff(CPUARMState *env) +uint64_t arm_hcr_el2_eff_secstate(CPUARMState *env, bool secure) { uint64_t ret = env->cp15.hcr_el2; - if (!arm_is_el2_enabled(env)) { + if (!arm_is_el2_enabled_secstate(env, secure)) { /* * "This register has no effect if EL2 is not enabled in the * current Security state". This is ARMv8.4-SecEL2 speak for @@ -5192,6 +5316,11 @@ uint64_t arm_hcr_el2_eff(CPUARMState *env) return ret; } +uint64_t arm_hcr_el2_eff(CPUARMState *env) +{ + return arm_hcr_el2_eff_secstate(env, arm_is_secure_below_el3(env)); +} + /* * Corresponds to ARM pseudocode function ELIsInHost(). */ @@ -6344,7 +6473,7 @@ static void define_pmu_regs(ARMCPU *cpu) g_free(pmevtyper_name); g_free(pmevtyper_el0_name); } - if (cpu_isar_feature(aa32_pmu_8_1, cpu)) { + if (cpu_isar_feature(aa32_pmuv3p1, cpu)) { ARMCPRegInfo v81_pmu_regs[] = { { .name = "PMCEID2", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 4, @@ -6357,7 +6486,7 @@ static void define_pmu_regs(ARMCPU *cpu) }; define_arm_cp_regs(cpu, v81_pmu_regs); } - if (cpu_isar_feature(any_pmu_8_4, cpu)) { + if (cpu_isar_feature(any_pmuv3p4, cpu)) { static const ARMCPRegInfo v84_pmmir = { .name = "PMMIR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 6, @@ -7345,11 +7474,16 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, not_v7_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_V8)) { - /* AArch64 ID registers, which all have impdef reset values. + /* + * v8 ID registers, which all have impdef reset values. * Note that within the ID register ranges the unused slots * must all RAZ, not UNDEF; future architecture versions may * define new registers here. + * ID registers which are AArch64 views of the AArch32 ID registers + * which already existed in v6 and v7 are handled elsewhere, + * in v6_idregs[]. */ + int i; ARMCPRegInfo v8_idregs[] = { /* * ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST in system @@ -7539,7 +7673,34 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, .resetvalue = cpu->isar.mvfr2 }, - { .name = "MVFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + /* + * "0, c0, c3, {0,1,2}" are the encodings corresponding to + * AArch64 MVFR[012]_EL1. Define the STATE_AA32 encoding + * as RAZ, since it is in the "reserved for future ID + * registers, RAZ" part of the AArch32 encoding space. + */ + { .name = "RES_0_C0_C3_0", .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, + .resetvalue = 0 }, + { .name = "RES_0_C0_C3_1", .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, + .resetvalue = 0 }, + { .name = "RES_0_C0_C3_2", .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, + .resetvalue = 0 }, + /* + * Other encodings in "0, c0, c3, ..." are STATE_BOTH because + * they're also RAZ for AArch64, and in v8 are gradually + * being filled with AArch64-view-of-AArch32-ID-register + * for new ID registers. + */ + { .name = "RES_0_C0_C3_3", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, @@ -7549,17 +7710,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, .resetvalue = cpu->isar.id_pfr2 }, - { .name = "MVFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + { .name = "ID_DFR1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, - .resetvalue = 0 }, - { .name = "MVFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .resetvalue = cpu->isar.id_dfr1 }, + { .name = "ID_MMFR5", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, - .resetvalue = 0 }, - { .name = "MVFR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .resetvalue = cpu->isar.id_mmfr5 }, + { .name = "RES_0_C0_C3_7", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, @@ -7625,6 +7786,29 @@ void register_cp_regs_for_features(ARMCPU *cpu) } define_arm_cp_regs(cpu, v8_idregs); define_arm_cp_regs(cpu, v8_cp_reginfo); + + for (i = 4; i < 16; i++) { + /* + * Encodings in "0, c0, {c4-c7}, {0-7}" are RAZ for AArch32. + * For pre-v8 cores there are RAZ patterns for these in + * id_pre_v8_midr_cp_reginfo[]; for v8 we do that here. + * v8 extends the "must RAZ" part of the ID register space + * to also cover c0, 0, c{8-15}, {0-7}. + * These are STATE_AA32 because in the AArch64 sysreg space + * c4-c7 is where the AArch64 ID registers live (and we've + * already defined those in v8_idregs[]), and c8-c15 are not + * "must RAZ" for AArch64. + */ + g_autofree char *name = g_strdup_printf("RES_0_C0_C%d_X", i); + ARMCPRegInfo v8_aa32_raz_idregs = { + .name = name, + .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 0, .crn = 0, .crm = i, .opc2 = CP_ANY, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, + .resetvalue = 0 }; + define_one_arm_cp_reg(cpu, &v8_aa32_raz_idregs); + } } /* @@ -7667,8 +7851,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) * value is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N. */ ARMCPRegInfo mdcr_el2 = { - .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, + .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, .type = ARM_CP_IO, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, + .writefn = mdcr_el2_write, .access = PL2_RW, .resetvalue = pmu_num_counters(env), .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), }; @@ -8185,12 +8370,17 @@ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b) static void arm_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; + CPUClass *cc = CPU_CLASS(oc); const char *typename; char *name; typename = object_class_get_name(oc); name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_ARM_CPU)); - qemu_printf(" %s\n", name); + if (cc->deprecation_note) { + qemu_printf(" %s (deprecated)\n", name); + } else { + qemu_printf(" %s\n", name); + } g_free(name); } @@ -10078,8 +10268,7 @@ uint64_t arm_sctlr(CPUARMState *env, int el) /* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */ if (el == 0) { ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0); - el = (mmu_idx == ARMMMUIdx_E20_0 || mmu_idx == ARMMMUIdx_SE20_0) - ? 2 : 1; + el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1; } return env->cp15.sctlr_el[el]; } @@ -10118,20 +10307,105 @@ static int aa64_va_parameter_tcma(uint64_t tcr, ARMMMUIdx mmu_idx) } } +static ARMGranuleSize tg0_to_gran_size(int tg) +{ + switch (tg) { + case 0: + return Gran4K; + case 1: + return Gran64K; + case 2: + return Gran16K; + default: + return GranInvalid; + } +} + +static ARMGranuleSize tg1_to_gran_size(int tg) +{ + switch (tg) { + case 1: + return Gran16K; + case 2: + return Gran4K; + case 3: + return Gran64K; + default: + return GranInvalid; + } +} + +static inline bool have4k(ARMCPU *cpu, bool stage2) +{ + return stage2 ? cpu_isar_feature(aa64_tgran4_2, cpu) + : cpu_isar_feature(aa64_tgran4, cpu); +} + +static inline bool have16k(ARMCPU *cpu, bool stage2) +{ + return stage2 ? cpu_isar_feature(aa64_tgran16_2, cpu) + : cpu_isar_feature(aa64_tgran16, cpu); +} + +static inline bool have64k(ARMCPU *cpu, bool stage2) +{ + return stage2 ? cpu_isar_feature(aa64_tgran64_2, cpu) + : cpu_isar_feature(aa64_tgran64, cpu); +} + +static ARMGranuleSize sanitize_gran_size(ARMCPU *cpu, ARMGranuleSize gran, + bool stage2) +{ + switch (gran) { + case Gran4K: + if (have4k(cpu, stage2)) { + return gran; + } + break; + case Gran16K: + if (have16k(cpu, stage2)) { + return gran; + } + break; + case Gran64K: + if (have64k(cpu, stage2)) { + return gran; + } + break; + case GranInvalid: + break; + } + /* + * If the guest selects a granule size that isn't implemented, + * the architecture requires that we behave as if it selected one + * that is (with an IMPDEF choice of which one to pick). We choose + * to implement the smallest supported granule size. + */ + if (have4k(cpu, stage2)) { + return Gran4K; + } + if (have16k(cpu, stage2)) { + return Gran16K; + } + assert(have64k(cpu, stage2)); + return Gran64K; +} + ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ARMMMUIdx mmu_idx, bool data) { uint64_t tcr = regime_tcr(env, mmu_idx); - bool epd, hpd, using16k, using64k, tsz_oob, ds; + bool epd, hpd, tsz_oob, ds; int select, tsz, tbi, max_tsz, min_tsz, ps, sh; + ARMGranuleSize gran; ARMCPU *cpu = env_archcpu(env); + bool stage2 = mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S; if (!regime_has_2_ranges(mmu_idx)) { select = 0; tsz = extract32(tcr, 0, 6); - using64k = extract32(tcr, 14, 1); - using16k = extract32(tcr, 15, 1); - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { + gran = tg0_to_gran_size(extract32(tcr, 14, 2)); + if (stage2) { /* VTCR_EL2 */ hpd = false; } else { @@ -10149,16 +10423,13 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, select = extract64(va, 55, 1); if (!select) { tsz = extract32(tcr, 0, 6); + gran = tg0_to_gran_size(extract32(tcr, 14, 2)); epd = extract32(tcr, 7, 1); sh = extract32(tcr, 12, 2); - using64k = extract32(tcr, 14, 1); - using16k = extract32(tcr, 15, 1); hpd = extract64(tcr, 41, 1); } else { - int tg = extract32(tcr, 30, 2); - using16k = tg == 1; - using64k = tg == 3; tsz = extract32(tcr, 16, 6); + gran = tg1_to_gran_size(extract32(tcr, 30, 2)); epd = extract32(tcr, 23, 1); sh = extract32(tcr, 28, 2); hpd = extract64(tcr, 42, 1); @@ -10167,8 +10438,10 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ds = extract64(tcr, 59, 1); } + gran = sanitize_gran_size(cpu, gran, stage2); + if (cpu_isar_feature(aa64_st, cpu)) { - max_tsz = 48 - using64k; + max_tsz = 48 - (gran == Gran64K); } else { max_tsz = 39; } @@ -10178,7 +10451,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, * adjust the effective value of DS, as documented. */ min_tsz = 16; - if (using64k) { + if (gran == Gran64K) { if (cpu_isar_feature(aa64_lva, cpu)) { min_tsz = 12; } @@ -10187,14 +10460,14 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, switch (mmu_idx) { case ARMMMUIdx_Stage2: case ARMMMUIdx_Stage2_S: - if (using16k) { + if (gran == Gran16K) { ds = cpu_isar_feature(aa64_tgran16_2_lpa2, cpu); } else { ds = cpu_isar_feature(aa64_tgran4_2_lpa2, cpu); } break; default: - if (using16k) { + if (gran == Gran16K) { ds = cpu_isar_feature(aa64_tgran16_lpa2, cpu); } else { ds = cpu_isar_feature(aa64_tgran4_lpa2, cpu); @@ -10231,10 +10504,9 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, .tbi = tbi, .epd = epd, .hpd = hpd, - .using16k = using16k, - .using64k = using64k, .tsz_oob = tsz_oob, .ds = ds, + .gran = gran, }; } @@ -10623,22 +10895,15 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) switch (mmu_idx) { case ARMMMUIdx_E10_0: case ARMMMUIdx_E20_0: - case ARMMMUIdx_SE10_0: - case ARMMMUIdx_SE20_0: return 0; case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1_PAN: - case ARMMMUIdx_SE10_1: - case ARMMMUIdx_SE10_1_PAN: return 1; case ARMMMUIdx_E2: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: - case ARMMMUIdx_SE2: - case ARMMMUIdx_SE20_2: - case ARMMMUIdx_SE20_2_PAN: return 2; - case ARMMMUIdx_SE3: + case ARMMMUIdx_E3: return 3; default: g_assert_not_reached(); @@ -10691,15 +10956,11 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) } break; case 3: - return ARMMMUIdx_SE3; + return ARMMMUIdx_E3; default: g_assert_not_reached(); } - if (arm_is_secure_below_el3(env)) { - idx &= ~ARM_MMU_IDX_A_NS; - } - return idx; } @@ -10764,6 +11025,10 @@ static CPUARMTBFlags rebuild_hflags_m32(CPUARMState *env, int fp_el, DP_TBFLAG_M32(flags, STACKCHECK, 1); } + if (arm_feature(env, ARM_FEATURE_M_SECURITY) && env->v7m.secure) { + DP_TBFLAG_M32(flags, SECURE, 1); + } + return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); } @@ -10898,15 +11163,11 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, switch (mmu_idx) { case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1_PAN: - case ARMMMUIdx_SE10_1: - case ARMMMUIdx_SE10_1_PAN: /* TODO: ARMv8.3-NV */ DP_TBFLAG_A64(flags, UNPRIV, 1); break; case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: - case ARMMMUIdx_SE20_2: - case ARMMMUIdx_SE20_2_PAN: /* * Note that EL20_2 is gated by HCR_EL2.E2H == 1, but EL20_0 is * gated by HCR_EL2. == '11', and so is LDTR. diff --git a/target/arm/internals.h b/target/arm/internals.h index b8fefdff67..9566364dca 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -649,78 +649,24 @@ static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx) case ARMMMUIdx_Stage1_E0: case ARMMMUIdx_Stage1_E1: case ARMMMUIdx_Stage1_E1_PAN: - case ARMMMUIdx_Stage1_SE0: - case ARMMMUIdx_Stage1_SE1: - case ARMMMUIdx_Stage1_SE1_PAN: case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: - case ARMMMUIdx_SE10_0: - case ARMMMUIdx_SE10_1: - case ARMMMUIdx_SE10_1_PAN: - case ARMMMUIdx_SE20_0: - case ARMMMUIdx_SE20_2: - case ARMMMUIdx_SE20_2_PAN: return true; default: return false; } } -/* Return true if this address translation regime is secure */ -static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx) -{ - switch (mmu_idx) { - case ARMMMUIdx_E10_0: - case ARMMMUIdx_E10_1: - case ARMMMUIdx_E10_1_PAN: - case ARMMMUIdx_E20_0: - case ARMMMUIdx_E20_2: - case ARMMMUIdx_E20_2_PAN: - case ARMMMUIdx_Stage1_E0: - case ARMMMUIdx_Stage1_E1: - case ARMMMUIdx_Stage1_E1_PAN: - case ARMMMUIdx_E2: - case ARMMMUIdx_Stage2: - case ARMMMUIdx_MPrivNegPri: - case ARMMMUIdx_MUserNegPri: - case ARMMMUIdx_MPriv: - case ARMMMUIdx_MUser: - return false; - case ARMMMUIdx_SE3: - case ARMMMUIdx_SE10_0: - case ARMMMUIdx_SE10_1: - case ARMMMUIdx_SE10_1_PAN: - case ARMMMUIdx_SE20_0: - case ARMMMUIdx_SE20_2: - case ARMMMUIdx_SE20_2_PAN: - case ARMMMUIdx_Stage1_SE0: - case ARMMMUIdx_Stage1_SE1: - case ARMMMUIdx_Stage1_SE1_PAN: - case ARMMMUIdx_SE2: - case ARMMMUIdx_Stage2_S: - case ARMMMUIdx_MSPrivNegPri: - case ARMMMUIdx_MSUserNegPri: - case ARMMMUIdx_MSPriv: - case ARMMMUIdx_MSUser: - return true; - default: - g_assert_not_reached(); - } -} - static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx) { switch (mmu_idx) { case ARMMMUIdx_Stage1_E1_PAN: - case ARMMMUIdx_Stage1_SE1_PAN: case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_E20_2_PAN: - case ARMMMUIdx_SE10_1_PAN: - case ARMMMUIdx_SE20_2_PAN: return true; default: return false; @@ -731,30 +677,20 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx) static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) { switch (mmu_idx) { - case ARMMMUIdx_SE20_0: - case ARMMMUIdx_SE20_2: - case ARMMMUIdx_SE20_2_PAN: case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_Stage2: case ARMMMUIdx_Stage2_S: - case ARMMMUIdx_SE2: case ARMMMUIdx_E2: return 2; - case ARMMMUIdx_SE3: + case ARMMMUIdx_E3: return 3; - case ARMMMUIdx_SE10_0: - case ARMMMUIdx_Stage1_SE0: - return arm_el_is_aa64(env, 3) ? 1 : 3; - case ARMMMUIdx_SE10_1: - case ARMMMUIdx_SE10_1_PAN: + case ARMMMUIdx_E10_0: case ARMMMUIdx_Stage1_E0: + return arm_el_is_aa64(env, 3) || !arm_is_secure_below_el3(env) ? 1 : 3; case ARMMMUIdx_Stage1_E1: case ARMMMUIdx_Stage1_E1_PAN: - case ARMMMUIdx_Stage1_SE1: - case ARMMMUIdx_Stage1_SE1_PAN: - case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_MPrivNegPri: @@ -996,9 +932,6 @@ static inline bool arm_mmu_idx_is_stage1_of_2(ARMMMUIdx mmu_idx) case ARMMMUIdx_Stage1_E0: case ARMMMUIdx_Stage1_E1: case ARMMMUIdx_Stage1_E1_PAN: - case ARMMMUIdx_Stage1_SE0: - case ARMMMUIdx_Stage1_SE1: - case ARMMMUIdx_Stage1_SE1_PAN: return true; default: return false; @@ -1065,6 +998,35 @@ static inline uint32_t aarch64_pstate_valid_mask(const ARMISARegisters *id) return valid; } +/* Granule size (i.e. page size) */ +typedef enum ARMGranuleSize { + /* Same order as TG0 encoding */ + Gran4K, + Gran64K, + Gran16K, + GranInvalid, +} ARMGranuleSize; + +/** + * arm_granule_bits: Return address size of the granule in bits + * + * Return the address size of the granule in bits. This corresponds + * to the pseudocode TGxGranuleBits(). + */ +static inline int arm_granule_bits(ARMGranuleSize gran) +{ + switch (gran) { + case Gran64K: + return 16; + case Gran16K: + return 14; + case Gran4K: + return 12; + default: + g_assert_not_reached(); + } +} + /* * Parameters of a given virtual address, as extracted from the * translation control register (TCR) for a given regime. @@ -1077,10 +1039,9 @@ typedef struct ARMVAParameters { bool tbi : 1; bool epd : 1; bool hpd : 1; - bool using16k : 1; - bool using64k : 1; bool tsz_oob : 1; /* tsz has been clamped to legal range */ bool ds : 1; + ARMGranuleSize gran : 2; } ARMVAParameters; ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, @@ -1123,13 +1084,7 @@ typedef struct V8M_SAttributes { void v8m_security_lookup(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - V8M_SAttributes *sattrs); - -bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, bool *is_subpage, - ARMMMUFaultInfo *fi, uint32_t *mregion); + bool secure, V8M_SAttributes *sattrs); /* Cacheability and shareability attributes for a memory access */ typedef struct ARMCacheAttrs { @@ -1142,13 +1097,62 @@ typedef struct ARMCacheAttrs { bool is_s2_format:1; } ARMCacheAttrs; +/* Fields that are valid upon success. */ +typedef struct GetPhysAddrResult { + CPUTLBEntryFull f; + ARMCacheAttrs cacheattrs; +} GetPhysAddrResult; + +/** + * get_phys_addr_with_secure: get the physical address for a virtual address + * @env: CPUARMState + * @address: virtual address to get physical address for + * @access_type: 0 for read, 1 for write, 2 for execute + * @mmu_idx: MMU index indicating required translation regime + * @is_secure: security state for the access + * @result: set on translation success. + * @fi: set to fault info if the translation fails + * + * Find the physical address corresponding to the given virtual address, + * by doing a translation table walk on MMU based systems or using the + * MPU state on MPU based systems. + * + * Returns false if the translation was successful. Otherwise, phys_ptr, attrs, + * prot and page_size may not be filled in, and the populated fsr value provides + * information on why the translation aborted, in the format of a + * DFSR/IFSR fault register, with the following caveats: + * * we honour the short vs long DFSR format differences. + * * the WnR bit is never set (the caller must do this). + * * for PSMAv5 based systems we don't bother to return a full FSR format + * value. + */ +bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, + MMUAccessType access_type, + ARMMMUIdx mmu_idx, bool is_secure, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) + __attribute__((nonnull)); + +/** + * get_phys_addr: get the physical address for a virtual address + * @env: CPUARMState + * @address: virtual address to get physical address for + * @access_type: 0 for read, 1 for write, 2 for execute + * @mmu_idx: MMU index indicating required translation regime + * @result: set on translation success. + * @fi: set to fault info if the translation fails + * + * Similarly, but use the security regime of @mmu_idx. + */ bool get_phys_addr(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) __attribute__((nonnull)); +bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool is_secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi, uint32_t *mregion); + void arm_log_exception(CPUState *cs); #endif /* !CONFIG_USER_ONLY */ @@ -1256,6 +1260,7 @@ enum MVEECIState { /* Definitions for the PMU registers */ #define PMCRN_MASK 0xf800 #define PMCRN_SHIFT 11 +#define PMCRLP 0x80 #define PMCRLC 0x40 #define PMCRDP 0x20 #define PMCRX 0x10 @@ -1267,7 +1272,7 @@ enum MVEECIState { * Mask of PMCR bits writable by guest (not including WO bits like C, P, * which can be written as 1 to trigger behaviour but which stay RAZ). */ -#define PMCR_WRITABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE) +#define PMCR_WRITABLE_MASK (PMCRLP | PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE) #define PMXEVTYPER_P 0x80000000 #define PMXEVTYPER_U 0x40000000 @@ -1296,7 +1301,7 @@ static inline uint32_t pmu_num_counters(CPUARMState *env) /* Bits allowed to be set/cleared for PMCNTEN* and PMINTEN* */ static inline uint64_t pmu_counter_mask(CPUARMState *env) { - return (1 << 31) | ((1 << pmu_num_counters(env)) - 1); + return (1ULL << 31) | ((1ULL << pmu_num_counters(env)) - 1); } #ifdef TARGET_AARCH64 diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 4339e1cd6e..1e4de9b42e 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -79,7 +79,9 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try, if (max_vm_pa_size < 0) { max_vm_pa_size = 0; } - vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size); + do { + vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size); + } while (vmfd == -1 && errno == EINTR); if (vmfd < 0) { goto err; } @@ -959,7 +961,7 @@ void kvm_arch_init_irq_routing(KVMState *s) int kvm_arch_irqchip_create(KVMState *s) { if (kvm_kernel_irqchip_split()) { - perror("-machine kernel_irqchip=split is not supported on ARM."); + error_report("-machine kernel_irqchip=split is not supported on ARM."); exit(1); } diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index d16d4ea250..1197253d12 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -507,7 +507,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) bool sve_supported; bool pmu_supported = false; uint64_t features = 0; - uint64_t t; int err; /* Old kernels may not know about the PREFERRED_TARGET ioctl: however @@ -528,10 +527,17 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) struct kvm_vcpu_init init = { .target = -1, }; /* - * Ask for Pointer Authentication if supported. We can't play the - * SVE trick of synthesising the ID reg as KVM won't tell us - * whether we have the architected or IMPDEF version of PAuth, so - * we have to use the actual ID regs. + * Ask for SVE if supported, so that we can query ID_AA64ZFR0, + * which is otherwise RAZ. + */ + sve_supported = kvm_arm_sve_supported(); + if (sve_supported) { + init.features[0] |= 1 << KVM_ARM_VCPU_SVE; + } + + /* + * Ask for Pointer Authentication if supported, so that we get + * the unsanitized field values for AA64ISAR1_EL1. */ if (kvm_arm_pauth_supported()) { init.features[0] |= (1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS | @@ -602,8 +608,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) ARM64_SYS_REG(3, 0, 0, 1, 0)); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1, ARM64_SYS_REG(3, 0, 0, 1, 1)); - err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2, - ARM64_SYS_REG(3, 0, 0, 3, 4)); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, ARM64_SYS_REG(3, 0, 0, 1, 2)); err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, @@ -637,6 +641,12 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) ARM64_SYS_REG(3, 0, 0, 3, 1)); err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, ARM64_SYS_REG(3, 0, 0, 3, 2)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2, + ARM64_SYS_REG(3, 0, 0, 3, 4)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr1, + ARM64_SYS_REG(3, 0, 0, 3, 5)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr5, + ARM64_SYS_REG(3, 0, 0, 3, 6)); /* * DBGDIDR is a bit complicated because the kernel doesn't @@ -673,25 +683,18 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) err |= read_sys_reg64(fdarray[2], &ahcf->isar.reset_pmcr_el0, ARM64_SYS_REG(3, 3, 9, 12, 0)); } - } - sve_supported = ioctl(fdarray[0], KVM_CHECK_EXTENSION, KVM_CAP_ARM_SVE) > 0; - - /* Add feature bits that can't appear until after VCPU init. */ - if (sve_supported) { - t = ahcf->isar.id_aa64pfr0; - t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); - ahcf->isar.id_aa64pfr0 = t; - - /* - * There is a range of kernels between kernel commit 73433762fcae - * and f81cb2c3ad41 which have a bug where the kernel doesn't expose - * SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has enabled - * SVE support, so we only read it here, rather than together with all - * the other ID registers earlier. - */ - err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0, - ARM64_SYS_REG(3, 0, 0, 4, 4)); + if (sve_supported) { + /* + * There is a range of kernels between kernel commit 73433762fcae + * and f81cb2c3ad41 which have a bug where the kernel doesn't + * expose SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has + * enabled SVE support, which resulted in an error rather than RAZ. + * So only read the register if we set KVM_ARM_VCPU_SVE above. + */ + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0, + ARM64_SYS_REG(3, 0, 0, 4, 4)); + } } kvm_arm_destroy_scratch_host_vcpu(fdarray); diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 308610f6b4..355cd4d60a 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -183,19 +183,14 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, { CPUState *cs = CPU(cpu); CPUARMState *env = &cpu->env; - MemTxAttrs attrs = {}; MemTxResult txres; - target_ulong page_size; - hwaddr physaddr; - int prot; + GetPhysAddrResult res = {}; ARMMMUFaultInfo fi = {}; - ARMCacheAttrs cacheattrs = {}; bool secure = mmu_idx & ARM_MMU_IDX_M_S; int exc; bool exc_secure; - if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr, - &attrs, &prot, &page_size, &fi, &cacheattrs)) { + if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &res, &fi)) { /* MPU/SAU lookup failed */ if (fi.type == ARMFault_QEMU_SFault) { if (mode == STACK_LAZYFP) { @@ -228,8 +223,8 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, } goto pend_fault; } - address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value, - attrs, &txres); + address_space_stl_le(arm_addressspace(cs, res.f.attrs), res.f.phys_addr, + value, res.f.attrs, &txres); if (txres != MEMTX_OK) { /* BusFault trying to write the data */ if (mode == STACK_LAZYFP) { @@ -276,20 +271,15 @@ static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr, { CPUState *cs = CPU(cpu); CPUARMState *env = &cpu->env; - MemTxAttrs attrs = {}; MemTxResult txres; - target_ulong page_size; - hwaddr physaddr; - int prot; + GetPhysAddrResult res = {}; ARMMMUFaultInfo fi = {}; - ARMCacheAttrs cacheattrs = {}; bool secure = mmu_idx & ARM_MMU_IDX_M_S; int exc; bool exc_secure; uint32_t value; - if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr, - &attrs, &prot, &page_size, &fi, &cacheattrs)) { + if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &res, &fi)) { /* MPU/SAU lookup failed */ if (fi.type == ARMFault_QEMU_SFault) { qemu_log_mask(CPU_LOG_INT, @@ -308,8 +298,8 @@ static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr, goto pend_fault; } - value = address_space_ldl(arm_addressspace(cs, attrs), physaddr, - attrs, &txres); + value = address_space_ldl(arm_addressspace(cs, res.f.attrs), + res.f.phys_addr, res.f.attrs, &txres); if (txres != MEMTX_OK) { /* BusFault trying to read the data */ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.UNSTKERR\n"); @@ -699,7 +689,8 @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure, if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { V8M_SAttributes sattrs = {}; - v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); + v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, + targets_secure, &sattrs); if (sattrs.ns) { attrs.secure = false; } else if (!targets_secure) { @@ -1990,7 +1981,7 @@ static bool do_v7m_function_return(ARMCPU *cpu) return true; } -static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, +static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool secure, uint32_t addr, uint16_t *insn) { /* @@ -2008,15 +1999,11 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, CPUState *cs = CPU(cpu); CPUARMState *env = &cpu->env; V8M_SAttributes sattrs = {}; - MemTxAttrs attrs = {}; + GetPhysAddrResult res = {}; ARMMMUFaultInfo fi = {}; - ARMCacheAttrs cacheattrs = {}; MemTxResult txres; - target_ulong page_size; - hwaddr physaddr; - int prot; - v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs); + v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, secure, &sattrs); if (!sattrs.nsc || sattrs.ns) { /* * This must be the second half of the insn, and it straddles a @@ -2028,16 +2015,15 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, "...really SecureFault with SFSR.INVEP\n"); return false; } - if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, &physaddr, - &attrs, &prot, &page_size, &fi, &cacheattrs)) { + if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, &res, &fi)) { /* the MPU lookup failed */ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure); qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n"); return false; } - *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr, - attrs, &txres); + *insn = address_space_lduw_le(arm_addressspace(cs, res.f.attrs), + res.f.phys_addr, res.f.attrs, &txres); if (txres != MEMTX_OK) { env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false); @@ -2060,17 +2046,12 @@ static bool v7m_read_sg_stack_word(ARMCPU *cpu, ARMMMUIdx mmu_idx, */ CPUState *cs = CPU(cpu); CPUARMState *env = &cpu->env; - MemTxAttrs attrs = {}; MemTxResult txres; - target_ulong page_size; - hwaddr physaddr; - int prot; + GetPhysAddrResult res = {}; ARMMMUFaultInfo fi = {}; - ARMCacheAttrs cacheattrs = {}; uint32_t value; - if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr, - &attrs, &prot, &page_size, &fi, &cacheattrs)) { + if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &res, &fi)) { /* MPU/SAU lookup failed */ if (fi.type == ARMFault_QEMU_SFault) { qemu_log_mask(CPU_LOG_INT, @@ -2088,8 +2069,8 @@ static bool v7m_read_sg_stack_word(ARMCPU *cpu, ARMMMUIdx mmu_idx, } return false; } - value = address_space_ldl(arm_addressspace(cs, attrs), physaddr, - attrs, &txres); + value = address_space_ldl(arm_addressspace(cs, res.f.attrs), + res.f.phys_addr, res.f.attrs, &txres); if (txres != MEMTX_OK) { /* BusFault trying to read the data */ qemu_log_mask(CPU_LOG_INT, @@ -2127,7 +2108,7 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu) /* We want to do the MPU lookup as secure; work out what mmu_idx that is */ mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true); - if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15], &insn)) { + if (!v7m_read_half_insn(cpu, mmu_idx, true, env->regs[15], &insn)) { return false; } @@ -2143,7 +2124,7 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu) goto gen_invep; } - if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15] + 2, &insn)) { + if (!v7m_read_half_insn(cpu, mmu_idx, true, env->regs[15] + 2, &insn)) { return false; } @@ -2790,15 +2771,10 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) V8M_SAttributes sattrs = {}; uint32_t tt_resp; bool r, rw, nsr, nsrw, mrvalid; - int prot; - ARMMMUFaultInfo fi = {}; - MemTxAttrs attrs = {}; - hwaddr phys_addr; ARMMMUIdx mmu_idx; uint32_t mregion; bool targetpriv; bool targetsec = env->v7m.secure; - bool is_subpage; /* * Work out what the security state and privilege level we're @@ -2829,18 +2805,20 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) * inspecting the other MPU state. */ if (arm_current_el(env) != 0 || alt) { + GetPhysAddrResult res = {}; + ARMMMUFaultInfo fi = {}; + /* We can ignore the return value as prot is always set */ - pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, - &phys_addr, &attrs, &prot, &is_subpage, - &fi, &mregion); + pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, targetsec, + &res, &fi, &mregion); if (mregion == -1) { mrvalid = false; mregion = 0; } else { mrvalid = true; } - r = prot & PAGE_READ; - rw = prot & PAGE_WRITE; + r = res.f.prot & PAGE_READ; + rw = res.f.prot & PAGE_WRITE; } else { r = false; rw = false; @@ -2849,7 +2827,8 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) } if (env->v7m.secure) { - v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); + v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, + targetsec, &sattrs); nsr = sattrs.ns && r; nsrw = sattrs.ns && rw; } else { diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index d11a8c70d0..fdd23ab3f8 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -106,7 +106,7 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, return tags + index; #else uintptr_t index; - CPUIOTLBEntry *iotlbentry; + CPUTLBEntryFull *full; int in_page, flags; ram_addr_t ptr_ra; hwaddr ptr_paddr, tag_paddr, xlat; @@ -129,7 +129,7 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, assert(!(flags & TLB_INVALID_MASK)); /* - * Find the iotlbentry for ptr. This *must* be present in the TLB + * Find the CPUTLBEntryFull for ptr. This *must* be present in the TLB * because we just found the mapping. * TODO: Perhaps there should be a cputlb helper that returns a * matching tlb entry + iotlb entry. @@ -144,10 +144,10 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, g_assert(tlb_hit(comparator, ptr)); } # endif - iotlbentry = &env_tlb(env)->d[ptr_mmu_idx].iotlb[index]; + full = &env_tlb(env)->d[ptr_mmu_idx].fulltlb[index]; /* If the virtual page MemAttr != Tagged, access unchecked. */ - if (!arm_tlb_mte_tagged(&iotlbentry->attrs)) { + if (!arm_tlb_mte_tagged(&full->attrs)) { return NULL; } @@ -181,7 +181,7 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, int wp = ptr_access == MMU_DATA_LOAD ? BP_MEM_READ : BP_MEM_WRITE; assert(ra != 0); cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, - iotlbentry->attrs, wp, ra); + full->attrs, wp, ra); } /* @@ -202,11 +202,11 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, tag_paddr = ptr_paddr >> (LOG2_TAG_GRANULE + 1); /* Look up the address in tag space. */ - tag_asi = iotlbentry->attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS; + tag_asi = full->attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS; tag_as = cpu_get_address_space(env_cpu(env), tag_asi); mr = address_space_translate(tag_as, tag_paddr, &xlat, NULL, tag_access == MMU_DATA_STORE, - iotlbentry->attrs); + full->attrs); /* * Note that @mr will never be NULL. If there is nothing in the address diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 3261039d93..23f16f4ff7 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -16,10 +16,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool s1_is_el0, hwaddr *phys_ptr, - MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) + bool is_secure, bool s1_is_el0, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) __attribute__((nonnull)); /* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ @@ -67,12 +65,6 @@ unsigned int arm_pamax(ARMCPU *cpu) ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) { switch (mmu_idx) { - case ARMMMUIdx_SE10_0: - return ARMMMUIdx_Stage1_SE0; - case ARMMMUIdx_SE10_1: - return ARMMMUIdx_Stage1_SE1; - case ARMMMUIdx_SE10_1_PAN: - return ARMMMUIdx_Stage1_SE1_PAN; case ARMMMUIdx_E10_0: return ARMMMUIdx_Stage1_E0; case ARMMMUIdx_E10_1: @@ -97,11 +89,8 @@ static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx) static bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) { switch (mmu_idx) { - case ARMMMUIdx_SE10_0: case ARMMMUIdx_E20_0: - case ARMMMUIdx_SE20_0: case ARMMMUIdx_Stage1_E0: - case ARMMMUIdx_Stage1_SE0: case ARMMMUIdx_MUser: case ARMMMUIdx_MSUser: case ARMMMUIdx_MUserNegPri: @@ -133,12 +122,13 @@ static uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) } /* Return true if the specified stage of address translation is disabled */ -static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx) +static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx, + bool is_secure) { uint64_t hcr_el2; if (arm_feature(env, ARM_FEATURE_M)) { - switch (env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] & + switch (env->v7m.mpu_ctrl[is_secure] & (R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) { case R_V7M_MPU_CTRL_ENABLE_MASK: /* Enabled, but not for HardFault and NMI */ @@ -156,29 +146,47 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx) } } - hcr_el2 = arm_hcr_el2_eff(env); + hcr_el2 = arm_hcr_el2_eff_secstate(env, is_secure); - if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { + switch (mmu_idx) { + case ARMMMUIdx_Stage2: + case ARMMMUIdx_Stage2_S: /* HCR.DC means HCR.VM behaves as 1 */ return (hcr_el2 & (HCR_DC | HCR_VM)) == 0; - } - if (hcr_el2 & HCR_TGE) { - /* TGE means that NS EL0/1 act as if SCTLR_EL1.M is zero */ - if (!regime_is_secure(env, mmu_idx) && regime_el(env, mmu_idx) == 1) { + case ARMMMUIdx_E10_0: + case ARMMMUIdx_E10_1: + case ARMMMUIdx_E10_1_PAN: + /* TGE means that EL0/1 act as if SCTLR_EL1.M is zero */ + if (hcr_el2 & HCR_TGE) { return true; } - } + break; - if ((hcr_el2 & HCR_DC) && arm_mmu_idx_is_stage1_of_2(mmu_idx)) { + case ARMMMUIdx_Stage1_E0: + case ARMMMUIdx_Stage1_E1: + case ARMMMUIdx_Stage1_E1_PAN: /* HCR.DC means SCTLR_EL1.M behaves as 0 */ - return true; + if (hcr_el2 & HCR_DC) { + return true; + } + break; + + case ARMMMUIdx_E20_0: + case ARMMMUIdx_E20_2: + case ARMMMUIdx_E20_2_PAN: + case ARMMMUIdx_E2: + case ARMMMUIdx_E3: + break; + + default: + g_assert_not_reached(); } return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; } -static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) +static bool ptw_attrs_are_device(uint64_t hcr, ARMCacheAttrs cacheattrs) { /* * For an S1 page table walk, the stage 1 attributes are always @@ -190,7 +198,7 @@ static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) * when cacheattrs.attrs bit [2] is 0. */ assert(cacheattrs.is_s2_format); - if (arm_hcr_el2_eff(env) & HCR_FWB) { + if (hcr & HCR_FWB) { return (cacheattrs.attrs & 0x4) == 0; } else { return (cacheattrs.attrs & 0xc) == 0; @@ -199,33 +207,31 @@ static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) /* Translate a S1 pagetable walk through S2 if needed. */ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, - hwaddr addr, bool *is_secure, + hwaddr addr, bool *is_secure_ptr, ARMMMUFaultInfo *fi) { - if (arm_mmu_idx_is_stage1_of_2(mmu_idx) && - !regime_translation_disabled(env, ARMMMUIdx_Stage2)) { - target_ulong s2size; - hwaddr s2pa; - int s2prot; - int ret; - ARMMMUIdx s2_mmu_idx = *is_secure ? ARMMMUIdx_Stage2_S - : ARMMMUIdx_Stage2; - ARMCacheAttrs cacheattrs = {}; - MemTxAttrs txattrs = {}; + bool is_secure = *is_secure_ptr; + ARMMMUIdx s2_mmu_idx = is_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; - ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, s2_mmu_idx, false, - &s2pa, &txattrs, &s2prot, &s2size, fi, - &cacheattrs); + if (arm_mmu_idx_is_stage1_of_2(mmu_idx) && + !regime_translation_disabled(env, s2_mmu_idx, is_secure)) { + GetPhysAddrResult s2 = {}; + uint64_t hcr; + int ret; + + ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, s2_mmu_idx, + is_secure, false, &s2, fi); if (ret) { assert(fi->type != ARMFault_None); fi->s2addr = addr; fi->stage2 = true; fi->s1ptw = true; - fi->s1ns = !*is_secure; + fi->s1ns = !is_secure; return ~0; } - if ((arm_hcr_el2_eff(env) & HCR_PTW) && - ptw_attrs_are_device(env, cacheattrs)) { + + hcr = arm_hcr_el2_eff_secstate(env, is_secure); + if ((hcr & HCR_PTW) && ptw_attrs_are_device(hcr, s2.cacheattrs)) { /* * PTW set and S1 walk touched S2 Device memory: * generate Permission fault. @@ -234,22 +240,23 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, fi->s2addr = addr; fi->stage2 = true; fi->s1ptw = true; - fi->s1ns = !*is_secure; + fi->s1ns = !is_secure; return ~0; } if (arm_is_secure_below_el3(env)) { /* Check if page table walk is to secure or non-secure PA space. */ - if (*is_secure) { - *is_secure = !(env->cp15.vstcr_el2 & VSTCR_SW); + if (is_secure) { + is_secure = !(env->cp15.vstcr_el2 & VSTCR_SW); } else { - *is_secure = !(env->cp15.vtcr_el2 & VTCR_NSW); + is_secure = !(env->cp15.vtcr_el2 & VTCR_NSW); } + *is_secure_ptr = is_secure; } else { - assert(!*is_secure); + assert(!is_secure); } - addr = s2pa; + addr = s2.f.phys_addr; } return addr; } @@ -421,8 +428,7 @@ static int simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - target_ulong *page_size, + bool is_secure, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { int level = 1; @@ -442,8 +448,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, fi->type = ARMFault_Translation; goto do_fault; } - desc = arm_ldl_ptw(env, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); + desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; } @@ -471,7 +476,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* 1Mb section. */ phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); ap = (desc >> 10) & 3; - *page_size = 1024 * 1024; + result->f.lg_page_size = 20; /* 1MB */ } else { /* Lookup l2 entry. */ if (type == 1) { @@ -481,8 +486,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Fine pagetable. */ table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); } - desc = arm_ldl_ptw(env, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); + desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; } @@ -493,12 +497,12 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, case 1: /* 64k page. */ phys_addr = (desc & 0xffff0000) | (address & 0xffff); ap = (desc >> (4 + ((address >> 13) & 6))) & 3; - *page_size = 0x10000; + result->f.lg_page_size = 16; break; case 2: /* 4k page. */ phys_addr = (desc & 0xfffff000) | (address & 0xfff); ap = (desc >> (4 + ((address >> 9) & 6))) & 3; - *page_size = 0x1000; + result->f.lg_page_size = 12; break; case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */ if (type == 1) { @@ -506,7 +510,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, if (arm_feature(env, ARM_FEATURE_XSCALE) || arm_feature(env, ARM_FEATURE_V6)) { phys_addr = (desc & 0xfffff000) | (address & 0xfff); - *page_size = 0x1000; + result->f.lg_page_size = 12; } else { /* * UNPREDICTABLE in ARMv5; we choose to take a @@ -517,7 +521,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, } } else { phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); - *page_size = 0x400; + result->f.lg_page_size = 10; } ap = (desc >> 4) & 3; break; @@ -526,14 +530,14 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, g_assert_not_reached(); } } - *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); - *prot |= *prot ? PAGE_EXEC : 0; - if (!(*prot & (1 << access_type))) { + result->f.prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); + result->f.prot |= result->f.prot ? PAGE_EXEC : 0; + if (!(result->f.prot & (1 << access_type))) { /* Access permission fault. */ fi->type = ARMFault_Permission; goto do_fault; } - *phys_ptr = phys_addr; + result->f.phys_addr = phys_addr; return false; do_fault: fi->domain = domain; @@ -543,8 +547,8 @@ do_fault: static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, ARMMMUFaultInfo *fi) + bool is_secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) { ARMCPU *cpu = env_archcpu(env); int level = 1; @@ -567,8 +571,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, fi->type = ARMFault_Translation; goto do_fault; } - desc = arm_ldl_ptw(env, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); + desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; } @@ -604,11 +607,11 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); phys_addr |= (uint64_t)extract32(desc, 20, 4) << 32; phys_addr |= (uint64_t)extract32(desc, 5, 4) << 36; - *page_size = 0x1000000; + result->f.lg_page_size = 24; /* 16MB */ } else { /* Section. */ phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); - *page_size = 0x100000; + result->f.lg_page_size = 20; /* 1MB */ } ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); xn = desc & (1 << 4); @@ -621,8 +624,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, ns = extract32(desc, 3, 1); /* Lookup l2 entry. */ table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - desc = arm_ldl_ptw(env, table, regime_is_secure(env, mmu_idx), - mmu_idx, fi); + desc = arm_ldl_ptw(env, table, is_secure, mmu_idx, fi); if (fi->type != ARMFault_None) { goto do_fault; } @@ -634,12 +636,12 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, case 1: /* 64k page. */ phys_addr = (desc & 0xffff0000) | (address & 0xffff); xn = desc & (1 << 15); - *page_size = 0x10000; + result->f.lg_page_size = 16; break; case 2: case 3: /* 4k page. */ phys_addr = (desc & 0xfffff000) | (address & 0xfff); xn = desc & 1; - *page_size = 0x1000; + result->f.lg_page_size = 12; break; default: /* Never happens, but compiler isn't smart enough to tell. */ @@ -647,7 +649,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, } } if (domain_prot == 3) { - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + result->f.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; } else { if (pxn && !regime_is_user(env, mmu_idx)) { xn = 1; @@ -665,14 +667,14 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, fi->type = ARMFault_AccessFlag; goto do_fault; } - *prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); + result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); } else { - *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); + result->f.prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); } - if (*prot && !xn) { - *prot |= PAGE_EXEC; + if (result->f.prot && !xn) { + result->f.prot |= PAGE_EXEC; } - if (!(*prot & (1 << access_type))) { + if (!(result->f.prot & (1 << access_type))) { /* Access permission fault. */ fi->type = ARMFault_Permission; goto do_fault; @@ -683,9 +685,9 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, * the CPU doesn't support TZ or this is a non-secure translation * regime, because the attribute will already be non-secure. */ - attrs->secure = false; + result->f.attrs.secure = false; } - *phys_ptr = phys_addr; + result->f.phys_addr = phys_addr; return false; do_fault: fi->domain = domain; @@ -972,19 +974,13 @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level, * table walk), must be true if this is stage 2 of a stage 1+2 * walk for an EL0 access. If @mmu_idx is anything else, * @s1_is_el0 is ignored. - * @phys_ptr: set to the physical address corresponding to the virtual address - * @attrs: set to the memory transaction attributes to use - * @prot: set to the permissions for the page containing phys_ptr - * @page_size_ptr: set to the size of the page containing phys_ptr + * @result: set on translation success, * @fi: set to fault info if the translation fails - * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes */ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - bool s1_is_el0, hwaddr *phys_ptr, - MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) + bool is_secure, bool s1_is_el0, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { ARMCPU *cpu = env_archcpu(env); /* Read an LPAE long-descriptor translation table. */ @@ -1066,13 +1062,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, } } - if (param.using64k) { - stride = 13; - } else if (param.using16k) { - stride = 11; - } else { - stride = 9; - } + stride = arm_granule_bits(param.gran) - 3; /* * Note that QEMU ignores shareability and cacheability attributes, @@ -1201,7 +1191,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, * remain non-secure. We implement this by just ORing in the NSTable/NS * bits at each step. */ - tableattrs = regime_is_secure(env, mmu_idx) ? 0 : (1 << 4); + tableattrs = is_secure ? 0 : (1 << 4); for (;;) { uint64_t descriptor; bool nstable; @@ -1302,16 +1292,16 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { ns = mmu_idx == ARMMMUIdx_Stage2; xn = extract32(attrs, 11, 2); - *prot = get_S2prot(env, ap, xn, s1_is_el0); + result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); } else { ns = extract32(attrs, 3, 1); xn = extract32(attrs, 12, 1); pxn = extract32(attrs, 11, 1); - *prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); + result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); } fault_type = ARMFault_Permission; - if (!(*prot & (1 << access_type))) { + if (!(result->f.prot & (1 << access_type))) { goto do_fault; } @@ -1321,23 +1311,23 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, * the CPU doesn't support TZ or this is a non-secure translation * regime, because the attribute will already be non-secure. */ - txattrs->secure = false; + result->f.attrs.secure = false; } /* When in aarch64 mode, and BTI is enabled, remember GP in the IOTLB. */ if (aarch64 && guarded && cpu_isar_feature(aa64_bti, cpu)) { - arm_tlb_bti_gp(txattrs) = true; + arm_tlb_bti_gp(&result->f.attrs) = true; } if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - cacheattrs->is_s2_format = true; - cacheattrs->attrs = extract32(attrs, 0, 4); + result->cacheattrs.is_s2_format = true; + result->cacheattrs.attrs = extract32(attrs, 0, 4); } else { /* Index into MAIR registers for cache attributes */ uint8_t attrindx = extract32(attrs, 0, 3); uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; assert(attrindx <= 7); - cacheattrs->is_s2_format = false; - cacheattrs->attrs = extract64(mair, attrindx * 8, 8); + result->cacheattrs.is_s2_format = false; + result->cacheattrs.attrs = extract64(mair, attrindx * 8, 8); } /* @@ -1346,13 +1336,13 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, * that case comes from TCR_ELx, which we extracted earlier. */ if (param.ds) { - cacheattrs->shareability = param.sh; + result->cacheattrs.shareability = param.sh; } else { - cacheattrs->shareability = extract32(attrs, 6, 2); + result->cacheattrs.shareability = extract32(attrs, 6, 2); } - *phys_ptr = descaddr; - *page_size_ptr = page_size; + result->f.phys_addr = descaddr; + result->f.lg_page_size = ctz64(page_size); return false; do_fault: @@ -1367,7 +1357,7 @@ do_fault: static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, + bool is_secure, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { int n; @@ -1375,14 +1365,14 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, uint32_t base; bool is_user = regime_is_user(env, mmu_idx); - if (regime_translation_disabled(env, mmu_idx)) { + if (regime_translation_disabled(env, mmu_idx, is_secure)) { /* MPU disabled. */ - *phys_ptr = address; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + result->f.phys_addr = address; + result->f.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return false; } - *phys_ptr = address; + result->f.phys_addr = address; for (n = 7; n >= 0; n--) { base = env->cp15.c6_region[n]; if ((base & 1) == 0) { @@ -1418,16 +1408,16 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, fi->level = 1; return true; } - *prot = PAGE_READ | PAGE_WRITE; + result->f.prot = PAGE_READ | PAGE_WRITE; break; case 2: - *prot = PAGE_READ; + result->f.prot = PAGE_READ; if (!is_user) { - *prot |= PAGE_WRITE; + result->f.prot |= PAGE_WRITE; } break; case 3: - *prot = PAGE_READ | PAGE_WRITE; + result->f.prot = PAGE_READ | PAGE_WRITE; break; case 5: if (is_user) { @@ -1435,10 +1425,10 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, fi->level = 1; return true; } - *prot = PAGE_READ; + result->f.prot = PAGE_READ; break; case 6: - *prot = PAGE_READ; + result->f.prot = PAGE_READ; break; default: /* Bad permission. */ @@ -1446,12 +1436,12 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, fi->level = 1; return true; } - *prot |= PAGE_EXEC; + result->f.prot |= PAGE_EXEC; return false; } static void get_phys_addr_pmsav7_default(CPUARMState *env, ARMMMUIdx mmu_idx, - int32_t address, int *prot) + int32_t address, uint8_t *prot) { if (!arm_feature(env, ARM_FEATURE_M)) { *prot = PAGE_READ | PAGE_WRITE; @@ -1507,7 +1497,7 @@ static bool m_is_system_region(CPUARMState *env, uint32_t address) } static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, - bool is_user) + bool is_secure, bool is_user) { /* * Return true if we should use the default memory map as a @@ -1520,8 +1510,7 @@ static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, } if (arm_feature(env, ARM_FEATURE_M)) { - return env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] - & R_V7M_MPU_CTRL_PRIVDEFENA_MASK; + return env->v7m.mpu_ctrl[is_secure] & R_V7M_MPU_CTRL_PRIVDEFENA_MASK; } else { return regime_sctlr(env, mmu_idx) & SCTLR_BR; } @@ -1529,19 +1518,18 @@ static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, - target_ulong *page_size, + bool secure, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { ARMCPU *cpu = env_archcpu(env); int n; bool is_user = regime_is_user(env, mmu_idx); - *phys_ptr = address; - *page_size = TARGET_PAGE_SIZE; - *prot = 0; + result->f.phys_addr = address; + result->f.lg_page_size = TARGET_PAGE_BITS; + result->f.prot = 0; - if (regime_translation_disabled(env, mmu_idx) || + if (regime_translation_disabled(env, mmu_idx, secure) || m_is_ppb_region(env, address)) { /* * MPU disabled or M profile PPB access: use default memory map. @@ -1551,7 +1539,7 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, * which always does a direct read using address_space_ldl(), rather * than going via this function, so we don't need to check that here. */ - get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); + get_phys_addr_pmsav7_default(env, mmu_idx, address, &result->f.prot); } else { /* MPU enabled */ for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { /* region search */ @@ -1593,7 +1581,7 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, if (ranges_overlap(base, rmask, address & TARGET_PAGE_MASK, TARGET_PAGE_SIZE)) { - *page_size = 1; + result->f.lg_page_size = 0; } continue; } @@ -1631,18 +1619,19 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, continue; } if (rsize < TARGET_PAGE_BITS) { - *page_size = 1 << rsize; + result->f.lg_page_size = rsize; } break; } if (n == -1) { /* no hits */ - if (!pmsav7_use_background_region(cpu, mmu_idx, is_user)) { + if (!pmsav7_use_background_region(cpu, mmu_idx, secure, is_user)) { /* background fault */ fi->type = ARMFault_Background; return true; } - get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); + get_phys_addr_pmsav7_default(env, mmu_idx, address, + &result->f.prot); } else { /* a MPU hit! */ uint32_t ap = extract32(env->pmsav7.dracr[n], 8, 3); uint32_t xn = extract32(env->pmsav7.dracr[n], 12, 1); @@ -1659,16 +1648,16 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, case 5: break; /* no access */ case 3: - *prot |= PAGE_WRITE; + result->f.prot |= PAGE_WRITE; /* fall through */ case 2: case 6: - *prot |= PAGE_READ | PAGE_EXEC; + result->f.prot |= PAGE_READ | PAGE_EXEC; break; case 7: /* for v7M, same as 6; for R profile a reserved value */ if (arm_feature(env, ARM_FEATURE_M)) { - *prot |= PAGE_READ | PAGE_EXEC; + result->f.prot |= PAGE_READ | PAGE_EXEC; break; } /* fall through */ @@ -1684,16 +1673,16 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, case 1: case 2: case 3: - *prot |= PAGE_WRITE; + result->f.prot |= PAGE_WRITE; /* fall through */ case 5: case 6: - *prot |= PAGE_READ | PAGE_EXEC; + result->f.prot |= PAGE_READ | PAGE_EXEC; break; case 7: /* for v7M, same as 6; for R profile a reserved value */ if (arm_feature(env, ARM_FEATURE_M)) { - *prot |= PAGE_READ | PAGE_EXEC; + result->f.prot |= PAGE_READ | PAGE_EXEC; break; } /* fall through */ @@ -1706,20 +1695,19 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, /* execute never */ if (xn) { - *prot &= ~PAGE_EXEC; + result->f.prot &= ~PAGE_EXEC; } } } fi->type = ARMFault_Permission; fi->level = 1; - return !(*prot & (1 << access_type)); + return !(result->f.prot & (1 << access_type)); } bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, bool *is_subpage, + bool secure, GetPhysAddrResult *result, ARMMMUFaultInfo *fi, uint32_t *mregion) { /* @@ -1728,21 +1716,21 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, * mregion is (if not NULL) set to the region number which matched, * or -1 if no region number is returned (MPU off, address did not * hit a region, address hit in multiple regions). - * We set is_subpage to true if the region hit doesn't cover the - * entire TARGET_PAGE the address is within. + * If the region hit doesn't cover the entire TARGET_PAGE the address + * is within, then we set the result page_size to 1 to force the + * memory system to use a subpage. */ ARMCPU *cpu = env_archcpu(env); bool is_user = regime_is_user(env, mmu_idx); - uint32_t secure = regime_is_secure(env, mmu_idx); int n; int matchregion = -1; bool hit = false; uint32_t addr_page_base = address & TARGET_PAGE_MASK; uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); - *is_subpage = false; - *phys_ptr = address; - *prot = 0; + result->f.lg_page_size = TARGET_PAGE_BITS; + result->f.phys_addr = address; + result->f.prot = 0; if (mregion) { *mregion = -1; } @@ -1754,12 +1742,12 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, * are done in arm_v7m_load_vector(), which always does a direct * read using address_space_ldl(), rather than going via this function. */ - if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */ + if (regime_translation_disabled(env, mmu_idx, secure)) { /* MPU disabled */ hit = true; } else if (m_is_ppb_region(env, address)) { hit = true; } else { - if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) { + if (pmsav7_use_background_region(cpu, mmu_idx, secure, is_user)) { hit = true; } @@ -1792,13 +1780,13 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, ranges_overlap(base, limit - base + 1, addr_page_base, TARGET_PAGE_SIZE)) { - *is_subpage = true; + result->f.lg_page_size = 0; } continue; } if (base > addr_page_base || limit < addr_page_limit) { - *is_subpage = true; + result->f.lg_page_size = 0; } if (matchregion != -1) { @@ -1824,7 +1812,7 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, if (matchregion == -1) { /* hit using the background region */ - get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); + get_phys_addr_pmsav7_default(env, mmu_idx, address, &result->f.prot); } else { uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2); uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1); @@ -1839,9 +1827,9 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, xn = 1; } - *prot = simple_ap_to_rw_prot(env, mmu_idx, ap); - if (*prot && !xn && !(pxn && !is_user)) { - *prot |= PAGE_EXEC; + result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap); + if (result->f.prot && !xn && !(pxn && !is_user)) { + result->f.prot |= PAGE_EXEC; } /* * We don't need to look the attribute up in the MAIR0/MAIR1 @@ -1854,7 +1842,7 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, fi->type = ARMFault_Permission; fi->level = 1; - return !(*prot & (1 << access_type)); + return !(result->f.prot & (1 << access_type)); } static bool v8m_is_sau_exempt(CPUARMState *env, @@ -1874,8 +1862,8 @@ static bool v8m_is_sau_exempt(CPUARMState *env, } void v8m_security_lookup(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - V8M_SAttributes *sattrs) + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool is_secure, V8M_SAttributes *sattrs) { /* * Look up the security attributes for this address. Compare the @@ -1903,7 +1891,7 @@ void v8m_security_lookup(CPUARMState *env, uint32_t address, } if (idau_exempt || v8m_is_sau_exempt(env, address, access_type)) { - sattrs->ns = !regime_is_secure(env, mmu_idx); + sattrs->ns = !is_secure; return; } @@ -1984,17 +1972,15 @@ void v8m_security_lookup(CPUARMState *env, uint32_t address, static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, target_ulong *page_size, + bool secure, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { - uint32_t secure = regime_is_secure(env, mmu_idx); V8M_SAttributes sattrs = {}; bool ret; - bool mpu_is_subpage; if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs); + v8m_security_lookup(env, address, access_type, mmu_idx, + secure, &sattrs); if (access_type == MMU_INST_FETCH) { /* * Instruction fetches always use the MMU bank and the @@ -2020,9 +2006,9 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, } else { fi->type = ARMFault_QEMU_SFault; } - *page_size = sattrs.subpage ? 1 : TARGET_PAGE_SIZE; - *phys_ptr = address; - *prot = 0; + result->f.lg_page_size = sattrs.subpage ? 0 : TARGET_PAGE_BITS; + result->f.phys_addr = address; + result->f.prot = 0; return true; } } else { @@ -2032,7 +2018,7 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, * might downgrade a secure access to nonsecure. */ if (sattrs.ns) { - txattrs->secure = false; + result->f.attrs.secure = false; } else if (!secure) { /* * NS access to S memory must fault. @@ -2045,17 +2031,19 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). */ fi->type = ARMFault_QEMU_SFault; - *page_size = sattrs.subpage ? 1 : TARGET_PAGE_SIZE; - *phys_ptr = address; - *prot = 0; + result->f.lg_page_size = sattrs.subpage ? 0 : TARGET_PAGE_BITS; + result->f.phys_addr = address; + result->f.prot = 0; return true; } } } - ret = pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr, - txattrs, prot, &mpu_is_subpage, fi, NULL); - *page_size = sattrs.subpage || mpu_is_subpage ? 1 : TARGET_PAGE_SIZE; + ret = pmsav8_mpu_lookup(env, address, access_type, mmu_idx, secure, + result, fi, NULL); + if (sattrs.subpage) { + result->f.lg_page_size = 0; + } return ret; } @@ -2068,14 +2056,14 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, * ref: shared/translation/attrs/S2AttrDecode() * .../S2ConvertAttrsHints() */ -static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs) +static uint8_t convert_stage2_attrs(uint64_t hcr, uint8_t s2attrs) { uint8_t hiattr = extract32(s2attrs, 2, 2); uint8_t loattr = extract32(s2attrs, 0, 2); uint8_t hihint = 0, lohint = 0; if (hiattr != 0) { /* normal memory */ - if (arm_hcr_el2_eff(env) & HCR_CD) { /* cache disabled */ + if (hcr & HCR_CD) { /* cache disabled */ hiattr = loattr = 1; /* non-cacheable */ } else { if (hiattr != 1) { /* Write-through or write-back */ @@ -2121,12 +2109,12 @@ static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) * s1 and s2 for the HCR_EL2.FWB == 0 case, returning the * combined attributes in MAIR_EL1 format. */ -static uint8_t combined_attrs_nofwb(CPUARMState *env, +static uint8_t combined_attrs_nofwb(uint64_t hcr, ARMCacheAttrs s1, ARMCacheAttrs s2) { uint8_t s1lo, s2lo, s1hi, s2hi, s2_mair_attrs, ret_attrs; - s2_mair_attrs = convert_stage2_attrs(env, s2.attrs); + s2_mair_attrs = convert_stage2_attrs(hcr, s2.attrs); s1lo = extract32(s1.attrs, 0, 4); s2lo = extract32(s2_mair_attrs, 0, 4); @@ -2181,8 +2169,7 @@ static uint8_t force_cacheattr_nibble_wb(uint8_t attr) * s1 and s2 for the HCR_EL2.FWB == 1 case, returning the * combined attributes in MAIR_EL1 format. */ -static uint8_t combined_attrs_fwb(CPUARMState *env, - ARMCacheAttrs s1, ARMCacheAttrs s2) +static uint8_t combined_attrs_fwb(ARMCacheAttrs s1, ARMCacheAttrs s2) { switch (s2.attrs) { case 7: @@ -2227,7 +2214,7 @@ static uint8_t combined_attrs_fwb(CPUARMState *env, * @s1: Attributes from stage 1 walk * @s2: Attributes from stage 2 walk */ -static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, +static ARMCacheAttrs combine_cacheattrs(uint64_t hcr, ARMCacheAttrs s1, ARMCacheAttrs s2) { ARMCacheAttrs ret; @@ -2254,10 +2241,10 @@ static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, } /* Combine memory type and cacheability attributes */ - if (arm_hcr_el2_eff(env) & HCR_FWB) { - ret.attrs = combined_attrs_fwb(env, s1, s2); + if (hcr & HCR_FWB) { + ret.attrs = combined_attrs_fwb(s1, s2); } else { - ret.attrs = combined_attrs_nofwb(env, s1, s2); + ret.attrs = combined_attrs_nofwb(hcr, s1, s2); } /* @@ -2280,38 +2267,84 @@ static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, return ret; } -/** - * get_phys_addr - get the physical address for this virtual address - * - * Find the physical address corresponding to the given virtual address, - * by doing a translation table walk on MMU based systems or using the - * MPU state on MPU based systems. - * - * Returns false if the translation was successful. Otherwise, phys_ptr, attrs, - * prot and page_size may not be filled in, and the populated fsr value provides - * information on why the translation aborted, in the format of a - * DFSR/IFSR fault register, with the following caveats: - * * we honour the short vs long DFSR format differences. - * * the WnR bit is never set (the caller must do this). - * * for PSMAv5 based systems we don't bother to return a full FSR format - * value. - * - * @env: CPUARMState - * @address: virtual address to get physical address for - * @access_type: 0 for read, 1 for write, 2 for execute - * @mmu_idx: MMU index indicating required translation regime - * @phys_ptr: set to the physical address corresponding to the virtual address - * @attrs: set to the memory transaction attributes to use - * @prot: set to the permissions for the page containing phys_ptr - * @page_size: set to the size of the page containing phys_ptr - * @fi: set to fault info if the translation fails - * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes +/* + * MMU disabled. S1 addresses within aa64 translation regimes are + * still checked for bounds -- see AArch64.S1DisabledOutput(). */ -bool get_phys_addr(CPUARMState *env, target_ulong address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, - ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) +static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address, + MMUAccessType access_type, + ARMMMUIdx mmu_idx, bool is_secure, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + uint8_t memattr = 0x00; /* Device nGnRnE */ + uint8_t shareability = 0; /* non-sharable */ + + if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) { + int r_el = regime_el(env, mmu_idx); + + if (arm_el_is_aa64(env, r_el)) { + int pamax = arm_pamax(env_archcpu(env)); + uint64_t tcr = env->cp15.tcr_el[r_el]; + int addrtop, tbi; + + tbi = aa64_va_parameter_tbi(tcr, mmu_idx); + if (access_type == MMU_INST_FETCH) { + tbi &= ~aa64_va_parameter_tbid(tcr, mmu_idx); + } + tbi = (tbi >> extract64(address, 55, 1)) & 1; + addrtop = (tbi ? 55 : 63); + + if (extract64(address, pamax, addrtop - pamax + 1) != 0) { + fi->type = ARMFault_AddressSize; + fi->level = 0; + fi->stage2 = false; + return 1; + } + + /* + * When TBI is disabled, we've just validated that all of the + * bits above PAMax are zero, so logically we only need to + * clear the top byte for TBI. But it's clearer to follow + * the pseudocode set of addrdesc.paddress. + */ + address = extract64(address, 0, 52); + } + + /* Fill in cacheattr a-la AArch64.TranslateAddressS1Off. */ + if (r_el == 1) { + uint64_t hcr = arm_hcr_el2_eff_secstate(env, is_secure); + if (hcr & HCR_DC) { + if (hcr & HCR_DCT) { + memattr = 0xf0; /* Tagged, Normal, WB, RWA */ + } else { + memattr = 0xff; /* Normal, WB, RWA */ + } + } + } + if (memattr == 0 && access_type == MMU_INST_FETCH) { + if (regime_sctlr(env, mmu_idx) & SCTLR_I) { + memattr = 0xee; /* Normal, WT, RA, NT */ + } else { + memattr = 0x44; /* Normal, NC, No */ + } + shareability = 2; /* outer sharable */ + } + result->cacheattrs.is_s2_format = false; + } + + result->f.phys_addr = address; + result->f.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + result->f.lg_page_size = TARGET_PAGE_BITS; + result->cacheattrs.shareability = shareability; + result->cacheattrs.attrs = memattr; + return 0; +} + +bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + bool is_secure, GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) { ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx); @@ -2322,43 +2355,54 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, */ if (arm_feature(env, ARM_FEATURE_EL2)) { hwaddr ipa; - int s2_prot; + int s1_prot; int ret; - bool ipa_secure; - ARMCacheAttrs cacheattrs2 = {}; + bool ipa_secure, s2walk_secure; + ARMCacheAttrs cacheattrs1; ARMMMUIdx s2_mmu_idx; bool is_el0; + uint64_t hcr; - ret = get_phys_addr(env, address, access_type, s1_mmu_idx, &ipa, - attrs, prot, page_size, fi, cacheattrs); + ret = get_phys_addr_with_secure(env, address, access_type, + s1_mmu_idx, is_secure, result, fi); /* If S1 fails or S2 is disabled, return early. */ - if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2)) { - *phys_ptr = ipa; + if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2, + is_secure)) { return ret; } - ipa_secure = attrs->secure; - if (arm_is_secure_below_el3(env)) { - if (ipa_secure) { - attrs->secure = !(env->cp15.vstcr_el2 & VSTCR_SW); - } else { - attrs->secure = !(env->cp15.vtcr_el2 & VTCR_NSW); - } + ipa = result->f.phys_addr; + ipa_secure = result->f.attrs.secure; + if (is_secure) { + /* Select TCR based on the NS bit from the S1 walk. */ + s2walk_secure = !(ipa_secure + ? env->cp15.vstcr_el2 & VSTCR_SW + : env->cp15.vtcr_el2 & VTCR_NSW); } else { assert(!ipa_secure); + s2walk_secure = false; } - s2_mmu_idx = attrs->secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; - is_el0 = mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_SE10_0; + s2_mmu_idx = (s2walk_secure + ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2); + is_el0 = mmu_idx == ARMMMUIdx_E10_0; - /* S1 is done. Now do S2 translation. */ - ret = get_phys_addr_lpae(env, ipa, access_type, s2_mmu_idx, is_el0, - phys_ptr, attrs, &s2_prot, - page_size, fi, &cacheattrs2); + /* + * S1 is done, now do S2 translation. + * Save the stage1 results so that we may merge + * prot and cacheattrs later. + */ + s1_prot = result->f.prot; + cacheattrs1 = result->cacheattrs; + memset(result, 0, sizeof(*result)); + + ret = get_phys_addr_lpae(env, ipa, access_type, s2_mmu_idx, + s2walk_secure, is_el0, result, fi); fi->s2addr = ipa; + /* Combine the S1 and S2 perms. */ - *prot &= s2_prot; + result->f.prot &= s1_prot; /* If S2 fails, return early. */ if (ret) { @@ -2366,7 +2410,8 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, } /* Combine the S1 and S2 cache attributes. */ - if (arm_hcr_el2_eff(env) & HCR_DC) { + hcr = arm_hcr_el2_eff_secstate(env, is_secure); + if (hcr & HCR_DC) { /* * HCR.DC forces the first stage attributes to * Normal Non-Shareable, @@ -2374,24 +2419,24 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, * Outer Write-Back Read-Allocate Write-Allocate. * Do not overwrite Tagged within attrs. */ - if (cacheattrs->attrs != 0xf0) { - cacheattrs->attrs = 0xff; + if (cacheattrs1.attrs != 0xf0) { + cacheattrs1.attrs = 0xff; } - cacheattrs->shareability = 0; + cacheattrs1.shareability = 0; } - *cacheattrs = combine_cacheattrs(env, *cacheattrs, cacheattrs2); + result->cacheattrs = combine_cacheattrs(hcr, cacheattrs1, + result->cacheattrs); + + /* + * Check if IPA translates to secure or non-secure PA space. + * Note that VSTCR overrides VTCR and {N}SW overrides {N}SA. + */ + result->f.attrs.secure = + (is_secure + && !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW)) + && (ipa_secure + || !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW)))); - /* Check if IPA translates to secure or non-secure PA space. */ - if (arm_is_secure_below_el3(env)) { - if (ipa_secure) { - attrs->secure = - !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW)); - } else { - attrs->secure = - !((env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW)) - || (env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW))); - } - } return 0; } else { /* @@ -2406,8 +2451,8 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, * cannot upgrade an non-secure translation regime's attributes * to secure. */ - attrs->secure = regime_is_secure(env, mmu_idx); - attrs->user = regime_is_user(env, mmu_idx); + result->f.attrs.secure = is_secure; + result->f.attrs.user = regime_is_user(env, mmu_idx); /* * Fast Context Switch Extension. This doesn't exist at all in v8. @@ -2424,20 +2469,20 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, if (arm_feature(env, ARM_FEATURE_PMSA)) { bool ret; - *page_size = TARGET_PAGE_SIZE; + result->f.lg_page_size = TARGET_PAGE_BITS; if (arm_feature(env, ARM_FEATURE_V8)) { /* PMSAv8 */ ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx, - phys_ptr, attrs, prot, page_size, fi); + is_secure, result, fi); } else if (arm_feature(env, ARM_FEATURE_V7)) { /* PMSAv7 */ ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, - phys_ptr, prot, page_size, fi); + is_secure, result, fi); } else { /* Pre-v7 MPU */ ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, - phys_ptr, prot, fi); + is_secure, result, fi); } qemu_log_mask(CPU_LOG_MMU, "PMSA MPU lookup for %s at 0x%08" PRIx32 " mmu_idx %u -> %s (prot %c%c%c)\n", @@ -2445,114 +2490,87 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, (access_type == MMU_DATA_STORE ? "writing" : "execute"), (uint32_t)address, mmu_idx, ret ? "Miss" : "Hit", - *prot & PAGE_READ ? 'r' : '-', - *prot & PAGE_WRITE ? 'w' : '-', - *prot & PAGE_EXEC ? 'x' : '-'); + result->f.prot & PAGE_READ ? 'r' : '-', + result->f.prot & PAGE_WRITE ? 'w' : '-', + result->f.prot & PAGE_EXEC ? 'x' : '-'); return ret; } /* Definitely a real MMU, not an MPU */ - if (regime_translation_disabled(env, mmu_idx)) { - uint64_t hcr; - uint8_t memattr; - - /* - * MMU disabled. S1 addresses within aa64 translation regimes are - * still checked for bounds -- see AArch64.TranslateAddressS1Off. - */ - if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) { - int r_el = regime_el(env, mmu_idx); - if (arm_el_is_aa64(env, r_el)) { - int pamax = arm_pamax(env_archcpu(env)); - uint64_t tcr = env->cp15.tcr_el[r_el]; - int addrtop, tbi; - - tbi = aa64_va_parameter_tbi(tcr, mmu_idx); - if (access_type == MMU_INST_FETCH) { - tbi &= ~aa64_va_parameter_tbid(tcr, mmu_idx); - } - tbi = (tbi >> extract64(address, 55, 1)) & 1; - addrtop = (tbi ? 55 : 63); - - if (extract64(address, pamax, addrtop - pamax + 1) != 0) { - fi->type = ARMFault_AddressSize; - fi->level = 0; - fi->stage2 = false; - return 1; - } - - /* - * When TBI is disabled, we've just validated that all of the - * bits above PAMax are zero, so logically we only need to - * clear the top byte for TBI. But it's clearer to follow - * the pseudocode set of addrdesc.paddress. - */ - address = extract64(address, 0, 52); - } - } - *phys_ptr = address; - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - *page_size = TARGET_PAGE_SIZE; - - /* Fill in cacheattr a-la AArch64.TranslateAddressS1Off. */ - hcr = arm_hcr_el2_eff(env); - cacheattrs->shareability = 0; - cacheattrs->is_s2_format = false; - if (hcr & HCR_DC) { - if (hcr & HCR_DCT) { - memattr = 0xf0; /* Tagged, Normal, WB, RWA */ - } else { - memattr = 0xff; /* Normal, WB, RWA */ - } - } else if (access_type == MMU_INST_FETCH) { - if (regime_sctlr(env, mmu_idx) & SCTLR_I) { - memattr = 0xee; /* Normal, WT, RA, NT */ - } else { - memattr = 0x44; /* Normal, NC, No */ - } - cacheattrs->shareability = 2; /* outer sharable */ - } else { - memattr = 0x00; /* Device, nGnRnE */ - } - cacheattrs->attrs = memattr; - return 0; + if (regime_translation_disabled(env, mmu_idx, is_secure)) { + return get_phys_addr_disabled(env, address, access_type, mmu_idx, + is_secure, result, fi); } - if (regime_using_lpae_format(env, mmu_idx)) { - return get_phys_addr_lpae(env, address, access_type, mmu_idx, false, - phys_ptr, attrs, prot, page_size, - fi, cacheattrs); + return get_phys_addr_lpae(env, address, access_type, mmu_idx, + is_secure, false, result, fi); } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { return get_phys_addr_v6(env, address, access_type, mmu_idx, - phys_ptr, attrs, prot, page_size, fi); + is_secure, result, fi); } else { return get_phys_addr_v5(env, address, access_type, mmu_idx, - phys_ptr, prot, page_size, fi); + is_secure, result, fi); } } +bool get_phys_addr(CPUARMState *env, target_ulong address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + GetPhysAddrResult *result, ARMMMUFaultInfo *fi) +{ + bool is_secure; + + switch (mmu_idx) { + case ARMMMUIdx_E10_0: + case ARMMMUIdx_E10_1: + case ARMMMUIdx_E10_1_PAN: + case ARMMMUIdx_E20_0: + case ARMMMUIdx_E20_2: + case ARMMMUIdx_E20_2_PAN: + case ARMMMUIdx_Stage1_E0: + case ARMMMUIdx_Stage1_E1: + case ARMMMUIdx_Stage1_E1_PAN: + case ARMMMUIdx_E2: + is_secure = arm_is_secure_below_el3(env); + break; + case ARMMMUIdx_Stage2: + case ARMMMUIdx_MPrivNegPri: + case ARMMMUIdx_MUserNegPri: + case ARMMMUIdx_MPriv: + case ARMMMUIdx_MUser: + is_secure = false; + break; + case ARMMMUIdx_E3: + case ARMMMUIdx_Stage2_S: + case ARMMMUIdx_MSPrivNegPri: + case ARMMMUIdx_MSUserNegPri: + case ARMMMUIdx_MSPriv: + case ARMMMUIdx_MSUser: + is_secure = true; + break; + default: + g_assert_not_reached(); + } + return get_phys_addr_with_secure(env, address, access_type, mmu_idx, + is_secure, result, fi); +} + hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, MemTxAttrs *attrs) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; - hwaddr phys_addr; - target_ulong page_size; - int prot; - bool ret; + GetPhysAddrResult res = {}; ARMMMUFaultInfo fi = {}; ARMMMUIdx mmu_idx = arm_mmu_idx(env); - ARMCacheAttrs cacheattrs = {}; + bool ret; - *attrs = (MemTxAttrs) {}; - - ret = get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &phys_addr, - attrs, &prot, &page_size, &fi, &cacheattrs); + ret = get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &res, &fi); + *attrs = res.f.attrs; if (ret) { return -1; } - return phys_addr; + return res.f.phys_addr; } diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index d6f7ef94fe..9cae8fd352 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -5384,8 +5384,8 @@ bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env, g_assert(tlb_hit(comparator, addr)); # endif - CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; - info->attrs = iotlbentry->attrs; + CPUTLBEntryFull *full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + info->attrs = full->attrs; } #endif diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index 5a709eab56..49601394ec 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -209,11 +209,8 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, { ARMCPU *cpu = ARM_CPU(cs); ARMMMUFaultInfo fi = {}; - hwaddr phys_addr; - target_ulong page_size; - int prot, ret; - MemTxAttrs attrs = {}; - ARMCacheAttrs cacheattrs = {}; + GetPhysAddrResult res = {}; + int ret; /* * Walk the page table and (if the mapping exists) add the page @@ -223,25 +220,23 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, */ ret = get_phys_addr(&cpu->env, address, access_type, core_to_arm_mmu_idx(&cpu->env, mmu_idx), - &phys_addr, &attrs, &prot, &page_size, - &fi, &cacheattrs); + &res, &fi); if (likely(!ret)) { /* * Map a single [sub]page. Regions smaller than our declared * target page size are handled specially, so for those we * pass in the exact addresses. */ - if (page_size >= TARGET_PAGE_SIZE) { - phys_addr &= TARGET_PAGE_MASK; + if (res.f.lg_page_size >= TARGET_PAGE_BITS) { + res.f.phys_addr &= TARGET_PAGE_MASK; address &= TARGET_PAGE_MASK; } /* Notice and record tagged memory. */ - if (cpu_isar_feature(aa64_mte, cpu) && cacheattrs.attrs == 0xf0) { - arm_tlb_mte_tagged(&attrs) = true; + if (cpu_isar_feature(aa64_mte, cpu) && res.cacheattrs.attrs == 0xf0) { + arm_tlb_mte_tagged(&res.f.attrs) = true; } - tlb_set_page_with_attrs(cs, address, phys_addr, attrs, - prot, mmu_idx, page_size); + tlb_set_page_full(cs, mmu_idx, address, &res.f); return true; } else if (probe) { return false; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 29d4077c79..6f6fcfcc18 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -111,14 +111,6 @@ static int get_a64_user_mem_index(DisasContext *s) case ARMMMUIdx_E20_2_PAN: useridx = ARMMMUIdx_E20_0; break; - case ARMMMUIdx_SE10_1: - case ARMMMUIdx_SE10_1_PAN: - useridx = ARMMMUIdx_SE10_0; - break; - case ARMMMUIdx_SE20_2: - case ARMMMUIdx_SE20_2_PAN: - useridx = ARMMMUIdx_SE20_0; - break; default: g_assert_not_reached(); } @@ -2219,17 +2211,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) * it is required for halting debug disabled: it will UNDEF. * Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction. */ - if (semihosting_enabled() && imm16 == 0xf000) { -#ifndef CONFIG_USER_ONLY - /* In system mode, don't allow userspace access to semihosting, - * to provide some semblance of security (and for consistency - * with our 32-bit semihosting). - */ - if (s->current_el == 0) { - unallocated_encoding(s); - break; - } -#endif + if (semihosting_enabled(s->current_el == 0) && imm16 == 0xf000) { gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST); } else { unallocated_encoding(s); @@ -14670,7 +14652,7 @@ static bool is_guarded_page(CPUARMState *env, DisasContext *s) * table entry even for that case. */ return (tlb_hit(entry->addr_code, addr) && - arm_tlb_bti_gp(&env_tlb(env)->d[mmu_idx].iotlb[index].attrs)); + arm_tlb_bti_gp(&env_tlb(env)->d[mmu_idx].fulltlb[index].attrs)); #endif } diff --git a/target/arm/translate-neon.c b/target/arm/translate-neon.c index 321c17e2c7..4016339d46 100644 --- a/target/arm/translate-neon.c +++ b/target/arm/translate-neon.c @@ -584,7 +584,11 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) case 3: return false; case 4: - align = pow2_align(size + 2); + if (size == 2) { + align = pow2_align(3); + } else { + align = pow2_align(size + 2); + } break; default: g_assert_not_reached(); diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 41f8b12259..621a2abb22 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -529,9 +529,10 @@ static void do_predtest(DisasContext *s, int dofs, int gofs, int words) } /* For each element size, the bits within a predicate word that are active. */ -const uint64_t pred_esz_masks[4] = { +const uint64_t pred_esz_masks[5] = { 0xffffffffffffffffull, 0x5555555555555555ull, - 0x1111111111111111ull, 0x0101010101010101ull + 0x1111111111111111ull, 0x0101010101010101ull, + 0x0001000100010001ull, }; static bool trans_INVALID(DisasContext *s, arg_INVALID *a) diff --git a/target/arm/translate.c b/target/arm/translate.c index 8dc4b43530..73c4e3d134 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -237,16 +237,12 @@ static inline int get_a32_user_mem_index(DisasContext *s) * otherwise, access as if at PL0. */ switch (s->mmu_idx) { + case ARMMMUIdx_E3: case ARMMMUIdx_E2: /* this one is UNPREDICTABLE */ case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1_PAN: return arm_to_core_mmu_idx(ARMMMUIdx_E10_0); - case ARMMMUIdx_SE3: - case ARMMMUIdx_SE10_0: - case ARMMMUIdx_SE10_1: - case ARMMMUIdx_SE10_1_PAN: - return arm_to_core_mmu_idx(ARMMMUIdx_SE10_0); case ARMMMUIdx_MUser: case ARMMMUIdx_MPriv: return arm_to_core_mmu_idx(ARMMMUIdx_MUser); @@ -1169,10 +1165,7 @@ static inline void gen_hlt(DisasContext *s, int imm) * semihosting, to provide some semblance of security * (and for consistency with our 32-bit semihosting). */ - if (semihosting_enabled() && -#ifndef CONFIG_USER_ONLY - s->current_el != 0 && -#endif + if (semihosting_enabled(s->current_el != 0) && (imm == (s->thumb ? 0x3c : 0xf000))) { gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST); return; @@ -6598,10 +6591,7 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a) /* BKPT is OK with ECI set and leaves it untouched */ s->eci_handled = true; if (arm_dc_feature(s, ARM_FEATURE_M) && - semihosting_enabled() && -#ifndef CONFIG_USER_ONLY - !IS_USER(s) && -#endif + semihosting_enabled(s->current_el == 0) && (a->imm == 0xab)) { gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST); } else { @@ -8098,7 +8088,7 @@ static TCGv_i32 op_addr_block_pre(DisasContext *s, arg_ldst_block *a, int n) * If the writeback is incrementing SP rather than * decrementing it, and the initial SP is below the * stack limit but the final written-back SP would - * be above, then then we must not perform any memory + * be above, then we must not perform any memory * accesses, but it is IMPDEF whether we generate * an exception. We choose to do so in this case. * At this point 'addr' is the lowest address, so @@ -8806,10 +8796,8 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a) { const uint32_t semihost_imm = s->thumb ? 0xab : 0x123456; - if (!arm_dc_feature(s, ARM_FEATURE_M) && semihosting_enabled() && -#ifndef CONFIG_USER_ONLY - !IS_USER(s) && -#endif + if (!arm_dc_feature(s, ARM_FEATURE_M) && + semihosting_enabled(s->current_el == 0) && (a->imm == semihost_imm)) { gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST); } else { @@ -9401,8 +9389,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->vfp_enabled = 1; dc->be_data = MO_TE; dc->v7m_handler_mode = EX_TBFLAG_M32(tb_flags, HANDLER); - dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) && - regime_is_secure(env, dc->mmu_idx); + dc->v8m_secure = EX_TBFLAG_M32(tb_flags, SECURE); dc->v8m_stackcheck = EX_TBFLAG_M32(tb_flags, STACKCHECK); dc->v8m_fpccr_s_wrong = EX_TBFLAG_M32(tb_flags, FPCCR_S_WRONG); dc->v7m_new_fp_ctxt_needed = @@ -9934,7 +9921,8 @@ static const TranslatorOps thumb_translator_ops = { }; /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc = { }; const TranslatorOps *ops = &arm_translator_ops; @@ -9949,7 +9937,7 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) } #endif - translator_loop(ops, &dc.base, cpu, tb, max_insns); + translator_loop(cpu, tb, max_insns, pc, host_pc, ops, &dc.base); } void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 05b992ff73..0d2861179d 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -32,6 +32,13 @@ static void avr_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.pc_w = value / 2; /* internally PC points to words */ } +static vaddr avr_cpu_get_pc(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + + return cpu->env.pc_w * 2; +} + static bool avr_cpu_has_work(CPUState *cs) { AVRCPU *cpu = AVR_CPU(cs); @@ -47,7 +54,7 @@ static void avr_cpu_synchronize_from_tb(CPUState *cs, AVRCPU *cpu = AVR_CPU(cs); CPUAVRState *env = &cpu->env; - env->pc_w = tb->pc / 2; /* internally PC points to words */ + env->pc_w = tb_pc(tb) / 2; /* internally PC points to words */ } static void avr_cpu_reset(DeviceState *ds) @@ -214,6 +221,7 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = avr_cpu_has_work; cc->dump_state = avr_cpu_dump_state; cc->set_pc = avr_cpu_set_pc; + cc->get_pc = avr_cpu_get_pc; dc->vmsd = &vms_avr_cpu; cc->sysemu_ops = &avr_sysemu_ops; cc->disas_set_info = avr_cpu_disas_set_info; diff --git a/target/avr/helper.c b/target/avr/helper.c index db76452f9a..156dde4e92 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -28,36 +28,41 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { - bool ret = false; - CPUClass *cc = CPU_GET_CLASS(cs); AVRCPU *cpu = AVR_CPU(cs); CPUAVRState *env = &cpu->env; + /* + * We cannot separate a skip from the next instruction, + * as the skip would not be preserved across the interrupt. + * Separating the two insn normally only happens at page boundaries. + */ + if (env->skip) { + return false; + } + if (interrupt_request & CPU_INTERRUPT_RESET) { if (cpu_interrupts_enabled(env)) { cs->exception_index = EXCP_RESET; - cc->tcg_ops->do_interrupt(cs); + avr_cpu_do_interrupt(cs); cs->interrupt_request &= ~CPU_INTERRUPT_RESET; - - ret = true; + return true; } } if (interrupt_request & CPU_INTERRUPT_HARD) { if (cpu_interrupts_enabled(env) && env->intsrc != 0) { int index = ctz32(env->intsrc); cs->exception_index = EXCP_INT(index); - cc->tcg_ops->do_interrupt(cs); + avr_cpu_do_interrupt(cs); env->intsrc &= env->intsrc - 1; /* clear the interrupt */ if (!env->intsrc) { cs->interrupt_request &= ~CPU_INTERRUPT_HARD; } - - ret = true; + return true; } } - return ret; + return false; } void avr_cpu_do_interrupt(CPUState *cs) @@ -102,38 +107,50 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) { - int prot = 0; - MemTxAttrs attrs = {}; + int prot, page_size = TARGET_PAGE_SIZE; uint32_t paddr; address &= TARGET_PAGE_MASK; if (mmu_idx == MMU_CODE_IDX) { - /* access to code in flash */ + /* Access to code in flash. */ paddr = OFFSET_CODE + address; prot = PAGE_READ | PAGE_EXEC; - if (paddr + TARGET_PAGE_SIZE > OFFSET_DATA) { + if (paddr >= OFFSET_DATA) { + /* + * This should not be possible via any architectural operations. + * There is certainly not an exception that we can deliver. + * Accept probing that might come from generic code. + */ + if (probe) { + return false; + } error_report("execution left flash memory"); abort(); } - } else if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { - /* - * access to CPU registers, exit and rebuilt this TB to use full access - * incase it touches specially handled registers like SREG or SP - */ - AVRCPU *cpu = AVR_CPU(cs); - CPUAVRState *env = &cpu->env; - env->fullacc = 1; - cpu_loop_exit_restore(cs, retaddr); } else { - /* access to memory. nothing special */ + /* Access to memory. */ paddr = OFFSET_DATA + address; prot = PAGE_READ | PAGE_WRITE; + if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* + * Access to CPU registers, exit and rebuilt this TB to use + * full access in case it touches specially handled registers + * like SREG or SP. For probing, set page_size = 1, in order + * to force tlb_fill to be called for the next access. + */ + if (probe) { + page_size = 1; + } else { + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + env->fullacc = 1; + cpu_loop_exit_restore(cs, retaddr); + } + } } - tlb_set_page_with_attrs(cs, address, paddr, attrs, prot, - mmu_idx, TARGET_PAGE_SIZE); - + tlb_set_page(cs, address, paddr, prot, mmu_idx, page_size); return true; } diff --git a/target/avr/translate.c b/target/avr/translate.c index dc9c3d6bcc..e65b6008c0 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2971,8 +2971,18 @@ static void avr_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) if (skip_label) { canonicalize_skip(ctx); gen_set_label(skip_label); - if (ctx->base.is_jmp == DISAS_NORETURN) { + + switch (ctx->base.is_jmp) { + case DISAS_NORETURN: ctx->base.is_jmp = DISAS_CHAIN; + break; + case DISAS_NEXT: + if (ctx->base.tb->flags & TB_FLAGS_SKIP) { + ctx->base.is_jmp = DISAS_TOO_MANY; + } + break; + default: + break; } } @@ -2989,6 +2999,11 @@ static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); bool nonconst_skip = canonicalize_skip(ctx); + /* + * Because we disable interrupts while env->skip is set, + * we must return to the main loop to re-evaluate afterward. + */ + bool force_exit = ctx->base.tb->flags & TB_FLAGS_SKIP; switch (ctx->base.is_jmp) { case DISAS_NORETURN: @@ -2997,7 +3012,7 @@ static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) case DISAS_NEXT: case DISAS_TOO_MANY: case DISAS_CHAIN: - if (!nonconst_skip) { + if (!nonconst_skip && !force_exit) { /* Note gen_goto_tb checks singlestep. */ gen_goto_tb(ctx, 1, ctx->npc); break; @@ -3005,8 +3020,11 @@ static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) tcg_gen_movi_tl(cpu_pc, ctx->npc); /* fall through */ case DISAS_LOOKUP: - tcg_gen_lookup_and_goto_ptr(); - break; + if (!force_exit) { + tcg_gen_lookup_and_goto_ptr(); + break; + } + /* fall through */ case DISAS_EXIT: tcg_gen_exit_tb(NULL, 0); break; @@ -3031,10 +3049,11 @@ static const TranslatorOps avr_tr_ops = { .disas_log = avr_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc = { }; - translator_loop(&avr_tr_ops, &dc.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &avr_tr_ops, &dc.base); } void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, diff --git a/target/cris/cpu.c b/target/cris/cpu.c index ed6c781342..22f5c70f39 100644 --- a/target/cris/cpu.c +++ b/target/cris/cpu.c @@ -35,6 +35,13 @@ static void cris_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.pc = value; } +static vaddr cris_cpu_get_pc(CPUState *cs) +{ + CRISCPU *cpu = CRIS_CPU(cs); + + return cpu->env.pc; +} + static bool cris_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); @@ -297,6 +304,7 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = cris_cpu_has_work; cc->dump_state = cris_cpu_dump_state; cc->set_pc = cris_cpu_set_pc; + cc->get_pc = cris_cpu_get_pc; cc->gdb_read_register = cris_cpu_gdb_read_register; cc->gdb_write_register = cris_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/cris/translate.c b/target/cris/translate.c index ac101344a3..73385b0b3c 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -3286,10 +3286,11 @@ static const TranslatorOps cris_tr_ops = { .disas_log = cris_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc; - translator_loop(&cris_tr_ops, &dc.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &cris_tr_ops, &dc.base); } void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags) diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc index dc890a557f..5d2a102c18 100644 --- a/target/hexagon/attribs_def.h.inc +++ b/target/hexagon/attribs_def.h.inc @@ -1,5 +1,5 @@ /* - * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved. * * 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 @@ -38,6 +38,17 @@ DEF_ATTRIB(SUBINSN, "sub-instruction", "", "") /* Load and Store attributes */ DEF_ATTRIB(LOAD, "Loads from memory", "", "") DEF_ATTRIB(STORE, "Stores to memory", "", "") +DEF_ATTRIB(STOREIMMED, "Stores immed to memory", "", "") +DEF_ATTRIB(MEMSIZE_0B, "Memory width is 0 byte", "", "") +DEF_ATTRIB(MEMSIZE_1B, "Memory width is 1 byte", "", "") +DEF_ATTRIB(MEMSIZE_2B, "Memory width is 2 bytes", "", "") +DEF_ATTRIB(MEMSIZE_4B, "Memory width is 4 bytes", "", "") +DEF_ATTRIB(MEMSIZE_8B, "Memory width is 8 bytes", "", "") +DEF_ATTRIB(SCALAR_STORE, "Store is scalar", "", "") +DEF_ATTRIB(REGWRSIZE_1B, "Memory width is 1 byte", "", "") +DEF_ATTRIB(REGWRSIZE_2B, "Memory width is 2 bytes", "", "") +DEF_ATTRIB(REGWRSIZE_4B, "Memory width is 4 bytes", "", "") +DEF_ATTRIB(REGWRSIZE_8B, "Memory width is 8 bytes", "", "") DEF_ATTRIB(MEMLIKE, "Memory-like instruction", "", "") DEF_ATTRIB(MEMLIKE_PACKET_RULES, "follows Memory-like packet rules", "", "") @@ -71,6 +82,11 @@ DEF_ATTRIB(COF, "Change-of-flow instruction", "", "") DEF_ATTRIB(CONDEXEC, "May be cancelled by a predicate", "", "") DEF_ATTRIB(DOTNEWVALUE, "Uses a register value generated in this pkt", "", "") DEF_ATTRIB(NEWCMPJUMP, "Compound compare and jump", "", "") +DEF_ATTRIB(NVSTORE, "New-value store", "", "") +DEF_ATTRIB(MEMOP, "memop", "", "") + +DEF_ATTRIB(ROPS_2, "Compound instruction worth 2 RISC-ops", "", "") +DEF_ATTRIB(ROPS_3, "Compound instruction worth 3 RISC-ops", "", "") /* access to implicit registers */ DEF_ATTRIB(IMPLICIT_WRITES_LR, "Writes the link register", "", "UREG.LR") @@ -87,6 +103,9 @@ DEF_ATTRIB(IMPLICIT_WRITES_P3, "May write Predicate 3", "", "UREG.P3") DEF_ATTRIB(IMPLICIT_READS_PC, "Reads the PC register", "", "") DEF_ATTRIB(IMPLICIT_WRITES_USR, "May write USR", "", "") DEF_ATTRIB(WRITES_PRED_REG, "Writes a predicate register", "", "") +DEF_ATTRIB(COMMUTES, "The operation is communitive", "", "") +DEF_ATTRIB(DEALLOCRET, "dealloc_return", "", "") +DEF_ATTRIB(DEALLOCFRAME, "deallocframe", "", "") DEF_ATTRIB(CRSLOT23, "Can execute in slot 2 or slot 3 (CR)", "", "") DEF_ATTRIB(IT_NOP, "nop instruction", "", "") @@ -94,17 +113,21 @@ DEF_ATTRIB(IT_EXTENDER, "constant extender instruction", "", "") /* Restrictions to make note of */ +DEF_ATTRIB(RESTRICT_COF_MAX1, "One change-of-flow per packet", "", "") +DEF_ATTRIB(RESTRICT_NOPACKET, "Not allowed in a packet", "", "") DEF_ATTRIB(RESTRICT_SLOT0ONLY, "Must execute on slot0", "", "") DEF_ATTRIB(RESTRICT_SLOT1ONLY, "Must execute on slot1", "", "") DEF_ATTRIB(RESTRICT_SLOT2ONLY, "Must execute on slot2", "", "") DEF_ATTRIB(RESTRICT_SLOT3ONLY, "Must execute on slot3", "", "") DEF_ATTRIB(RESTRICT_NOSLOT1, "No slot 1 instruction in parallel", "", "") DEF_ATTRIB(RESTRICT_PREFERSLOT0, "Try to encode into slot 0", "", "") +DEF_ATTRIB(RESTRICT_PACKET_AXOK, "May exist with A-type or X-type", "", "") DEF_ATTRIB(ICOP, "Instruction cache op", "", "") DEF_ATTRIB(HWLOOP0_END, "Ends HW loop0", "", "") DEF_ATTRIB(HWLOOP1_END, "Ends HW loop1", "", "") +DEF_ATTRIB(RET_TYPE, "return type", "", "") DEF_ATTRIB(DCZEROA, "dczeroa type", "", "") DEF_ATTRIB(ICFLUSHOP, "icflush op type", "", "") DEF_ATTRIB(DCFLUSHOP, "dcflush op type", "", "") @@ -116,5 +139,18 @@ DEF_ATTRIB(L2FETCH, "Instruction is l2fetch type", "", "") DEF_ATTRIB(ICINVA, "icinva", "", "") DEF_ATTRIB(DCCLEANINVA, "dccleaninva", "", "") +/* Documentation Notes */ +DEF_ATTRIB(NOTE_CONDITIONAL, "can be conditionally executed", "", "") +DEF_ATTRIB(NOTE_NEWVAL_SLOT0, "New-value oprnd must execute on slot 0", "", "") +DEF_ATTRIB(NOTE_PRIV, "Monitor-level feature", "", "") +DEF_ATTRIB(NOTE_NOPACKET, "solo instruction", "", "") +DEF_ATTRIB(NOTE_AXOK, "May only be grouped with ALU32 or non-FP XTYPE.", "", "") +DEF_ATTRIB(NOTE_LATEPRED, "The predicate can not be used as a .new", "", "") +DEF_ATTRIB(NOTE_NVSLOT0, "Can execute only in slot 0 (ST)", "", "") + +/* Restrictions to make note of */ +DEF_ATTRIB(RESTRICT_NOSLOT1_STORE, "Packet must not have slot 1 store", "", "") +DEF_ATTRIB(RESTRICT_LATEPRED, "Predicate can not be used as a .new.", "", "") + /* Keep this as the last attribute: */ DEF_ATTRIB(ZZ_LASTATTRIB, "Last attribute in the file", "", "") diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index fa9bd702d6..fa6d722555 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -251,12 +251,19 @@ static void hexagon_cpu_set_pc(CPUState *cs, vaddr value) env->gpr[HEX_REG_PC] = value; } +static vaddr hexagon_cpu_get_pc(CPUState *cs) +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + return env->gpr[HEX_REG_PC]; +} + static void hexagon_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { HexagonCPU *cpu = HEXAGON_CPU(cs); CPUHexagonState *env = &cpu->env; - env->gpr[HEX_REG_PC] = tb->pc; + env->gpr[HEX_REG_PC] = tb_pc(tb); } static bool hexagon_cpu_has_work(CPUState *cs) @@ -337,6 +344,7 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data) cc->has_work = hexagon_cpu_has_work; cc->dump_state = hexagon_dump_state; cc->set_pc = hexagon_cpu_set_pc; + cc->get_pc = hexagon_cpu_get_pc; cc->gdb_read_register = hexagon_gdb_read_register; cc->gdb_write_register = hexagon_gdb_write_register; cc->gdb_num_core_regs = TOTAL_PER_THREAD_REGS + NUM_VREGS + NUM_QREGS; diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 6f0f27b4ba..6b73b5c60c 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved. * * 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 @@ -402,10 +402,13 @@ static void decode_set_insn_attr_fields(Packet *pkt) } if (GET_ATTRIB(opcode, A_STORE)) { - if (pkt->insn[i].slot == 0) { - pkt->pkt_has_store_s0 = true; - } else { - pkt->pkt_has_store_s1 = true; + if (GET_ATTRIB(opcode, A_SCALAR_STORE) && + !GET_ATTRIB(opcode, A_MEMSIZE_0B)) { + if (pkt->insn[i].slot == 0) { + pkt->pkt_has_store_s0 = true; + } else { + pkt->pkt_has_store_s1 = true; + } } } diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py index 1fd9de95d5..6dea02b0b9 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 ## -## Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. +## Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved. ## ## 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 @@ -164,7 +164,9 @@ def genptr_decl(f, tag, regtype, regid, regno): (regtype, regid, regno)) f.write(" const intptr_t %s%sV_off =\n" % \ (regtype, regid)) - if (hex_common.is_tmp_result(tag)): + if (regid == "y"): + f.write(" offsetof(CPUHexagonState, vtmp);\n") + elif (hex_common.is_tmp_result(tag)): f.write(" ctx_tmp_vreg_off(ctx, %s%sN, 1, true);\n" % \ (regtype, regid)) else: @@ -379,9 +381,6 @@ def genptr_src_read(f, tag, regtype, regid): f.write(" vreg_src_off(ctx, %s%sN),\n" % \ (regtype, regid)) f.write(" sizeof(MMVector), sizeof(MMVector));\n") - if (not hex_common.skip_qemu_helper(tag)): - f.write(" tcg_gen_addi_ptr(%s%sV, cpu_env, %s%sV_off);\n" % \ - (regtype, regid, regtype, regid)) else: print("Bad register parse: ", regtype, regid) elif (regtype == "Q"): @@ -549,7 +548,7 @@ def genptr_dst_write_opn(f,regtype, regid, tag): if (hex_common.is_hvx_reg(regtype)): if (hex_common.is_new_result(tag)): genptr_dst_write_ext(f, tag, regtype, regid, "EXT_NEW") - if (hex_common.is_tmp_result(tag)): + elif (hex_common.is_tmp_result(tag)): genptr_dst_write_ext(f, tag, regtype, regid, "EXT_TMP") else: genptr_dst_write_ext(f, tag, regtype, regid, "EXT_DFL") diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 8a334ba07b..806d0974ff 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -401,62 +401,50 @@ static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot) tcg_gen_mov_tl(hex_store_val32[slot], src); } -static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, - DisasContext *ctx, int slot) +static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, int slot) { gen_store32(vaddr, src, 1, slot); - ctx->store_width[slot] = 1; } -static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, - DisasContext *ctx, int slot) +static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, int slot) { TCGv tmp = tcg_constant_tl(src); - gen_store1(cpu_env, vaddr, tmp, ctx, slot); + gen_store1(cpu_env, vaddr, tmp, slot); } -static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, - DisasContext *ctx, int slot) +static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, int slot) { gen_store32(vaddr, src, 2, slot); - ctx->store_width[slot] = 2; } -static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, - DisasContext *ctx, int slot) +static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, int slot) { TCGv tmp = tcg_constant_tl(src); - gen_store2(cpu_env, vaddr, tmp, ctx, slot); + gen_store2(cpu_env, vaddr, tmp, slot); } -static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, - DisasContext *ctx, int slot) +static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, int slot) { gen_store32(vaddr, src, 4, slot); - ctx->store_width[slot] = 4; } -static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, - DisasContext *ctx, int slot) +static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, int slot) { TCGv tmp = tcg_constant_tl(src); - gen_store4(cpu_env, vaddr, tmp, ctx, slot); + gen_store4(cpu_env, vaddr, tmp, slot); } -static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, - DisasContext *ctx, int slot) +static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, int slot) { tcg_gen_mov_tl(hex_store_addr[slot], vaddr); tcg_gen_movi_tl(hex_store_width[slot], 8); tcg_gen_mov_i64(hex_store_val64[slot], src); - ctx->store_width[slot] = 8; } -static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, - DisasContext *ctx, int slot) +static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, int slot) { TCGv_i64 tmp = tcg_constant_i64(src); - gen_store8(cpu_env, vaddr, tmp, ctx, slot); + gen_store8(cpu_env, vaddr, tmp, slot); } static TCGv gen_8bitsof(TCGv result, TCGv value) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index c81aca8d2a..d9ba7df786 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 ## -## Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. +## Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved. ## ## 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 @@ -75,6 +75,7 @@ def calculate_attribs(): add_qemu_macro_attrib('fWRITE_P3', 'A_WRITES_PRED_REG') add_qemu_macro_attrib('fSET_OVERFLOW', 'A_IMPLICIT_WRITES_USR') add_qemu_macro_attrib('fSET_LPCFG', 'A_IMPLICIT_WRITES_USR') + add_qemu_macro_attrib('fSTORE', 'A_SCALAR_STORE') # Recurse down macros, find attributes from sub-macros macroValues = list(macros.values()) diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 939c6fc55f..d71c04cd30 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -944,13 +944,6 @@ MPY_ENC(F2_dfmpyfix, "1000","ddddd","0","0","1","0","11") MPY_ENC(F2_dfmin, "1000","ddddd","0","0","1","1","11") MPY_ENC(F2_dfmax, "1000","ddddd","0","1","0","0","11") MPY_ENC(F2_dfmpyll, "1000","ddddd","0","1","0","1","11") -#ifdef ADD_DP_OPS -MPY_ENC(F2_dfdivcheat, "1000","ddddd","0","0","0","1","00") - -MPY_ENC(F2_dffixupn, "1000","ddddd","0","1","0","1","11") -MPY_ENC(F2_dffixupd, "1000","ddddd","0","1","1","0","11") -MPY_ENC(F2_dfrecipa, "1000","ddddd","0","1","1","1","ee") -#endif MPY_ENC(M7_dcmpyrw, "1000","ddddd","0","0","0","1","10") MPY_ENC(M7_dcmpyrwc, "1000","ddddd","0","0","1","1","10") @@ -1024,15 +1017,6 @@ MPY_ENC(M5_vdmacbsu, "1010","xxxxx","0","1","0","0","01") MPY_ENC(F2_dfmpylh, "1010","xxxxx","0","0","0","0","11") MPY_ENC(F2_dfmpyhh, "1010","xxxxx","0","0","0","1","11") -#ifdef ADD_DP_OPS -MPY_ENC(F2_dfmpyhh, "1010","xxxxx","0","0","1","0","11") -MPY_ENC(F2_dffma, "1010","xxxxx","0","0","0","0","11") -MPY_ENC(F2_dffms, "1010","xxxxx","0","0","0","1","11") - -MPY_ENC(F2_dffma_lib, "1010","xxxxx","0","0","1","0","11") -MPY_ENC(F2_dffms_lib, "1010","xxxxx","0","0","1","1","11") -MPY_ENC(F2_dffma_sc, "1010","xxxxx","0","1","1","1","uu") -#endif MPY_ENC(M7_dcmpyrw_acc, "1010","xxxxx","0","0","0","1","10") @@ -1547,15 +1531,8 @@ SH2_RR_ENC(F2_conv_df2d, "0000","111","0","0 00","ddddd") SH2_RR_ENC(F2_conv_df2ud, "0000","111","0","0 01","ddddd") SH2_RR_ENC(F2_conv_ud2df, "0000","111","0","0 10","ddddd") SH2_RR_ENC(F2_conv_d2df, "0000","111","0","0 11","ddddd") -#ifdef ADD_DP_OPS -SH2_RR_ENC(F2_dffixupr, "0000","111","0","1 00","ddddd") -SH2_RR_ENC(F2_dfsqrtcheat, "0000","111","0","1 01","ddddd") -#endif SH2_RR_ENC(F2_conv_df2d_chop, "0000","111","0","1 10","ddddd") SH2_RR_ENC(F2_conv_df2ud_chop,"0000","111","0","1 11","ddddd") -#ifdef ADD_DP_OPS -SH2_RR_ENC(F2_dfinvsqrta, "0000","111","1","0 ee","ddddd") -#endif diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef index 359d3b744e..237634bdd9 100644 --- a/target/hexagon/imported/ldst.idef +++ b/target/hexagon/imported/ldst.idef @@ -1,5 +1,5 @@ /* - * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved. * * 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 @@ -31,12 +31,12 @@ Q6INSN(L2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))",ATTRIB,DESCR,{fEA_REG( Q6INSN(L2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))", ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<opcode; + uint32_t slot = insn->slot; + uint8_t width = 0; + + if (GET_ATTRIB(opcode, A_SCALAR_STORE)) { + if (GET_ATTRIB(opcode, A_MEMSIZE_1B)) { + width |= 1; + } + if (GET_ATTRIB(opcode, A_MEMSIZE_2B)) { + width |= 2; + } + if (GET_ATTRIB(opcode, A_MEMSIZE_4B)) { + width |= 4; + } + if (GET_ATTRIB(opcode, A_MEMSIZE_8B)) { + width |= 8; + } + tcg_debug_assert(is_power_of_2(width)); + ctx->store_width[slot] = width; + } +} + static void gen_insn(CPUHexagonState *env, DisasContext *ctx, Insn *insn, Packet *pkt) { @@ -334,6 +358,7 @@ static void gen_insn(CPUHexagonState *env, DisasContext *ctx, mark_implicit_reg_writes(ctx, insn); insn->generate(env, ctx, insn, pkt); mark_implicit_pred_writes(ctx, insn); + mark_store_width(ctx, insn); } else { gen_exception_end_tb(ctx, HEX_EXCP_INVALID_OPCODE); } @@ -499,10 +524,12 @@ static void process_store_log(DisasContext *ctx, Packet *pkt) * slot 1 and then slot 0. This will be important when * the memory accesses overlap. */ - if (pkt->pkt_has_store_s1 && !pkt->pkt_has_dczeroa) { + if (pkt->pkt_has_store_s1) { + g_assert(!pkt->pkt_has_dczeroa); process_store(ctx, pkt, 1); } - if (pkt->pkt_has_store_s0 && !pkt->pkt_has_dczeroa) { + if (pkt->pkt_has_store_s0) { + g_assert(!pkt->pkt_has_dczeroa); process_store(ctx, pkt, 0); } } @@ -665,7 +692,7 @@ static void gen_commit_packet(CPUHexagonState *env, DisasContext *ctx, * The dczeroa will be the store in slot 0, check that we don't have * a store in slot 1 or an HVX store. */ - g_assert(has_store_s0 && !has_store_s1 && !has_hvx_store); + g_assert(!has_store_s1 && !has_hvx_store); process_dczeroa(ctx, pkt); } else if (has_hvx_store) { TCGv mem_idx = tcg_constant_tl(ctx->mem_idx); @@ -850,11 +877,13 @@ static const TranslatorOps hexagon_tr_ops = { .disas_log = hexagon_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&hexagon_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, + &hexagon_tr_ops, &ctx.base); } #define NAME_LEN 64 diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index a6f52caf14..e677ca09d4 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -36,13 +36,20 @@ static void hppa_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.iaoq_b = value + 4; } +static vaddr hppa_cpu_get_pc(CPUState *cs) +{ + HPPACPU *cpu = HPPA_CPU(cs); + + return cpu->env.iaoq_f; +} + static void hppa_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { HPPACPU *cpu = HPPA_CPU(cs); #ifdef CONFIG_USER_ONLY - cpu->env.iaoq_f = tb->pc; + cpu->env.iaoq_f = tb_pc(tb); cpu->env.iaoq_b = tb->cs_base; #else /* Recover the IAOQ values from the GVA + PRIV. */ @@ -52,7 +59,7 @@ static void hppa_cpu_synchronize_from_tb(CPUState *cs, int32_t diff = cs_base; cpu->env.iasq_f = iasq_f; - cpu->env.iaoq_f = (tb->pc & ~iasq_f) + priv; + cpu->env.iaoq_f = (tb_pc(tb) & ~iasq_f) + priv; if (diff) { cpu->env.iaoq_b = cpu->env.iaoq_f + diff; } @@ -168,6 +175,7 @@ static void hppa_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = hppa_cpu_has_work; cc->dump_state = hppa_cpu_dump_state; cc->set_pc = hppa_cpu_set_pc; + cc->get_pc = hppa_cpu_get_pc; cc->gdb_read_register = hppa_cpu_gdb_read_register; cc->gdb_write_register = hppa_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/hppa/helper.c b/target/hppa/helper.c index e2758d8df3..74b8747083 100644 --- a/target/hppa/helper.c +++ b/target/hppa/helper.c @@ -85,9 +85,11 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags) char psw_c[20]; int i; - qemu_fprintf(f, "IA_F " TARGET_FMT_lx " IA_B " TARGET_FMT_lx "\n", + qemu_fprintf(f, "IA_F " TARGET_FMT_lx " IA_B " TARGET_FMT_lx + " IIR " TREG_FMT_lx "\n", hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f), - hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b)); + hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b), + env->cr[CR_IIR]); psw_c[0] = (psw & PSW_W ? 'W' : '-'); psw_c[1] = (psw & PSW_E ? 'E' : '-'); diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index cd304f051e..fbd80e4248 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -170,7 +170,7 @@ target_ureg HELPER(probe)(CPUHPPAState *env, target_ulong addr, uint32_t level, uint32_t want) { #ifdef CONFIG_USER_ONLY - return page_check_range(addr, 1, want); + return (page_check_range(addr, 1, want) == 0) ? 1 : 0; #else int prot, excp; hwaddr phys; diff --git a/target/hppa/translate.c b/target/hppa/translate.c index b8dbfee5e9..8b861957e0 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -4340,10 +4340,11 @@ static const TranslatorOps hppa_tr_ops = { .disas_log = hppa_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&hppa_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); } void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb, diff --git a/target/i386/arch_dump.c b/target/i386/arch_dump.c index 004141fc04..c290910a04 100644 --- a/target/i386/arch_dump.c +++ b/target/i386/arch_dump.c @@ -42,7 +42,7 @@ typedef struct { static int x86_64_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, int id, - void *opaque) + DumpState *s) { x86_64_user_regs_struct regs; Elf64_Nhdr *note; @@ -94,7 +94,7 @@ static int x86_64_write_elf64_note(WriteCoreDumpFunction f, buf += descsz - sizeof(x86_64_user_regs_struct)-sizeof(target_ulong); memcpy(buf, ®s, sizeof(x86_64_user_regs_struct)); - ret = f(note, note_size, opaque); + ret = f(note, note_size, s); g_free(note); if (ret < 0) { return -1; @@ -148,7 +148,7 @@ static void x86_fill_elf_prstatus(x86_elf_prstatus *prstatus, CPUX86State *env, } static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, - int id, void *opaque) + int id, DumpState *s) { x86_elf_prstatus prstatus; Elf64_Nhdr *note; @@ -170,7 +170,7 @@ static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, buf += ROUND_UP(name_size, 4); memcpy(buf, &prstatus, sizeof(prstatus)); - ret = f(note, note_size, opaque); + ret = f(note, note_size, s); g_free(note); if (ret < 0) { return -1; @@ -180,7 +180,7 @@ static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, } int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { X86CPU *cpu = X86_CPU(cs); int ret; @@ -189,10 +189,10 @@ int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, bool lma = !!(first_x86_cpu->env.hflags & HF_LMA_MASK); if (lma) { - ret = x86_64_write_elf64_note(f, &cpu->env, cpuid, opaque); + ret = x86_64_write_elf64_note(f, &cpu->env, cpuid, s); } else { #endif - ret = x86_write_elf64_note(f, &cpu->env, cpuid, opaque); + ret = x86_write_elf64_note(f, &cpu->env, cpuid, s); #ifdef TARGET_X86_64 } #endif @@ -201,7 +201,7 @@ int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, } int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { X86CPU *cpu = X86_CPU(cs); x86_elf_prstatus prstatus; @@ -224,7 +224,7 @@ int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, buf += ROUND_UP(name_size, 4); memcpy(buf, &prstatus, sizeof(prstatus)); - ret = f(note, note_size, opaque); + ret = f(note, note_size, s); g_free(note); if (ret < 0) { return -1; @@ -329,7 +329,7 @@ static void qemu_get_cpustate(QEMUCPUState *s, CPUX86State *env) static inline int cpu_write_qemu_note(WriteCoreDumpFunction f, CPUX86State *env, - void *opaque, + DumpState *s, int type) { QEMUCPUState state; @@ -369,7 +369,7 @@ static inline int cpu_write_qemu_note(WriteCoreDumpFunction f, buf += ROUND_UP(name_size, 4); memcpy(buf, &state, sizeof(state)); - ret = f(note, note_size, opaque); + ret = f(note, note_size, s); g_free(note); if (ret < 0) { return -1; @@ -379,19 +379,19 @@ static inline int cpu_write_qemu_note(WriteCoreDumpFunction f, } int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cs, - void *opaque) + DumpState *s) { X86CPU *cpu = X86_CPU(cs); - return cpu_write_qemu_note(f, &cpu->env, opaque, 1); + return cpu_write_qemu_note(f, &cpu->env, s, 1); } int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cs, - void *opaque) + DumpState *s) { X86CPU *cpu = X86_CPU(cs); - return cpu_write_qemu_note(f, &cpu->env, opaque, 0); + return cpu_write_qemu_note(f, &cpu->env, s, 0); } int cpu_get_dump_info(ArchDumpInfo *info, diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6a57ef13af..ad623d91e4 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3632,7 +3632,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { CPUID_7_0_EDX_CORE_CAPABILITY, .features[FEAT_CORE_CAPABILITY] = MSR_CORE_CAP_SPLIT_LOCK_DETECT, - /* XSAVES is is added in version 3 */ + /* XSAVES is added in version 3 */ .features[FEAT_XSAVE] = CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | CPUID_XSAVE_XGETBV1, @@ -4837,6 +4837,11 @@ static void x86_cpu_list_entry(gpointer data, gpointer user_data) desc = g_strdup_printf("%s", model_id); } + if (cc->model && cc->model->cpudef->deprecation_note) { + g_autofree char *olddesc = desc; + desc = g_strdup_printf("%s (deprecated)", olddesc); + } + qemu_printf("x86 %-20s %s\n", name, desc); } @@ -6819,6 +6824,14 @@ static void x86_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.eip = value; } +static vaddr x86_cpu_get_pc(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + + /* Match cpu_get_tb_cpu_state. */ + return cpu->env.eip + cpu->env.segs[R_CS].base; +} + int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request) { X86CPU *cpu = X86_CPU(cs); @@ -7101,6 +7114,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->has_work = x86_cpu_has_work; cc->dump_state = x86_cpu_dump_state; cc->set_pc = x86_cpu_set_pc; + cc->get_pc = x86_cpu_get_pc; cc->gdb_read_register = x86_cpu_gdb_read_register; cc->gdb_write_register = x86_cpu_gdb_write_register; cc->get_arch_id = x86_cpu_get_arch_id; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 82004b65b9..b75108d6a3 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1938,13 +1938,13 @@ extern const VMStateDescription vmstate_x86_cpu; int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request); int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque); + int cpuid, DumpState *s); int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, - int cpuid, void *opaque); + int cpuid, DumpState *s); int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque); + DumpState *s); int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, - void *opaque); + DumpState *s); void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, Error **errp); diff --git a/target/i386/helper.c b/target/i386/helper.c index fa409e9c44..b954ccda50 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -415,7 +415,7 @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data) if (need_reset) { emit_guest_memory_failure(MEMORY_FAILURE_ACTION_RESET, ar, recursive); - monitor_printf(params->mon, "%s", msg); + monitor_puts(params->mon, msg); qemu_log_mask(CPU_LOG_RESET, "%s\n", msg); qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); return; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index f148a6d52f..f2a96492ce 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -157,7 +157,7 @@ bool kvm_has_adjust_clock_stable(void) { int ret = kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK); - return (ret == KVM_CLOCK_TSC_STABLE); + return (ret & KVM_CLOCK_TSC_STABLE); } bool kvm_has_adjust_clock(void) @@ -1695,6 +1695,30 @@ static void kvm_init_xsave(CPUX86State *env) env->xsave_buf_len); } +static void kvm_init_nested_state(CPUX86State *env) +{ + struct kvm_vmx_nested_state_hdr *vmx_hdr; + uint32_t size; + + if (!env->nested_state) { + return; + } + + size = env->nested_state->size; + + memset(env->nested_state, 0, size); + env->nested_state->size = size; + + if (cpu_has_vmx(env)) { + env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX; + vmx_hdr = &env->nested_state->hdr.vmx; + vmx_hdr->vmxon_pa = -1ull; + vmx_hdr->vmcs12_pa = -1ull; + } else if (cpu_has_svm(env)) { + env->nested_state->format = KVM_STATE_NESTED_FORMAT_SVM; + } +} + int kvm_arch_init_vcpu(CPUState *cs) { struct { @@ -2122,19 +2146,10 @@ int kvm_arch_init_vcpu(CPUState *cs) assert(max_nested_state_len >= offsetof(struct kvm_nested_state, data)); if (cpu_has_vmx(env) || cpu_has_svm(env)) { - struct kvm_vmx_nested_state_hdr *vmx_hdr; - env->nested_state = g_malloc0(max_nested_state_len); env->nested_state->size = max_nested_state_len; - if (cpu_has_vmx(env)) { - env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX; - vmx_hdr = &env->nested_state->hdr.vmx; - vmx_hdr->vmxon_pa = -1ull; - vmx_hdr->vmcs12_pa = -1ull; - } else { - env->nested_state->format = KVM_STATE_NESTED_FORMAT_SVM; - } + kvm_init_nested_state(env); } } @@ -2161,15 +2176,11 @@ int kvm_arch_destroy_vcpu(CPUState *cs) g_free(env->xsave_buf); - if (cpu->kvm_msr_buf) { - g_free(cpu->kvm_msr_buf); - cpu->kvm_msr_buf = NULL; - } + g_free(cpu->kvm_msr_buf); + cpu->kvm_msr_buf = NULL; - if (env->nested_state) { - g_free(env->nested_state); - env->nested_state = NULL; - } + g_free(env->nested_state); + env->nested_state = NULL; qemu_del_vm_change_state_handler(cpu->vmsentry); @@ -2199,6 +2210,8 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) /* enabled by default */ env->poll_control_msr = 1; + kvm_init_nested_state(env); + sev_es_set_reset_vector(CPU(cpu)); } @@ -4512,6 +4525,18 @@ int kvm_arch_put_registers(CPUState *cpu, int level) assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); + /* + * Put MSR_IA32_FEATURE_CONTROL first, this ensures the VM gets out of VMX + * root operation upon vCPU reset. kvm_put_msr_feature_control() should also + * preceed kvm_put_nested_state() when 'real' nested state is set. + */ + if (level >= KVM_PUT_RESET_STATE) { + ret = kvm_put_msr_feature_control(x86_cpu); + if (ret < 0) { + return ret; + } + } + /* must be before kvm_put_nested_state so that EFER.SVME is set */ ret = has_sregs2 ? kvm_put_sregs2(x86_cpu) : kvm_put_sregs(x86_cpu); if (ret < 0) { @@ -4523,11 +4548,6 @@ int kvm_arch_put_registers(CPUState *cpu, int level) if (ret < 0) { return ret; } - - ret = kvm_put_msr_feature_control(x86_cpu); - if (ret < 0) { - return ret; - } } if (level == KVM_PUT_FULL_STATE) { diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index 535440f882..7bf8bb967d 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -22,7 +22,6 @@ #if SHIFT == 0 #define Reg MMXReg -#define SIZE 8 #define XMM_ONLY(...) #define B(n) MMX_B(n) #define W(n) MMX_W(n) @@ -31,7 +30,6 @@ #define SUFFIX _mmx #else #define Reg ZMMReg -#define SIZE 16 #define XMM_ONLY(...) __VA_ARGS__ #define B(n) ZMM_B(n) #define W(n) ZMM_W(n) @@ -40,275 +38,210 @@ #define SUFFIX _xmm #endif -/* - * Copy the relevant parts of a Reg value around. In the case where - * sizeof(Reg) > SIZE, these helpers operate only on the lower bytes of - * a 64 byte ZMMReg, so we must copy only those and keep the top bytes - * untouched in the guest-visible destination destination register. - * Note that the "lower bytes" are placed last in memory on big-endian - * hosts, which store the vector backwards in memory. In that case the - * copy *starts* at B(SIZE - 1) and ends at B(0), the opposite of - * the little-endian case. - */ -#if HOST_BIG_ENDIAN -#define MOVE(d, r) memcpy(&((d).B(SIZE - 1)), &(r).B(SIZE - 1), SIZE) -#else -#define MOVE(d, r) memcpy(&(d).B(0), &(r).B(0), SIZE) +#define LANE_WIDTH (SHIFT ? 16 : 8) +#define PACK_WIDTH (LANE_WIDTH / 2) + +#if SHIFT == 0 +#define FPSRL(x, c) ((x) >> shift) +#define FPSRAW(x, c) ((int16_t)(x) >> shift) +#define FPSRAL(x, c) ((int32_t)(x) >> shift) +#define FPSLL(x, c) ((x) << shift) #endif -void glue(helper_psrlw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psrlw, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { + Reg *s = d; int shift; - - if (s->Q(0) > 15) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + if (c->Q(0) > 15) { + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } else { - shift = s->B(0); - d->W(0) >>= shift; - d->W(1) >>= shift; - d->W(2) >>= shift; - d->W(3) >>= shift; -#if SHIFT == 1 - d->W(4) >>= shift; - d->W(5) >>= shift; - d->W(6) >>= shift; - d->W(7) >>= shift; -#endif + shift = c->B(0); + for (int i = 0; i < 4 << SHIFT; i++) { + d->W(i) = FPSRL(s->W(i), shift); + } } } -void glue(helper_psraw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psllw, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { + Reg *s = d; int shift; + if (c->Q(0) > 15) { + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } + } else { + shift = c->B(0); + for (int i = 0; i < 4 << SHIFT; i++) { + d->W(i) = FPSLL(s->W(i), shift); + } + } +} - if (s->Q(0) > 15) { +void glue(helper_psraw, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) +{ + Reg *s = d; + int shift; + if (c->Q(0) > 15) { shift = 15; } else { - shift = s->B(0); + shift = c->B(0); + } + for (int i = 0; i < 4 << SHIFT; i++) { + d->W(i) = FPSRAW(s->W(i), shift); } - d->W(0) = (int16_t)d->W(0) >> shift; - d->W(1) = (int16_t)d->W(1) >> shift; - d->W(2) = (int16_t)d->W(2) >> shift; - d->W(3) = (int16_t)d->W(3) >> shift; -#if SHIFT == 1 - d->W(4) = (int16_t)d->W(4) >> shift; - d->W(5) = (int16_t)d->W(5) >> shift; - d->W(6) = (int16_t)d->W(6) >> shift; - d->W(7) = (int16_t)d->W(7) >> shift; -#endif } -void glue(helper_psllw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psrld, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { + Reg *s = d; int shift; - - if (s->Q(0) > 15) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + if (c->Q(0) > 31) { + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } else { - shift = s->B(0); - d->W(0) <<= shift; - d->W(1) <<= shift; - d->W(2) <<= shift; - d->W(3) <<= shift; -#if SHIFT == 1 - d->W(4) <<= shift; - d->W(5) <<= shift; - d->W(6) <<= shift; - d->W(7) <<= shift; -#endif + shift = c->B(0); + for (int i = 0; i < 2 << SHIFT; i++) { + d->L(i) = FPSRL(s->L(i), shift); + } } } -void glue(helper_psrld, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_pslld, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { + Reg *s = d; int shift; - - if (s->Q(0) > 31) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + if (c->Q(0) > 31) { + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } else { - shift = s->B(0); - d->L(0) >>= shift; - d->L(1) >>= shift; -#if SHIFT == 1 - d->L(2) >>= shift; - d->L(3) >>= shift; -#endif + shift = c->B(0); + for (int i = 0; i < 2 << SHIFT; i++) { + d->L(i) = FPSLL(s->L(i), shift); + } } } -void glue(helper_psrad, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psrad, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { + Reg *s = d; int shift; - - if (s->Q(0) > 31) { + if (c->Q(0) > 31) { shift = 31; } else { - shift = s->B(0); + shift = c->B(0); + } + for (int i = 0; i < 2 << SHIFT; i++) { + d->L(i) = FPSRAL(s->L(i), shift); } - d->L(0) = (int32_t)d->L(0) >> shift; - d->L(1) = (int32_t)d->L(1) >> shift; -#if SHIFT == 1 - d->L(2) = (int32_t)d->L(2) >> shift; - d->L(3) = (int32_t)d->L(3) >> shift; -#endif } -void glue(helper_pslld, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psrlq, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { + Reg *s = d; int shift; - - if (s->Q(0) > 31) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + if (c->Q(0) > 63) { + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } else { - shift = s->B(0); - d->L(0) <<= shift; - d->L(1) <<= shift; -#if SHIFT == 1 - d->L(2) <<= shift; - d->L(3) <<= shift; -#endif + shift = c->B(0); + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = FPSRL(s->Q(i), shift); + } } } -void glue(helper_psrlq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_psllq, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { + Reg *s = d; int shift; - - if (s->Q(0) > 63) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + if (c->Q(0) > 63) { + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } else { - shift = s->B(0); - d->Q(0) >>= shift; -#if SHIFT == 1 - d->Q(1) >>= shift; -#endif + shift = c->B(0); + for (int i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = FPSLL(s->Q(i), shift); + } } } -void glue(helper_psllq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +#if SHIFT >= 1 +void glue(helper_psrldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { - int shift; + Reg *s = d; + int shift, i, j; - if (s->Q(0) > 63) { - d->Q(0) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif - } else { - shift = s->B(0); - d->Q(0) <<= shift; -#if SHIFT == 1 - d->Q(1) <<= shift; -#endif - } -} - -#if SHIFT == 1 -void glue(helper_psrldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - int shift, i; - - shift = s->L(0); + shift = c->L(0); if (shift > 16) { shift = 16; } - for (i = 0; i < 16 - shift; i++) { - d->B(i) = d->B(i + shift); - } - for (i = 16 - shift; i < 16; i++) { - d->B(i) = 0; + for (j = 0; j < 8 << SHIFT; j += LANE_WIDTH) { + for (i = 0; i < 16 - shift; i++) { + d->B(j + i) = s->B(j + i + shift); + } + for (i = 16 - shift; i < 16; i++) { + d->B(j + i) = 0; + } } } -void glue(helper_pslldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_pslldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *c) { - int shift, i; + Reg *s = d; + int shift, i, j; - shift = s->L(0); + shift = c->L(0); if (shift > 16) { shift = 16; } - for (i = 15; i >= shift; i--) { - d->B(i) = d->B(i - shift); - } - for (i = 0; i < shift; i++) { - d->B(i) = 0; + for (j = 0; j < 8 << SHIFT; j += LANE_WIDTH) { + for (i = 15; i >= shift; i--) { + d->B(j + i) = s->B(j + i - shift); + } + for (i = 0; i < shift; i++) { + d->B(j + i) = 0; + } } } #endif +#define SSE_HELPER_1(name, elem, num, F) \ + void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ + { \ + int n = num; \ + for (int i = 0; i < n; i++) { \ + d->elem(i) = F(s->elem(i)); \ + } \ + } + +#define SSE_HELPER_2(name, elem, num, F) \ + void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ + { \ + Reg *v = d; \ + int n = num; \ + for (int i = 0; i < n; i++) { \ + d->elem(i) = F(v->elem(i), s->elem(i)); \ + } \ + } + #define SSE_HELPER_B(name, F) \ - void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ - { \ - d->B(0) = F(d->B(0), s->B(0)); \ - d->B(1) = F(d->B(1), s->B(1)); \ - d->B(2) = F(d->B(2), s->B(2)); \ - d->B(3) = F(d->B(3), s->B(3)); \ - d->B(4) = F(d->B(4), s->B(4)); \ - d->B(5) = F(d->B(5), s->B(5)); \ - d->B(6) = F(d->B(6), s->B(6)); \ - d->B(7) = F(d->B(7), s->B(7)); \ - XMM_ONLY( \ - d->B(8) = F(d->B(8), s->B(8)); \ - d->B(9) = F(d->B(9), s->B(9)); \ - d->B(10) = F(d->B(10), s->B(10)); \ - d->B(11) = F(d->B(11), s->B(11)); \ - d->B(12) = F(d->B(12), s->B(12)); \ - d->B(13) = F(d->B(13), s->B(13)); \ - d->B(14) = F(d->B(14), s->B(14)); \ - d->B(15) = F(d->B(15), s->B(15)); \ - ) \ - } + SSE_HELPER_2(name, B, 8 << SHIFT, F) #define SSE_HELPER_W(name, F) \ - void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ - { \ - d->W(0) = F(d->W(0), s->W(0)); \ - d->W(1) = F(d->W(1), s->W(1)); \ - d->W(2) = F(d->W(2), s->W(2)); \ - d->W(3) = F(d->W(3), s->W(3)); \ - XMM_ONLY( \ - d->W(4) = F(d->W(4), s->W(4)); \ - d->W(5) = F(d->W(5), s->W(5)); \ - d->W(6) = F(d->W(6), s->W(6)); \ - d->W(7) = F(d->W(7), s->W(7)); \ - ) \ - } + SSE_HELPER_2(name, W, 4 << SHIFT, F) #define SSE_HELPER_L(name, F) \ - void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ - { \ - d->L(0) = F(d->L(0), s->L(0)); \ - d->L(1) = F(d->L(1), s->L(1)); \ - XMM_ONLY( \ - d->L(2) = F(d->L(2), s->L(2)); \ - d->L(3) = F(d->L(3), s->L(3)); \ - ) \ - } + SSE_HELPER_2(name, L, 2 << SHIFT, F) #define SSE_HELPER_Q(name, F) \ - void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ - { \ - d->Q(0) = F(d->Q(0), s->Q(0)); \ - XMM_ONLY( \ - d->Q(1) = F(d->Q(1), s->Q(1)); \ - ) \ - } + SSE_HELPER_2(name, Q, 1 << SHIFT, F) #if SHIFT == 0 static inline int satub(int x) @@ -440,19 +373,22 @@ SSE_HELPER_W(helper_pavgw, FAVG) void glue(helper_pmuludq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->Q(0) = (uint64_t)s->L(0) * (uint64_t)d->L(0); -#if SHIFT == 1 - d->Q(1) = (uint64_t)s->L(2) * (uint64_t)d->L(2); -#endif + Reg *v = d; + int i; + + for (i = 0; i < (1 << SHIFT); i++) { + d->Q(i) = (uint64_t)s->L(i * 2) * (uint64_t)v->L(i * 2); + } } void glue(helper_pmaddwd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { + Reg *v = d; int i; for (i = 0; i < (2 << SHIFT); i++) { - d->L(i) = (int16_t)s->W(2 * i) * (int16_t)d->W(2 * i) + - (int16_t)s->W(2 * i + 1) * (int16_t)d->W(2 * i + 1); + d->L(i) = (int16_t)s->W(2 * i) * (int16_t)v->W(2 * i) + + (int16_t)s->W(2 * i + 1) * (int16_t)v->W(2 * i + 1); } } @@ -466,34 +402,27 @@ static inline int abs1(int a) } } #endif + void glue(helper_psadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - unsigned int val; + Reg *v = d; + int i; - val = 0; - val += abs1(d->B(0) - s->B(0)); - val += abs1(d->B(1) - s->B(1)); - val += abs1(d->B(2) - s->B(2)); - val += abs1(d->B(3) - s->B(3)); - val += abs1(d->B(4) - s->B(4)); - val += abs1(d->B(5) - s->B(5)); - val += abs1(d->B(6) - s->B(6)); - val += abs1(d->B(7) - s->B(7)); - d->Q(0) = val; -#if SHIFT == 1 - val = 0; - val += abs1(d->B(8) - s->B(8)); - val += abs1(d->B(9) - s->B(9)); - val += abs1(d->B(10) - s->B(10)); - val += abs1(d->B(11) - s->B(11)); - val += abs1(d->B(12) - s->B(12)); - val += abs1(d->B(13) - s->B(13)); - val += abs1(d->B(14) - s->B(14)); - val += abs1(d->B(15) - s->B(15)); - d->Q(1) = val; -#endif + for (i = 0; i < (1 << SHIFT); i++) { + unsigned int val = 0; + val += abs1(v->B(8 * i + 0) - s->B(8 * i + 0)); + val += abs1(v->B(8 * i + 1) - s->B(8 * i + 1)); + val += abs1(v->B(8 * i + 2) - s->B(8 * i + 2)); + val += abs1(v->B(8 * i + 3) - s->B(8 * i + 3)); + val += abs1(v->B(8 * i + 4) - s->B(8 * i + 4)); + val += abs1(v->B(8 * i + 5) - s->B(8 * i + 5)); + val += abs1(v->B(8 * i + 6) - s->B(8 * i + 6)); + val += abs1(v->B(8 * i + 7) - s->B(8 * i + 7)); + d->Q(i) = val; + } } +#if SHIFT < 2 void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, target_ulong a0) { @@ -505,128 +434,161 @@ void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, } } } +#endif void glue(helper_movl_mm_T0, SUFFIX)(Reg *d, uint32_t val) { + int i; + d->L(0) = val; d->L(1) = 0; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + for (i = 1; i < (1 << SHIFT); i++) { + d->Q(i) = 0; + } } #ifdef TARGET_X86_64 void glue(helper_movq_mm_T0, SUFFIX)(Reg *d, uint64_t val) { + int i; + d->Q(0) = val; -#if SHIFT == 1 - d->Q(1) = 0; -#endif + for (i = 1; i < (1 << SHIFT); i++) { + d->Q(i) = 0; + } } #endif +#define SHUFFLE4(F, a, b, offset) do { \ + r0 = a->F((order & 3) + offset); \ + r1 = a->F(((order >> 2) & 3) + offset); \ + r2 = b->F(((order >> 4) & 3) + offset); \ + r3 = b->F(((order >> 6) & 3) + offset); \ + d->F(offset) = r0; \ + d->F(offset + 1) = r1; \ + d->F(offset + 2) = r2; \ + d->F(offset + 3) = r3; \ + } while (0) + #if SHIFT == 0 void glue(helper_pshufw, SUFFIX)(Reg *d, Reg *s, int order) { - Reg r; + uint16_t r0, r1, r2, r3; - r.W(0) = s->W(order & 3); - r.W(1) = s->W((order >> 2) & 3); - r.W(2) = s->W((order >> 4) & 3); - r.W(3) = s->W((order >> 6) & 3); - MOVE(*d, r); + SHUFFLE4(W, s, s, 0); } #else -void helper_shufps(Reg *d, Reg *s, int order) +void glue(helper_shufps, SUFFIX)(Reg *d, Reg *s, int order) { - Reg r; + Reg *v = d; + uint32_t r0, r1, r2, r3; + int i; - r.L(0) = d->L(order & 3); - r.L(1) = d->L((order >> 2) & 3); - r.L(2) = s->L((order >> 4) & 3); - r.L(3) = s->L((order >> 6) & 3); - MOVE(*d, r); + for (i = 0; i < 2 << SHIFT; i += 4) { + SHUFFLE4(L, v, s, i); + } } -void helper_shufpd(Reg *d, Reg *s, int order) +void glue(helper_shufpd, SUFFIX)(Reg *d, Reg *s, int order) { - Reg r; + Reg *v = d; + uint64_t r0, r1; + int i; - r.Q(0) = d->Q(order & 1); - r.Q(1) = s->Q((order >> 1) & 1); - MOVE(*d, r); + for (i = 0; i < 1 << SHIFT; i += 2) { + r0 = v->Q(((order & 1) & 1) + i); + r1 = s->Q(((order >> 1) & 1) + i); + d->Q(i) = r0; + d->Q(i + 1) = r1; + order >>= 2; + } } void glue(helper_pshufd, SUFFIX)(Reg *d, Reg *s, int order) { - Reg r; + uint32_t r0, r1, r2, r3; + int i; - r.L(0) = s->L(order & 3); - r.L(1) = s->L((order >> 2) & 3); - r.L(2) = s->L((order >> 4) & 3); - r.L(3) = s->L((order >> 6) & 3); - MOVE(*d, r); + for (i = 0; i < 2 << SHIFT; i += 4) { + SHUFFLE4(L, s, s, i); + } } void glue(helper_pshuflw, SUFFIX)(Reg *d, Reg *s, int order) { - Reg r; + uint16_t r0, r1, r2, r3; + int i, j; - r.W(0) = s->W(order & 3); - r.W(1) = s->W((order >> 2) & 3); - r.W(2) = s->W((order >> 4) & 3); - r.W(3) = s->W((order >> 6) & 3); - r.Q(1) = s->Q(1); - MOVE(*d, r); + for (i = 0, j = 1; j < 1 << SHIFT; i += 8, j += 2) { + SHUFFLE4(W, s, s, i); + d->Q(j) = s->Q(j); + } } void glue(helper_pshufhw, SUFFIX)(Reg *d, Reg *s, int order) { - Reg r; + uint16_t r0, r1, r2, r3; + int i, j; - r.Q(0) = s->Q(0); - r.W(4) = s->W(4 + (order & 3)); - r.W(5) = s->W(4 + ((order >> 2) & 3)); - r.W(6) = s->W(4 + ((order >> 4) & 3)); - r.W(7) = s->W(4 + ((order >> 6) & 3)); - MOVE(*d, r); + for (i = 4, j = 0; j < 1 << SHIFT; i += 8, j += 2) { + d->Q(j) = s->Q(j); + SHUFFLE4(W, s, s, i); + } } #endif -#if SHIFT == 1 +#if SHIFT >= 1 /* FPU ops */ /* XXX: not accurate */ -#define SSE_HELPER_S(name, F) \ - void helper_ ## name ## ps(CPUX86State *env, Reg *d, Reg *s) \ +#define SSE_HELPER_P(name, F) \ + void glue(helper_ ## name ## ps, SUFFIX)(CPUX86State *env, \ + Reg *d, Reg *s) \ { \ - d->ZMM_S(0) = F(32, d->ZMM_S(0), s->ZMM_S(0)); \ - d->ZMM_S(1) = F(32, d->ZMM_S(1), s->ZMM_S(1)); \ - d->ZMM_S(2) = F(32, d->ZMM_S(2), s->ZMM_S(2)); \ - d->ZMM_S(3) = F(32, d->ZMM_S(3), s->ZMM_S(3)); \ + Reg *v = d; \ + int i; \ + for (i = 0; i < 2 << SHIFT; i++) { \ + d->ZMM_S(i) = F(32, v->ZMM_S(i), s->ZMM_S(i)); \ + } \ } \ \ - void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s) \ + void glue(helper_ ## name ## pd, SUFFIX)(CPUX86State *env, \ + Reg *d, Reg *s) \ { \ - d->ZMM_S(0) = F(32, d->ZMM_S(0), s->ZMM_S(0)); \ - } \ - \ - void helper_ ## name ## pd(CPUX86State *env, Reg *d, Reg *s) \ - { \ - d->ZMM_D(0) = F(64, d->ZMM_D(0), s->ZMM_D(0)); \ - d->ZMM_D(1) = F(64, d->ZMM_D(1), s->ZMM_D(1)); \ - } \ - \ - void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s) \ - { \ - d->ZMM_D(0) = F(64, d->ZMM_D(0), s->ZMM_D(0)); \ + Reg *v = d; \ + int i; \ + for (i = 0; i < 1 << SHIFT; i++) { \ + d->ZMM_D(i) = F(64, v->ZMM_D(i), s->ZMM_D(i)); \ + } \ } +#if SHIFT == 1 + +#define SSE_HELPER_S(name, F) \ + SSE_HELPER_P(name, F) \ + \ + void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s)\ + { \ + Reg *v = d; \ + d->ZMM_S(0) = F(32, v->ZMM_S(0), s->ZMM_S(0)); \ + } \ + \ + void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s)\ + { \ + Reg *v = d; \ + d->ZMM_D(0) = F(64, v->ZMM_D(0), s->ZMM_D(0)); \ + } + +#else + +#define SSE_HELPER_S(name, F) SSE_HELPER_P(name, F) + +#endif + #define FPU_ADD(size, a, b) float ## size ## _add(a, b, &env->sse_status) #define FPU_SUB(size, a, b) float ## size ## _sub(a, b, &env->sse_status) #define FPU_MUL(size, a, b) float ## size ## _mul(a, b, &env->sse_status) #define FPU_DIV(size, a, b) float ## size ## _div(a, b, &env->sse_status) -#define FPU_SQRT(size, a, b) float ## size ## _sqrt(b, &env->sse_status) /* Note that the choice of comparison op here is important to get the * special cases right: for min and max Intel specifies that (-0,0), @@ -643,27 +605,56 @@ SSE_HELPER_S(mul, FPU_MUL) SSE_HELPER_S(div, FPU_DIV) SSE_HELPER_S(min, FPU_MIN) SSE_HELPER_S(max, FPU_MAX) -SSE_HELPER_S(sqrt, FPU_SQRT) +void glue(helper_sqrtps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +{ + int i; + for (i = 0; i < 2 << SHIFT; i++) { + d->ZMM_S(i) = float32_sqrt(s->ZMM_S(i), &env->sse_status); + } +} + +void glue(helper_sqrtpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +{ + int i; + for (i = 0; i < 1 << SHIFT; i++) { + d->ZMM_D(i) = float64_sqrt(s->ZMM_D(i), &env->sse_status); + } +} + +#if SHIFT == 1 +void helper_sqrtss(CPUX86State *env, Reg *d, Reg *s) +{ + d->ZMM_S(0) = float32_sqrt(s->ZMM_S(0), &env->sse_status); +} + +void helper_sqrtsd(CPUX86State *env, Reg *d, Reg *s) +{ + d->ZMM_D(0) = float64_sqrt(s->ZMM_D(0), &env->sse_status); +} +#endif /* float to float conversions */ -void helper_cvtps2pd(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_cvtps2pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - float32 s0, s1; - - s0 = s->ZMM_S(0); - s1 = s->ZMM_S(1); - d->ZMM_D(0) = float32_to_float64(s0, &env->sse_status); - d->ZMM_D(1) = float32_to_float64(s1, &env->sse_status); + int i; + for (i = 1 << SHIFT; --i >= 0; ) { + d->ZMM_D(i) = float32_to_float64(s->ZMM_S(i), &env->sse_status); + } } -void helper_cvtpd2ps(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_cvtpd2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->ZMM_S(0) = float64_to_float32(s->ZMM_D(0), &env->sse_status); - d->ZMM_S(1) = float64_to_float32(s->ZMM_D(1), &env->sse_status); - d->Q(1) = 0; + int i; + for (i = 0; i < 1 << SHIFT; i++) { + d->ZMM_S(i) = float64_to_float32(s->ZMM_D(i), &env->sse_status); + } + for (i >>= 1; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } +#if SHIFT == 1 void helper_cvtss2sd(CPUX86State *env, Reg *d, Reg *s) { d->ZMM_D(0) = float32_to_float64(s->ZMM_S(0), &env->sse_status); @@ -673,26 +664,27 @@ void helper_cvtsd2ss(CPUX86State *env, Reg *d, Reg *s) { d->ZMM_S(0) = float64_to_float32(s->ZMM_D(0), &env->sse_status); } +#endif /* integer to float */ -void helper_cvtdq2ps(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_cvtdq2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->ZMM_S(0) = int32_to_float32(s->ZMM_L(0), &env->sse_status); - d->ZMM_S(1) = int32_to_float32(s->ZMM_L(1), &env->sse_status); - d->ZMM_S(2) = int32_to_float32(s->ZMM_L(2), &env->sse_status); - d->ZMM_S(3) = int32_to_float32(s->ZMM_L(3), &env->sse_status); + int i; + for (i = 0; i < 2 << SHIFT; i++) { + d->ZMM_S(i) = int32_to_float32(s->ZMM_L(i), &env->sse_status); + } } -void helper_cvtdq2pd(CPUX86State *env, Reg *d, Reg *s) +void glue(helper_cvtdq2pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - int32_t l0, l1; - - l0 = (int32_t)s->ZMM_L(0); - l1 = (int32_t)s->ZMM_L(1); - d->ZMM_D(0) = int32_to_float64(l0, &env->sse_status); - d->ZMM_D(1) = int32_to_float64(l1, &env->sse_status); + int i; + for (i = 1 << SHIFT; --i >= 0; ) { + int32_t l = s->ZMM_L(i); + d->ZMM_D(i) = int32_to_float64(l, &env->sse_status); + } } +#if SHIFT == 1 void helper_cvtpi2ps(CPUX86State *env, ZMMReg *d, MMXReg *s) { d->ZMM_S(0) = int32_to_float32(s->MMX_L(0), &env->sse_status); @@ -727,8 +719,11 @@ void helper_cvtsq2sd(CPUX86State *env, ZMMReg *d, uint64_t val) } #endif +#endif + /* float to integer */ +#if SHIFT == 1 /* * x86 mandates that we return the indefinite integer value for the result * of any float-to-integer conversion that raises the 'invalid' exception. @@ -759,22 +754,28 @@ WRAP_FLOATCONV(int64_t, float32_to_int64, float32, INT64_MIN) WRAP_FLOATCONV(int64_t, float32_to_int64_round_to_zero, float32, INT64_MIN) WRAP_FLOATCONV(int64_t, float64_to_int64, float64, INT64_MIN) WRAP_FLOATCONV(int64_t, float64_to_int64_round_to_zero, float64, INT64_MIN) +#endif -void helper_cvtps2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s) +void glue(helper_cvtps2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_L(0) = x86_float32_to_int32(s->ZMM_S(0), &env->sse_status); - d->ZMM_L(1) = x86_float32_to_int32(s->ZMM_S(1), &env->sse_status); - d->ZMM_L(2) = x86_float32_to_int32(s->ZMM_S(2), &env->sse_status); - d->ZMM_L(3) = x86_float32_to_int32(s->ZMM_S(3), &env->sse_status); + int i; + for (i = 0; i < 2 << SHIFT; i++) { + d->ZMM_L(i) = x86_float32_to_int32(s->ZMM_S(i), &env->sse_status); + } } -void helper_cvtpd2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s) +void glue(helper_cvtpd2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_L(0) = x86_float64_to_int32(s->ZMM_D(0), &env->sse_status); - d->ZMM_L(1) = x86_float64_to_int32(s->ZMM_D(1), &env->sse_status); - d->ZMM_Q(1) = 0; + int i; + for (i = 0; i < 1 << SHIFT; i++) { + d->ZMM_L(i) = x86_float64_to_int32(s->ZMM_D(i), &env->sse_status); + } + for (i >>= 1; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } +#if SHIFT == 1 void helper_cvtps2pi(CPUX86State *env, MMXReg *d, ZMMReg *s) { d->MMX_L(0) = x86_float32_to_int32(s->ZMM_S(0), &env->sse_status); @@ -808,23 +809,31 @@ int64_t helper_cvtsd2sq(CPUX86State *env, ZMMReg *s) return x86_float64_to_int64(s->ZMM_D(0), &env->sse_status); } #endif +#endif /* float to integer truncated */ -void helper_cvttps2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s) +void glue(helper_cvttps2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_L(0) = x86_float32_to_int32_round_to_zero(s->ZMM_S(0), &env->sse_status); - d->ZMM_L(1) = x86_float32_to_int32_round_to_zero(s->ZMM_S(1), &env->sse_status); - d->ZMM_L(2) = x86_float32_to_int32_round_to_zero(s->ZMM_S(2), &env->sse_status); - d->ZMM_L(3) = x86_float32_to_int32_round_to_zero(s->ZMM_S(3), &env->sse_status); + int i; + for (i = 0; i < 2 << SHIFT; i++) { + d->ZMM_L(i) = x86_float32_to_int32_round_to_zero(s->ZMM_S(i), + &env->sse_status); + } } -void helper_cvttpd2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s) +void glue(helper_cvttpd2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_L(0) = x86_float64_to_int32_round_to_zero(s->ZMM_D(0), &env->sse_status); - d->ZMM_L(1) = x86_float64_to_int32_round_to_zero(s->ZMM_D(1), &env->sse_status); - d->ZMM_Q(1) = 0; + int i; + for (i = 0; i < 1 << SHIFT; i++) { + d->ZMM_L(i) = x86_float64_to_int32_round_to_zero(s->ZMM_D(i), + &env->sse_status); + } + for (i >>= 1; i < 1 << SHIFT; i++) { + d->Q(i) = 0; + } } +#if SHIFT == 1 void helper_cvttps2pi(CPUX86State *env, MMXReg *d, ZMMReg *s) { d->MMX_L(0) = x86_float32_to_int32_round_to_zero(s->ZMM_S(0), &env->sse_status); @@ -858,25 +867,21 @@ int64_t helper_cvttsd2sq(CPUX86State *env, ZMMReg *s) return x86_float64_to_int64_round_to_zero(s->ZMM_D(0), &env->sse_status); } #endif +#endif -void helper_rsqrtps(CPUX86State *env, ZMMReg *d, ZMMReg *s) +void glue(helper_rsqrtps, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s) { uint8_t old_flags = get_float_exception_flags(&env->sse_status); - d->ZMM_S(0) = float32_div(float32_one, - float32_sqrt(s->ZMM_S(0), &env->sse_status), - &env->sse_status); - d->ZMM_S(1) = float32_div(float32_one, - float32_sqrt(s->ZMM_S(1), &env->sse_status), - &env->sse_status); - d->ZMM_S(2) = float32_div(float32_one, - float32_sqrt(s->ZMM_S(2), &env->sse_status), - &env->sse_status); - d->ZMM_S(3) = float32_div(float32_one, - float32_sqrt(s->ZMM_S(3), &env->sse_status), - &env->sse_status); + int i; + for (i = 0; i < 2 << SHIFT; i++) { + d->ZMM_S(i) = float32_div(float32_one, + float32_sqrt(s->ZMM_S(i), &env->sse_status), + &env->sse_status); + } set_float_exception_flags(old_flags, &env->sse_status); } +#if SHIFT == 1 void helper_rsqrtss(CPUX86State *env, ZMMReg *d, ZMMReg *s) { uint8_t old_flags = get_float_exception_flags(&env->sse_status); @@ -885,24 +890,28 @@ void helper_rsqrtss(CPUX86State *env, ZMMReg *d, ZMMReg *s) &env->sse_status); set_float_exception_flags(old_flags, &env->sse_status); } +#endif -void helper_rcpps(CPUX86State *env, ZMMReg *d, ZMMReg *s) +void glue(helper_rcpps, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s) { uint8_t old_flags = get_float_exception_flags(&env->sse_status); - d->ZMM_S(0) = float32_div(float32_one, s->ZMM_S(0), &env->sse_status); - d->ZMM_S(1) = float32_div(float32_one, s->ZMM_S(1), &env->sse_status); - d->ZMM_S(2) = float32_div(float32_one, s->ZMM_S(2), &env->sse_status); - d->ZMM_S(3) = float32_div(float32_one, s->ZMM_S(3), &env->sse_status); + int i; + for (i = 0; i < 2 << SHIFT; i++) { + d->ZMM_S(i) = float32_div(float32_one, s->ZMM_S(i), &env->sse_status); + } set_float_exception_flags(old_flags, &env->sse_status); } +#if SHIFT == 1 void helper_rcpss(CPUX86State *env, ZMMReg *d, ZMMReg *s) { uint8_t old_flags = get_float_exception_flags(&env->sse_status); d->ZMM_S(0) = float32_div(float32_one, s->ZMM_S(0), &env->sse_status); set_float_exception_flags(old_flags, &env->sse_status); } +#endif +#if SHIFT == 1 static inline uint64_t helper_extrq(uint64_t src, int shift, int len) { uint64_t mask; @@ -917,7 +926,7 @@ static inline uint64_t helper_extrq(uint64_t src, int shift, int len) void helper_extrq_r(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_Q(0) = helper_extrq(d->ZMM_Q(0), s->ZMM_B(1), s->ZMM_B(0)); + d->ZMM_Q(0) = helper_extrq(d->ZMM_Q(0), s->ZMM_B(1) & 63, s->ZMM_B(0) & 63); } void helper_extrq_i(CPUX86State *env, ZMMReg *d, int index, int length) @@ -925,7 +934,7 @@ void helper_extrq_i(CPUX86State *env, ZMMReg *d, int index, int length) d->ZMM_Q(0) = helper_extrq(d->ZMM_Q(0), index, length); } -static inline uint64_t helper_insertq(uint64_t src, int shift, int len) +static inline uint64_t helper_insertq(uint64_t dest, uint64_t src, int shift, int len) { uint64_t mask; @@ -934,125 +943,146 @@ static inline uint64_t helper_insertq(uint64_t src, int shift, int len) } else { mask = (1ULL << len) - 1; } - return (src & ~(mask << shift)) | ((src & mask) << shift); + return (dest & ~(mask << shift)) | ((src & mask) << shift); } void helper_insertq_r(CPUX86State *env, ZMMReg *d, ZMMReg *s) { - d->ZMM_Q(0) = helper_insertq(s->ZMM_Q(0), s->ZMM_B(9), s->ZMM_B(8)); + d->ZMM_Q(0) = helper_insertq(d->ZMM_Q(0), s->ZMM_Q(0), s->ZMM_B(9) & 63, s->ZMM_B(8) & 63); } -void helper_insertq_i(CPUX86State *env, ZMMReg *d, int index, int length) +void helper_insertq_i(CPUX86State *env, ZMMReg *d, ZMMReg *s, int index, int length) { - d->ZMM_Q(0) = helper_insertq(d->ZMM_Q(0), index, length); + d->ZMM_Q(0) = helper_insertq(d->ZMM_Q(0), s->ZMM_Q(0), index, length); +} +#endif + +#define SSE_HELPER_HPS(name, F) \ +void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ +{ \ + Reg *v = d; \ + float32 r[2 << SHIFT]; \ + int i, j, k; \ + for (k = 0; k < 2 << SHIFT; k += LANE_WIDTH / 4) { \ + for (i = j = 0; j < 4; i++, j += 2) { \ + r[i + k] = F(v->ZMM_S(j + k), v->ZMM_S(j + k + 1), &env->sse_status); \ + } \ + for (j = 0; j < 4; i++, j += 2) { \ + r[i + k] = F(s->ZMM_S(j + k), s->ZMM_S(j + k + 1), &env->sse_status); \ + } \ + } \ + for (i = 0; i < 2 << SHIFT; i++) { \ + d->ZMM_S(i) = r[i]; \ + } \ } -void helper_haddps(CPUX86State *env, ZMMReg *d, ZMMReg *s) +SSE_HELPER_HPS(haddps, float32_add) +SSE_HELPER_HPS(hsubps, float32_sub) + +#define SSE_HELPER_HPD(name, F) \ +void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ +{ \ + Reg *v = d; \ + float64 r[1 << SHIFT]; \ + int i, j, k; \ + for (k = 0; k < 1 << SHIFT; k += LANE_WIDTH / 8) { \ + for (i = j = 0; j < 2; i++, j += 2) { \ + r[i + k] = F(v->ZMM_D(j + k), v->ZMM_D(j + k + 1), &env->sse_status); \ + } \ + for (j = 0; j < 2; i++, j += 2) { \ + r[i + k] = F(s->ZMM_D(j + k), s->ZMM_D(j + k + 1), &env->sse_status); \ + } \ + } \ + for (i = 0; i < 1 << SHIFT; i++) { \ + d->ZMM_D(i) = r[i]; \ + } \ +} + +SSE_HELPER_HPD(haddpd, float64_add) +SSE_HELPER_HPD(hsubpd, float64_sub) + +void glue(helper_addsubps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - ZMMReg r; - - r.ZMM_S(0) = float32_add(d->ZMM_S(0), d->ZMM_S(1), &env->sse_status); - r.ZMM_S(1) = float32_add(d->ZMM_S(2), d->ZMM_S(3), &env->sse_status); - r.ZMM_S(2) = float32_add(s->ZMM_S(0), s->ZMM_S(1), &env->sse_status); - r.ZMM_S(3) = float32_add(s->ZMM_S(2), s->ZMM_S(3), &env->sse_status); - MOVE(*d, r); + Reg *v = d; + int i; + for (i = 0; i < 2 << SHIFT; i += 2) { + d->ZMM_S(i) = float32_sub(v->ZMM_S(i), s->ZMM_S(i), &env->sse_status); + d->ZMM_S(i+1) = float32_add(v->ZMM_S(i+1), s->ZMM_S(i+1), &env->sse_status); + } } -void helper_haddpd(CPUX86State *env, ZMMReg *d, ZMMReg *s) +void glue(helper_addsubpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - ZMMReg r; - - r.ZMM_D(0) = float64_add(d->ZMM_D(0), d->ZMM_D(1), &env->sse_status); - r.ZMM_D(1) = float64_add(s->ZMM_D(0), s->ZMM_D(1), &env->sse_status); - MOVE(*d, r); + Reg *v = d; + int i; + for (i = 0; i < 1 << SHIFT; i += 2) { + d->ZMM_D(i) = float64_sub(v->ZMM_D(i), s->ZMM_D(i), &env->sse_status); + d->ZMM_D(i+1) = float64_add(v->ZMM_D(i+1), s->ZMM_D(i+1), &env->sse_status); + } } -void helper_hsubps(CPUX86State *env, ZMMReg *d, ZMMReg *s) -{ - ZMMReg r; - - r.ZMM_S(0) = float32_sub(d->ZMM_S(0), d->ZMM_S(1), &env->sse_status); - r.ZMM_S(1) = float32_sub(d->ZMM_S(2), d->ZMM_S(3), &env->sse_status); - r.ZMM_S(2) = float32_sub(s->ZMM_S(0), s->ZMM_S(1), &env->sse_status); - r.ZMM_S(3) = float32_sub(s->ZMM_S(2), s->ZMM_S(3), &env->sse_status); - MOVE(*d, r); -} - -void helper_hsubpd(CPUX86State *env, ZMMReg *d, ZMMReg *s) -{ - ZMMReg r; - - r.ZMM_D(0) = float64_sub(d->ZMM_D(0), d->ZMM_D(1), &env->sse_status); - r.ZMM_D(1) = float64_sub(s->ZMM_D(0), s->ZMM_D(1), &env->sse_status); - MOVE(*d, r); -} - -void helper_addsubps(CPUX86State *env, ZMMReg *d, ZMMReg *s) -{ - d->ZMM_S(0) = float32_sub(d->ZMM_S(0), s->ZMM_S(0), &env->sse_status); - d->ZMM_S(1) = float32_add(d->ZMM_S(1), s->ZMM_S(1), &env->sse_status); - d->ZMM_S(2) = float32_sub(d->ZMM_S(2), s->ZMM_S(2), &env->sse_status); - d->ZMM_S(3) = float32_add(d->ZMM_S(3), s->ZMM_S(3), &env->sse_status); -} - -void helper_addsubpd(CPUX86State *env, ZMMReg *d, ZMMReg *s) -{ - d->ZMM_D(0) = float64_sub(d->ZMM_D(0), s->ZMM_D(0), &env->sse_status); - d->ZMM_D(1) = float64_add(d->ZMM_D(1), s->ZMM_D(1), &env->sse_status); -} - -/* XXX: unordered */ -#define SSE_HELPER_CMP(name, F) \ - void helper_ ## name ## ps(CPUX86State *env, Reg *d, Reg *s) \ +#define SSE_HELPER_CMP_P(name, F, C) \ + void glue(helper_ ## name ## ps, SUFFIX)(CPUX86State *env, \ + Reg *d, Reg *s) \ { \ - d->ZMM_L(0) = F(32, d->ZMM_S(0), s->ZMM_S(0)); \ - d->ZMM_L(1) = F(32, d->ZMM_S(1), s->ZMM_S(1)); \ - d->ZMM_L(2) = F(32, d->ZMM_S(2), s->ZMM_S(2)); \ - d->ZMM_L(3) = F(32, d->ZMM_S(3), s->ZMM_S(3)); \ + Reg *v = d; \ + int i; \ + for (i = 0; i < 2 << SHIFT; i++) { \ + d->ZMM_L(i) = C(F(32, v->ZMM_S(i), s->ZMM_S(i))) ? -1 : 0; \ + } \ } \ \ - void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s) \ + void glue(helper_ ## name ## pd, SUFFIX)(CPUX86State *env, \ + Reg *d, Reg *s) \ { \ - d->ZMM_L(0) = F(32, d->ZMM_S(0), s->ZMM_S(0)); \ - } \ - \ - void helper_ ## name ## pd(CPUX86State *env, Reg *d, Reg *s) \ - { \ - d->ZMM_Q(0) = F(64, d->ZMM_D(0), s->ZMM_D(0)); \ - d->ZMM_Q(1) = F(64, d->ZMM_D(1), s->ZMM_D(1)); \ - } \ - \ - void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s) \ - { \ - d->ZMM_Q(0) = F(64, d->ZMM_D(0), s->ZMM_D(0)); \ + Reg *v = d; \ + int i; \ + for (i = 0; i < 1 << SHIFT; i++) { \ + d->ZMM_Q(i) = C(F(64, v->ZMM_D(i), s->ZMM_D(i))) ? -1 : 0; \ + } \ } -#define FPU_CMPEQ(size, a, b) \ - (float ## size ## _eq_quiet(a, b, &env->sse_status) ? -1 : 0) -#define FPU_CMPLT(size, a, b) \ - (float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0) -#define FPU_CMPLE(size, a, b) \ - (float ## size ## _le(a, b, &env->sse_status) ? -1 : 0) -#define FPU_CMPUNORD(size, a, b) \ - (float ## size ## _unordered_quiet(a, b, &env->sse_status) ? -1 : 0) -#define FPU_CMPNEQ(size, a, b) \ - (float ## size ## _eq_quiet(a, b, &env->sse_status) ? 0 : -1) -#define FPU_CMPNLT(size, a, b) \ - (float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1) -#define FPU_CMPNLE(size, a, b) \ - (float ## size ## _le(a, b, &env->sse_status) ? 0 : -1) -#define FPU_CMPORD(size, a, b) \ - (float ## size ## _unordered_quiet(a, b, &env->sse_status) ? 0 : -1) +#if SHIFT == 1 +#define SSE_HELPER_CMP(name, F, C) \ + SSE_HELPER_CMP_P(name, F, C) \ + void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s) \ + { \ + Reg *v = d; \ + d->ZMM_L(0) = C(F(32, v->ZMM_S(0), s->ZMM_S(0))) ? -1 : 0; \ + } \ + \ + void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s) \ + { \ + Reg *v = d; \ + d->ZMM_Q(0) = C(F(64, v->ZMM_D(0), s->ZMM_D(0))) ? -1 : 0; \ + } -SSE_HELPER_CMP(cmpeq, FPU_CMPEQ) -SSE_HELPER_CMP(cmplt, FPU_CMPLT) -SSE_HELPER_CMP(cmple, FPU_CMPLE) -SSE_HELPER_CMP(cmpunord, FPU_CMPUNORD) -SSE_HELPER_CMP(cmpneq, FPU_CMPNEQ) -SSE_HELPER_CMP(cmpnlt, FPU_CMPNLT) -SSE_HELPER_CMP(cmpnle, FPU_CMPNLE) -SSE_HELPER_CMP(cmpord, FPU_CMPORD) +#define FPU_EQ(x) (x == float_relation_equal) +#define FPU_LT(x) (x == float_relation_less) +#define FPU_LE(x) (x <= float_relation_equal) +#define FPU_UNORD(x) (x == float_relation_unordered) +#define FPU_CMPQ(size, a, b) \ + float ## size ## _compare_quiet(a, b, &env->sse_status) +#define FPU_CMPS(size, a, b) \ + float ## size ## _compare(a, b, &env->sse_status) + +#else +#define SSE_HELPER_CMP(name, F, C) SSE_HELPER_CMP_P(name, F, C) +#endif + +SSE_HELPER_CMP(cmpeq, FPU_CMPQ, FPU_EQ) +SSE_HELPER_CMP(cmplt, FPU_CMPS, FPU_LT) +SSE_HELPER_CMP(cmple, FPU_CMPS, FPU_LE) +SSE_HELPER_CMP(cmpunord, FPU_CMPQ, FPU_UNORD) +SSE_HELPER_CMP(cmpneq, FPU_CMPQ, !FPU_EQ) +SSE_HELPER_CMP(cmpnlt, FPU_CMPS, !FPU_LT) +SSE_HELPER_CMP(cmpnle, FPU_CMPS, !FPU_LE) +SSE_HELPER_CMP(cmpord, FPU_CMPQ, !FPU_UNORD) + +#undef SSE_HELPER_CMP + +#if SHIFT == 1 static const int comis_eflags[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; void helper_ucomiss(CPUX86State *env, Reg *d, Reg *s) @@ -1098,25 +1128,30 @@ void helper_comisd(CPUX86State *env, Reg *d, Reg *s) ret = float64_compare(d0, d1, &env->sse_status); CC_SRC = comis_eflags[ret + 1]; } +#endif -uint32_t helper_movmskps(CPUX86State *env, Reg *s) +uint32_t glue(helper_movmskps, SUFFIX)(CPUX86State *env, Reg *s) { - int b0, b1, b2, b3; + uint32_t mask; + int i; - b0 = s->ZMM_L(0) >> 31; - b1 = s->ZMM_L(1) >> 31; - b2 = s->ZMM_L(2) >> 31; - b3 = s->ZMM_L(3) >> 31; - return b0 | (b1 << 1) | (b2 << 2) | (b3 << 3); + mask = 0; + for (i = 0; i < 2 << SHIFT; i++) { + mask |= (s->ZMM_L(i) >> (31 - i)) & (1 << i); + } + return mask; } -uint32_t helper_movmskpd(CPUX86State *env, Reg *s) +uint32_t glue(helper_movmskpd, SUFFIX)(CPUX86State *env, Reg *s) { - int b0, b1; + uint32_t mask; + int i; - b0 = s->ZMM_L(1) >> 31; - b1 = s->ZMM_L(3) >> 31; - return b0 | (b1 << 1); + mask = 0; + for (i = 0; i < 1 << SHIFT; i++) { + mask |= (s->ZMM_Q(i) >> (63 - i)) & (1 << i); + } + return mask; } #endif @@ -1124,179 +1159,150 @@ uint32_t helper_movmskpd(CPUX86State *env, Reg *s) uint32_t glue(helper_pmovmskb, SUFFIX)(CPUX86State *env, Reg *s) { uint32_t val; + int i; val = 0; - val |= (s->B(0) >> 7); - val |= (s->B(1) >> 6) & 0x02; - val |= (s->B(2) >> 5) & 0x04; - val |= (s->B(3) >> 4) & 0x08; - val |= (s->B(4) >> 3) & 0x10; - val |= (s->B(5) >> 2) & 0x20; - val |= (s->B(6) >> 1) & 0x40; - val |= (s->B(7)) & 0x80; -#if SHIFT == 1 - val |= (s->B(8) << 1) & 0x0100; - val |= (s->B(9) << 2) & 0x0200; - val |= (s->B(10) << 3) & 0x0400; - val |= (s->B(11) << 4) & 0x0800; - val |= (s->B(12) << 5) & 0x1000; - val |= (s->B(13) << 6) & 0x2000; - val |= (s->B(14) << 7) & 0x4000; - val |= (s->B(15) << 8) & 0x8000; -#endif + for (i = 0; i < (1 << SHIFT); i++) { + uint8_t byte = 0; + byte |= (s->B(8 * i + 0) >> 7); + byte |= (s->B(8 * i + 1) >> 6) & 0x02; + byte |= (s->B(8 * i + 2) >> 5) & 0x04; + byte |= (s->B(8 * i + 3) >> 4) & 0x08; + byte |= (s->B(8 * i + 4) >> 3) & 0x10; + byte |= (s->B(8 * i + 5) >> 2) & 0x20; + byte |= (s->B(8 * i + 6) >> 1) & 0x40; + byte |= (s->B(8 * i + 7)) & 0x80; + val |= byte << (8 * i); + } return val; } -void glue(helper_packsswb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - Reg r; - - r.B(0) = satsb((int16_t)d->W(0)); - r.B(1) = satsb((int16_t)d->W(1)); - r.B(2) = satsb((int16_t)d->W(2)); - r.B(3) = satsb((int16_t)d->W(3)); -#if SHIFT == 1 - r.B(4) = satsb((int16_t)d->W(4)); - r.B(5) = satsb((int16_t)d->W(5)); - r.B(6) = satsb((int16_t)d->W(6)); - r.B(7) = satsb((int16_t)d->W(7)); -#endif - r.B((4 << SHIFT) + 0) = satsb((int16_t)s->W(0)); - r.B((4 << SHIFT) + 1) = satsb((int16_t)s->W(1)); - r.B((4 << SHIFT) + 2) = satsb((int16_t)s->W(2)); - r.B((4 << SHIFT) + 3) = satsb((int16_t)s->W(3)); -#if SHIFT == 1 - r.B(12) = satsb((int16_t)s->W(4)); - r.B(13) = satsb((int16_t)s->W(5)); - r.B(14) = satsb((int16_t)s->W(6)); - r.B(15) = satsb((int16_t)s->W(7)); -#endif - MOVE(*d, r); +#define PACK_HELPER_B(name, F) \ +void glue(helper_pack ## name, SUFFIX)(CPUX86State *env, \ + Reg *d, Reg *s) \ +{ \ + Reg *v = d; \ + uint8_t r[PACK_WIDTH * 2]; \ + int j, k; \ + for (j = 0; j < 4 << SHIFT; j += PACK_WIDTH) { \ + for (k = 0; k < PACK_WIDTH; k++) { \ + r[k] = F((int16_t)v->W(j + k)); \ + } \ + for (k = 0; k < PACK_WIDTH; k++) { \ + r[PACK_WIDTH + k] = F((int16_t)s->W(j + k)); \ + } \ + for (k = 0; k < PACK_WIDTH * 2; k++) { \ + d->B(2 * j + k) = r[k]; \ + } \ + } \ } -void glue(helper_packuswb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - Reg r; - - r.B(0) = satub((int16_t)d->W(0)); - r.B(1) = satub((int16_t)d->W(1)); - r.B(2) = satub((int16_t)d->W(2)); - r.B(3) = satub((int16_t)d->W(3)); -#if SHIFT == 1 - r.B(4) = satub((int16_t)d->W(4)); - r.B(5) = satub((int16_t)d->W(5)); - r.B(6) = satub((int16_t)d->W(6)); - r.B(7) = satub((int16_t)d->W(7)); -#endif - r.B((4 << SHIFT) + 0) = satub((int16_t)s->W(0)); - r.B((4 << SHIFT) + 1) = satub((int16_t)s->W(1)); - r.B((4 << SHIFT) + 2) = satub((int16_t)s->W(2)); - r.B((4 << SHIFT) + 3) = satub((int16_t)s->W(3)); -#if SHIFT == 1 - r.B(12) = satub((int16_t)s->W(4)); - r.B(13) = satub((int16_t)s->W(5)); - r.B(14) = satub((int16_t)s->W(6)); - r.B(15) = satub((int16_t)s->W(7)); -#endif - MOVE(*d, r); -} +PACK_HELPER_B(sswb, satsb) +PACK_HELPER_B(uswb, satub) void glue(helper_packssdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - Reg r; + Reg *v = d; + uint16_t r[PACK_WIDTH]; + int j, k; - r.W(0) = satsw(d->L(0)); - r.W(1) = satsw(d->L(1)); -#if SHIFT == 1 - r.W(2) = satsw(d->L(2)); - r.W(3) = satsw(d->L(3)); -#endif - r.W((2 << SHIFT) + 0) = satsw(s->L(0)); - r.W((2 << SHIFT) + 1) = satsw(s->L(1)); -#if SHIFT == 1 - r.W(6) = satsw(s->L(2)); - r.W(7) = satsw(s->L(3)); -#endif - MOVE(*d, r); + for (j = 0; j < 2 << SHIFT; j += PACK_WIDTH / 2) { + for (k = 0; k < PACK_WIDTH / 2; k++) { + r[k] = satsw(v->L(j + k)); + } + for (k = 0; k < PACK_WIDTH / 2; k++) { + r[PACK_WIDTH / 2 + k] = satsw(s->L(j + k)); + } + for (k = 0; k < PACK_WIDTH; k++) { + d->W(2 * j + k) = r[k]; + } + } } #define UNPCK_OP(base_name, base) \ \ void glue(helper_punpck ## base_name ## bw, SUFFIX)(CPUX86State *env,\ - Reg *d, Reg *s) \ + Reg *d, Reg *s) \ { \ - Reg r; \ + Reg *v = d; \ + uint8_t r[PACK_WIDTH * 2]; \ + int j, i; \ \ - r.B(0) = d->B((base << (SHIFT + 2)) + 0); \ - r.B(1) = s->B((base << (SHIFT + 2)) + 0); \ - r.B(2) = d->B((base << (SHIFT + 2)) + 1); \ - r.B(3) = s->B((base << (SHIFT + 2)) + 1); \ - r.B(4) = d->B((base << (SHIFT + 2)) + 2); \ - r.B(5) = s->B((base << (SHIFT + 2)) + 2); \ - r.B(6) = d->B((base << (SHIFT + 2)) + 3); \ - r.B(7) = s->B((base << (SHIFT + 2)) + 3); \ - XMM_ONLY( \ - r.B(8) = d->B((base << (SHIFT + 2)) + 4); \ - r.B(9) = s->B((base << (SHIFT + 2)) + 4); \ - r.B(10) = d->B((base << (SHIFT + 2)) + 5); \ - r.B(11) = s->B((base << (SHIFT + 2)) + 5); \ - r.B(12) = d->B((base << (SHIFT + 2)) + 6); \ - r.B(13) = s->B((base << (SHIFT + 2)) + 6); \ - r.B(14) = d->B((base << (SHIFT + 2)) + 7); \ - r.B(15) = s->B((base << (SHIFT + 2)) + 7); \ - ) \ - MOVE(*d, r); \ + for (j = 0; j < 8 << SHIFT; ) { \ + int k = j + base * PACK_WIDTH; \ + for (i = 0; i < PACK_WIDTH; i++) { \ + r[2 * i] = v->B(k + i); \ + r[2 * i + 1] = s->B(k + i); \ + } \ + for (i = 0; i < PACK_WIDTH * 2; i++, j++) { \ + d->B(j) = r[i]; \ + } \ + } \ } \ \ void glue(helper_punpck ## base_name ## wd, SUFFIX)(CPUX86State *env,\ - Reg *d, Reg *s) \ + Reg *d, Reg *s) \ { \ - Reg r; \ + Reg *v = d; \ + uint16_t r[PACK_WIDTH]; \ + int j, i; \ \ - r.W(0) = d->W((base << (SHIFT + 1)) + 0); \ - r.W(1) = s->W((base << (SHIFT + 1)) + 0); \ - r.W(2) = d->W((base << (SHIFT + 1)) + 1); \ - r.W(3) = s->W((base << (SHIFT + 1)) + 1); \ - XMM_ONLY( \ - r.W(4) = d->W((base << (SHIFT + 1)) + 2); \ - r.W(5) = s->W((base << (SHIFT + 1)) + 2); \ - r.W(6) = d->W((base << (SHIFT + 1)) + 3); \ - r.W(7) = s->W((base << (SHIFT + 1)) + 3); \ - ) \ - MOVE(*d, r); \ + for (j = 0; j < 4 << SHIFT; ) { \ + int k = j + base * PACK_WIDTH / 2; \ + for (i = 0; i < PACK_WIDTH / 2; i++) { \ + r[2 * i] = v->W(k + i); \ + r[2 * i + 1] = s->W(k + i); \ + } \ + for (i = 0; i < PACK_WIDTH; i++, j++) { \ + d->W(j) = r[i]; \ + } \ + } \ } \ \ void glue(helper_punpck ## base_name ## dq, SUFFIX)(CPUX86State *env,\ - Reg *d, Reg *s) \ + Reg *d, Reg *s) \ { \ - Reg r; \ + Reg *v = d; \ + uint32_t r[PACK_WIDTH / 2]; \ + int j, i; \ \ - r.L(0) = d->L((base << SHIFT) + 0); \ - r.L(1) = s->L((base << SHIFT) + 0); \ - XMM_ONLY( \ - r.L(2) = d->L((base << SHIFT) + 1); \ - r.L(3) = s->L((base << SHIFT) + 1); \ - ) \ - MOVE(*d, r); \ + for (j = 0; j < 2 << SHIFT; ) { \ + int k = j + base * PACK_WIDTH / 4; \ + for (i = 0; i < PACK_WIDTH / 4; i++) { \ + r[2 * i] = v->L(k + i); \ + r[2 * i + 1] = s->L(k + i); \ + } \ + for (i = 0; i < PACK_WIDTH / 2; i++, j++) { \ + d->L(j) = r[i]; \ + } \ + } \ } \ \ XMM_ONLY( \ - void glue(helper_punpck ## base_name ## qdq, SUFFIX)(CPUX86State \ - *env, \ - Reg *d, \ - Reg *s) \ + void glue(helper_punpck ## base_name ## qdq, SUFFIX)( \ + CPUX86State *env, Reg *d, Reg *s) \ { \ - Reg r; \ + Reg *v = d; \ + uint64_t r[2]; \ + int i; \ \ - r.Q(0) = d->Q(base); \ - r.Q(1) = s->Q(base); \ - MOVE(*d, r); \ + for (i = 0; i < 1 << SHIFT; i += 2) { \ + r[0] = v->Q(base + i); \ + r[1] = s->Q(base + i); \ + d->Q(i) = r[0]; \ + d->Q(i + 1) = r[1]; \ + } \ } \ ) UNPCK_OP(l, 0) UNPCK_OP(h, 1) +#undef PACK_WIDTH +#undef PACK_HELPER_B +#undef UNPCK_OP + + /* 3DNow! float ops */ #if SHIFT == 0 void helper_pi2fd(CPUX86State *env, MMXReg *d, MMXReg *s) @@ -1327,11 +1333,11 @@ void helper_pf2iw(CPUX86State *env, MMXReg *d, MMXReg *s) void helper_pfacc(CPUX86State *env, MMXReg *d, MMXReg *s) { - MMXReg r; + float32 r; - r.MMX_S(0) = float32_add(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); - r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); - MOVE(*d, r); + r = float32_add(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); + d->MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); + d->MMX_S(0) = r; } void helper_pfadd(CPUX86State *env, MMXReg *d, MMXReg *s) @@ -1392,20 +1398,20 @@ void helper_pfmul(CPUX86State *env, MMXReg *d, MMXReg *s) void helper_pfnacc(CPUX86State *env, MMXReg *d, MMXReg *s) { - MMXReg r; + float32 r; - r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); - r.MMX_S(1) = float32_sub(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); - MOVE(*d, r); + r = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); + d->MMX_S(1) = float32_sub(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); + d->MMX_S(0) = r; } void helper_pfpnacc(CPUX86State *env, MMXReg *d, MMXReg *s) { - MMXReg r; + float32 r; - r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); - r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); - MOVE(*d, r); + r = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); + d->MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); + d->MMX_S(0) = r; } void helper_pfrcp(CPUX86State *env, MMXReg *d, MMXReg *s) @@ -1438,132 +1444,105 @@ void helper_pfsubr(CPUX86State *env, MMXReg *d, MMXReg *s) void helper_pswapd(CPUX86State *env, MMXReg *d, MMXReg *s) { - MMXReg r; + uint32_t r; - r.MMX_L(0) = s->MMX_L(1); - r.MMX_L(1) = s->MMX_L(0); - MOVE(*d, r); + r = s->MMX_L(0); + d->MMX_L(0) = s->MMX_L(1); + d->MMX_L(1) = r; } #endif /* SSSE3 op helpers */ void glue(helper_pshufb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { + Reg *v = d; int i; - Reg r; +#if SHIFT == 0 + uint8_t r[8]; - for (i = 0; i < (8 << SHIFT); i++) { - r.B(i) = (s->B(i) & 0x80) ? 0 : (d->B(s->B(i) & ((8 << SHIFT) - 1))); + for (i = 0; i < 8; i++) { + r[i] = (s->B(i) & 0x80) ? 0 : (v->B(s->B(i) & 7)); } + for (i = 0; i < 8; i++) { + d->B(i) = r[i]; + } +#else + uint8_t r[8 << SHIFT]; - MOVE(*d, r); -} - -void glue(helper_phaddw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - - Reg r; - - r.W(0) = (int16_t)d->W(0) + (int16_t)d->W(1); - r.W(1) = (int16_t)d->W(2) + (int16_t)d->W(3); - XMM_ONLY(r.W(2) = (int16_t)d->W(4) + (int16_t)d->W(5)); - XMM_ONLY(r.W(3) = (int16_t)d->W(6) + (int16_t)d->W(7)); - r.W((2 << SHIFT) + 0) = (int16_t)s->W(0) + (int16_t)s->W(1); - r.W((2 << SHIFT) + 1) = (int16_t)s->W(2) + (int16_t)s->W(3); - XMM_ONLY(r.W(6) = (int16_t)s->W(4) + (int16_t)s->W(5)); - XMM_ONLY(r.W(7) = (int16_t)s->W(6) + (int16_t)s->W(7)); - - MOVE(*d, r); -} - -void glue(helper_phaddd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - Reg r; - - r.L(0) = (int32_t)d->L(0) + (int32_t)d->L(1); - XMM_ONLY(r.L(1) = (int32_t)d->L(2) + (int32_t)d->L(3)); - r.L((1 << SHIFT) + 0) = (int32_t)s->L(0) + (int32_t)s->L(1); - XMM_ONLY(r.L(3) = (int32_t)s->L(2) + (int32_t)s->L(3)); - - MOVE(*d, r); -} - -void glue(helper_phaddsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - Reg r; - - r.W(0) = satsw((int16_t)d->W(0) + (int16_t)d->W(1)); - r.W(1) = satsw((int16_t)d->W(2) + (int16_t)d->W(3)); - XMM_ONLY(r.W(2) = satsw((int16_t)d->W(4) + (int16_t)d->W(5))); - XMM_ONLY(r.W(3) = satsw((int16_t)d->W(6) + (int16_t)d->W(7))); - r.W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) + (int16_t)s->W(1)); - r.W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) + (int16_t)s->W(3)); - XMM_ONLY(r.W(6) = satsw((int16_t)s->W(4) + (int16_t)s->W(5))); - XMM_ONLY(r.W(7) = satsw((int16_t)s->W(6) + (int16_t)s->W(7))); - - MOVE(*d, r); -} - -void glue(helper_pmaddubsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - d->W(0) = satsw((int8_t)s->B(0) * (uint8_t)d->B(0) + - (int8_t)s->B(1) * (uint8_t)d->B(1)); - d->W(1) = satsw((int8_t)s->B(2) * (uint8_t)d->B(2) + - (int8_t)s->B(3) * (uint8_t)d->B(3)); - d->W(2) = satsw((int8_t)s->B(4) * (uint8_t)d->B(4) + - (int8_t)s->B(5) * (uint8_t)d->B(5)); - d->W(3) = satsw((int8_t)s->B(6) * (uint8_t)d->B(6) + - (int8_t)s->B(7) * (uint8_t)d->B(7)); -#if SHIFT == 1 - d->W(4) = satsw((int8_t)s->B(8) * (uint8_t)d->B(8) + - (int8_t)s->B(9) * (uint8_t)d->B(9)); - d->W(5) = satsw((int8_t)s->B(10) * (uint8_t)d->B(10) + - (int8_t)s->B(11) * (uint8_t)d->B(11)); - d->W(6) = satsw((int8_t)s->B(12) * (uint8_t)d->B(12) + - (int8_t)s->B(13) * (uint8_t)d->B(13)); - d->W(7) = satsw((int8_t)s->B(14) * (uint8_t)d->B(14) + - (int8_t)s->B(15) * (uint8_t)d->B(15)); + for (i = 0; i < 8 << SHIFT; i++) { + int j = i & ~0xf; + r[i] = (s->B(i) & 0x80) ? 0 : v->B(j | (s->B(i) & 0xf)); + } + for (i = 0; i < 8 << SHIFT; i++) { + d->B(i) = r[i]; + } #endif } -void glue(helper_phsubw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - d->W(0) = (int16_t)d->W(0) - (int16_t)d->W(1); - d->W(1) = (int16_t)d->W(2) - (int16_t)d->W(3); - XMM_ONLY(d->W(2) = (int16_t)d->W(4) - (int16_t)d->W(5)); - XMM_ONLY(d->W(3) = (int16_t)d->W(6) - (int16_t)d->W(7)); - d->W((2 << SHIFT) + 0) = (int16_t)s->W(0) - (int16_t)s->W(1); - d->W((2 << SHIFT) + 1) = (int16_t)s->W(2) - (int16_t)s->W(3); - XMM_ONLY(d->W(6) = (int16_t)s->W(4) - (int16_t)s->W(5)); - XMM_ONLY(d->W(7) = (int16_t)s->W(6) - (int16_t)s->W(7)); +#define SSE_HELPER_HW(name, F) \ +void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ +{ \ + Reg *v = d; \ + uint16_t r[4 << SHIFT]; \ + int i, j, k; \ + for (k = 0; k < 4 << SHIFT; k += LANE_WIDTH / 2) { \ + for (i = j = 0; j < LANE_WIDTH / 2; i++, j += 2) { \ + r[i + k] = F(v->W(j + k), v->W(j + k + 1)); \ + } \ + for (j = 0; j < LANE_WIDTH / 2; i++, j += 2) { \ + r[i + k] = F(s->W(j + k), s->W(j + k + 1)); \ + } \ + } \ + for (i = 0; i < 4 << SHIFT; i++) { \ + d->W(i) = r[i]; \ + } \ } -void glue(helper_phsubd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) -{ - d->L(0) = (int32_t)d->L(0) - (int32_t)d->L(1); - XMM_ONLY(d->L(1) = (int32_t)d->L(2) - (int32_t)d->L(3)); - d->L((1 << SHIFT) + 0) = (int32_t)s->L(0) - (int32_t)s->L(1); - XMM_ONLY(d->L(3) = (int32_t)s->L(2) - (int32_t)s->L(3)); +#define SSE_HELPER_HL(name, F) \ +void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ +{ \ + Reg *v = d; \ + uint32_t r[2 << SHIFT]; \ + int i, j, k; \ + for (k = 0; k < 2 << SHIFT; k += LANE_WIDTH / 4) { \ + for (i = j = 0; j < LANE_WIDTH / 4; i++, j += 2) { \ + r[i + k] = F(v->L(j + k), v->L(j + k + 1)); \ + } \ + for (j = 0; j < LANE_WIDTH / 4; i++, j += 2) { \ + r[i + k] = F(s->L(j + k), s->L(j + k + 1)); \ + } \ + } \ + for (i = 0; i < 2 << SHIFT; i++) { \ + d->L(i) = r[i]; \ + } \ } -void glue(helper_phsubsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) +SSE_HELPER_HW(phaddw, FADD) +SSE_HELPER_HW(phsubw, FSUB) +SSE_HELPER_HW(phaddsw, FADDSW) +SSE_HELPER_HW(phsubsw, FSUBSW) +SSE_HELPER_HL(phaddd, FADD) +SSE_HELPER_HL(phsubd, FSUB) + +#undef SSE_HELPER_HW +#undef SSE_HELPER_HL + +void glue(helper_pmaddubsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->W(0) = satsw((int16_t)d->W(0) - (int16_t)d->W(1)); - d->W(1) = satsw((int16_t)d->W(2) - (int16_t)d->W(3)); - XMM_ONLY(d->W(2) = satsw((int16_t)d->W(4) - (int16_t)d->W(5))); - XMM_ONLY(d->W(3) = satsw((int16_t)d->W(6) - (int16_t)d->W(7))); - d->W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) - (int16_t)s->W(1)); - d->W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) - (int16_t)s->W(3)); - XMM_ONLY(d->W(6) = satsw((int16_t)s->W(4) - (int16_t)s->W(5))); - XMM_ONLY(d->W(7) = satsw((int16_t)s->W(6) - (int16_t)s->W(7))); + Reg *v = d; + int i; + for (i = 0; i < 4 << SHIFT; i++) { + d->W(i) = satsw((int8_t)s->B(i * 2) * (uint8_t)v->B(i * 2) + + (int8_t)s->B(i * 2 + 1) * (uint8_t)v->B(i * 2 + 1)); + } } -#define FABSB(_, x) (x > INT8_MAX ? -(int8_t)x : x) -#define FABSW(_, x) (x > INT16_MAX ? -(int16_t)x : x) -#define FABSL(_, x) (x > INT32_MAX ? -(int32_t)x : x) -SSE_HELPER_B(helper_pabsb, FABSB) -SSE_HELPER_W(helper_pabsw, FABSW) -SSE_HELPER_L(helper_pabsd, FABSL) +#define FABSB(x) (x > INT8_MAX ? -(int8_t)x : x) +#define FABSW(x) (x > INT16_MAX ? -(int16_t)x : x) +#define FABSL(x) (x > INT32_MAX ? -(int32_t)x : x) +SSE_HELPER_1(helper_pabsb, B, 8 << SHIFT, FABSB) +SSE_HELPER_1(helper_pabsw, W, 4 << SHIFT, FABSW) +SSE_HELPER_1(helper_pabsd, L, 2 << SHIFT, FABSL) #define FMULHRSW(d, s) (((int16_t) d * (int16_t)s + 0x4000) >> 15) SSE_HELPER_W(helper_pmulhrsw, FMULHRSW) @@ -1578,147 +1557,117 @@ SSE_HELPER_L(helper_psignd, FSIGNL) void glue(helper_palignr, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, int32_t shift) { - Reg r; + Reg *v = d; + int i; /* XXX could be checked during translation */ - if (shift >= (16 << SHIFT)) { - r.Q(0) = 0; - XMM_ONLY(r.Q(1) = 0); + if (shift >= (SHIFT ? 32 : 16)) { + for (i = 0; i < (1 << SHIFT); i++) { + d->Q(i) = 0; + } } else { shift <<= 3; #define SHR(v, i) (i < 64 && i > -64 ? i > 0 ? v >> (i) : (v << -(i)) : 0) #if SHIFT == 0 - r.Q(0) = SHR(s->Q(0), shift - 0) | - SHR(d->Q(0), shift - 64); + d->Q(0) = SHR(s->Q(0), shift - 0) | + SHR(v->Q(0), shift - 64); #else - r.Q(0) = SHR(s->Q(0), shift - 0) | - SHR(s->Q(1), shift - 64) | - SHR(d->Q(0), shift - 128) | - SHR(d->Q(1), shift - 192); - r.Q(1) = SHR(s->Q(0), shift + 64) | - SHR(s->Q(1), shift - 0) | - SHR(d->Q(0), shift - 64) | - SHR(d->Q(1), shift - 128); + for (i = 0; i < (1 << SHIFT); i += 2) { + uint64_t r0, r1; + + r0 = SHR(s->Q(i), shift - 0) | + SHR(s->Q(i + 1), shift - 64) | + SHR(v->Q(i), shift - 128) | + SHR(v->Q(i + 1), shift - 192); + r1 = SHR(s->Q(i), shift + 64) | + SHR(s->Q(i + 1), shift - 0) | + SHR(v->Q(i), shift - 64) | + SHR(v->Q(i + 1), shift - 128); + d->Q(i) = r0; + d->Q(i + 1) = r1; + } #endif #undef SHR } - - MOVE(*d, r); } -#define XMM0 (env->xmm_regs[0]) +#if SHIFT >= 1 -#if SHIFT == 1 #define SSE_HELPER_V(name, elem, num, F) \ - void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ + void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ { \ - d->elem(0) = F(d->elem(0), s->elem(0), XMM0.elem(0)); \ - d->elem(1) = F(d->elem(1), s->elem(1), XMM0.elem(1)); \ - if (num > 2) { \ - d->elem(2) = F(d->elem(2), s->elem(2), XMM0.elem(2)); \ - d->elem(3) = F(d->elem(3), s->elem(3), XMM0.elem(3)); \ - if (num > 4) { \ - d->elem(4) = F(d->elem(4), s->elem(4), XMM0.elem(4)); \ - d->elem(5) = F(d->elem(5), s->elem(5), XMM0.elem(5)); \ - d->elem(6) = F(d->elem(6), s->elem(6), XMM0.elem(6)); \ - d->elem(7) = F(d->elem(7), s->elem(7), XMM0.elem(7)); \ - if (num > 8) { \ - d->elem(8) = F(d->elem(8), s->elem(8), XMM0.elem(8)); \ - d->elem(9) = F(d->elem(9), s->elem(9), XMM0.elem(9)); \ - d->elem(10) = F(d->elem(10), s->elem(10), XMM0.elem(10)); \ - d->elem(11) = F(d->elem(11), s->elem(11), XMM0.elem(11)); \ - d->elem(12) = F(d->elem(12), s->elem(12), XMM0.elem(12)); \ - d->elem(13) = F(d->elem(13), s->elem(13), XMM0.elem(13)); \ - d->elem(14) = F(d->elem(14), s->elem(14), XMM0.elem(14)); \ - d->elem(15) = F(d->elem(15), s->elem(15), XMM0.elem(15)); \ - } \ - } \ + Reg *v = d; \ + Reg *m = &env->xmm_regs[0]; \ + int i; \ + for (i = 0; i < num; i++) { \ + d->elem(i) = F(v->elem(i), s->elem(i), m->elem(i)); \ } \ } #define SSE_HELPER_I(name, elem, num, F) \ - void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t imm) \ + void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, \ + uint32_t imm) \ { \ - d->elem(0) = F(d->elem(0), s->elem(0), ((imm >> 0) & 1)); \ - d->elem(1) = F(d->elem(1), s->elem(1), ((imm >> 1) & 1)); \ - if (num > 2) { \ - d->elem(2) = F(d->elem(2), s->elem(2), ((imm >> 2) & 1)); \ - d->elem(3) = F(d->elem(3), s->elem(3), ((imm >> 3) & 1)); \ - if (num > 4) { \ - d->elem(4) = F(d->elem(4), s->elem(4), ((imm >> 4) & 1)); \ - d->elem(5) = F(d->elem(5), s->elem(5), ((imm >> 5) & 1)); \ - d->elem(6) = F(d->elem(6), s->elem(6), ((imm >> 6) & 1)); \ - d->elem(7) = F(d->elem(7), s->elem(7), ((imm >> 7) & 1)); \ - if (num > 8) { \ - d->elem(8) = F(d->elem(8), s->elem(8), ((imm >> 8) & 1)); \ - d->elem(9) = F(d->elem(9), s->elem(9), ((imm >> 9) & 1)); \ - d->elem(10) = F(d->elem(10), s->elem(10), \ - ((imm >> 10) & 1)); \ - d->elem(11) = F(d->elem(11), s->elem(11), \ - ((imm >> 11) & 1)); \ - d->elem(12) = F(d->elem(12), s->elem(12), \ - ((imm >> 12) & 1)); \ - d->elem(13) = F(d->elem(13), s->elem(13), \ - ((imm >> 13) & 1)); \ - d->elem(14) = F(d->elem(14), s->elem(14), \ - ((imm >> 14) & 1)); \ - d->elem(15) = F(d->elem(15), s->elem(15), \ - ((imm >> 15) & 1)); \ - } \ - } \ + Reg *v = d; \ + int i; \ + for (i = 0; i < num; i++) { \ + int j = i & 7; \ + d->elem(i) = F(v->elem(i), s->elem(i), (imm >> j) & 1); \ } \ } /* SSE4.1 op helpers */ -#define FBLENDVB(d, s, m) ((m & 0x80) ? s : d) -#define FBLENDVPS(d, s, m) ((m & 0x80000000) ? s : d) -#define FBLENDVPD(d, s, m) ((m & 0x8000000000000000LL) ? s : d) -SSE_HELPER_V(helper_pblendvb, B, 16, FBLENDVB) -SSE_HELPER_V(helper_blendvps, L, 4, FBLENDVPS) -SSE_HELPER_V(helper_blendvpd, Q, 2, FBLENDVPD) +#define FBLENDVB(v, s, m) ((m & 0x80) ? s : v) +#define FBLENDVPS(v, s, m) ((m & 0x80000000) ? s : v) +#define FBLENDVPD(v, s, m) ((m & 0x8000000000000000LL) ? s : v) +SSE_HELPER_V(helper_pblendvb, B, 8 << SHIFT, FBLENDVB) +SSE_HELPER_V(helper_blendvps, L, 2 << SHIFT, FBLENDVPS) +SSE_HELPER_V(helper_blendvpd, Q, 1 << SHIFT, FBLENDVPD) void glue(helper_ptest, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - uint64_t zf = (s->Q(0) & d->Q(0)) | (s->Q(1) & d->Q(1)); - uint64_t cf = (s->Q(0) & ~d->Q(0)) | (s->Q(1) & ~d->Q(1)); + uint64_t zf = 0, cf = 0; + int i; + for (i = 0; i < 1 << SHIFT; i++) { + zf |= (s->Q(i) & d->Q(i)); + cf |= (s->Q(i) & ~d->Q(i)); + } CC_SRC = (zf ? 0 : CC_Z) | (cf ? 0 : CC_C); } -#define SSE_HELPER_F(name, elem, num, F) \ - void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ - { \ - if (num > 2) { \ - if (num > 4) { \ - d->elem(7) = F(7); \ - d->elem(6) = F(6); \ - d->elem(5) = F(5); \ - d->elem(4) = F(4); \ - } \ - d->elem(3) = F(3); \ - d->elem(2) = F(2); \ - } \ - d->elem(1) = F(1); \ - d->elem(0) = F(0); \ +#define SSE_HELPER_F(name, elem, num, F) \ + void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ + { \ + int n = num; \ + for (int i = n; --i >= 0; ) { \ + d->elem(i) = F(i); \ + } \ } -SSE_HELPER_F(helper_pmovsxbw, W, 8, (int8_t) s->B) -SSE_HELPER_F(helper_pmovsxbd, L, 4, (int8_t) s->B) -SSE_HELPER_F(helper_pmovsxbq, Q, 2, (int8_t) s->B) -SSE_HELPER_F(helper_pmovsxwd, L, 4, (int16_t) s->W) -SSE_HELPER_F(helper_pmovsxwq, Q, 2, (int16_t) s->W) -SSE_HELPER_F(helper_pmovsxdq, Q, 2, (int32_t) s->L) -SSE_HELPER_F(helper_pmovzxbw, W, 8, s->B) -SSE_HELPER_F(helper_pmovzxbd, L, 4, s->B) -SSE_HELPER_F(helper_pmovzxbq, Q, 2, s->B) -SSE_HELPER_F(helper_pmovzxwd, L, 4, s->W) -SSE_HELPER_F(helper_pmovzxwq, Q, 2, s->W) -SSE_HELPER_F(helper_pmovzxdq, Q, 2, s->L) +#if SHIFT > 0 +SSE_HELPER_F(helper_pmovsxbw, W, 4 << SHIFT, (int8_t) s->B) +SSE_HELPER_F(helper_pmovsxbd, L, 2 << SHIFT, (int8_t) s->B) +SSE_HELPER_F(helper_pmovsxbq, Q, 1 << SHIFT, (int8_t) s->B) +SSE_HELPER_F(helper_pmovsxwd, L, 2 << SHIFT, (int16_t) s->W) +SSE_HELPER_F(helper_pmovsxwq, Q, 1 << SHIFT, (int16_t) s->W) +SSE_HELPER_F(helper_pmovsxdq, Q, 1 << SHIFT, (int32_t) s->L) +SSE_HELPER_F(helper_pmovzxbw, W, 4 << SHIFT, s->B) +SSE_HELPER_F(helper_pmovzxbd, L, 2 << SHIFT, s->B) +SSE_HELPER_F(helper_pmovzxbq, Q, 1 << SHIFT, s->B) +SSE_HELPER_F(helper_pmovzxwd, L, 2 << SHIFT, s->W) +SSE_HELPER_F(helper_pmovzxwq, Q, 1 << SHIFT, s->W) +SSE_HELPER_F(helper_pmovzxdq, Q, 1 << SHIFT, s->L) +#endif void glue(helper_pmuldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->Q(0) = (int64_t)(int32_t) d->L(0) * (int32_t) s->L(0); - d->Q(1) = (int64_t)(int32_t) d->L(2) * (int32_t) s->L(2); + Reg *v = d; + int i; + + for (i = 0; i < 1 << SHIFT; i++) { + d->Q(i) = (int64_t)(int32_t) v->L(2 * i) * (int32_t) s->L(2 * i); + } } #define FCMPEQQ(d, s) (d == s ? -1 : 0) @@ -1726,17 +1675,23 @@ SSE_HELPER_Q(helper_pcmpeqq, FCMPEQQ) void glue(helper_packusdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - Reg r; + Reg *v = d; + uint16_t r[8]; + int i, j, k; - r.W(0) = satuw((int32_t) d->L(0)); - r.W(1) = satuw((int32_t) d->L(1)); - r.W(2) = satuw((int32_t) d->L(2)); - r.W(3) = satuw((int32_t) d->L(3)); - r.W(4) = satuw((int32_t) s->L(0)); - r.W(5) = satuw((int32_t) s->L(1)); - r.W(6) = satuw((int32_t) s->L(2)); - r.W(7) = satuw((int32_t) s->L(3)); - MOVE(*d, r); + for (i = 0, j = 0; i <= 2 << SHIFT; i += 8, j += 4) { + r[0] = satuw(v->L(j)); + r[1] = satuw(v->L(j + 1)); + r[2] = satuw(v->L(j + 2)); + r[3] = satuw(v->L(j + 3)); + r[4] = satuw(s->L(j)); + r[5] = satuw(s->L(j + 1)); + r[6] = satuw(s->L(j + 2)); + r[7] = satuw(s->L(j + 3)); + for (k = 0; k < 8; k++) { + d->W(i + k) = r[k]; + } + } } #define FMINSB(d, s) MIN((int8_t)d, (int8_t)s) @@ -1755,6 +1710,7 @@ SSE_HELPER_L(helper_pmaxud, MAX) #define FMULLD(d, s) ((int32_t)d * (int32_t)s) SSE_HELPER_L(helper_pmulld, FMULLD) +#if SHIFT == 1 void glue(helper_phminposuw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { int idx = 0; @@ -1786,12 +1742,14 @@ void glue(helper_phminposuw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) d->L(1) = 0; d->Q(1) = 0; } +#endif void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; + int i; prev_rounding_mode = env->sse_status.float_rounding_mode; if (!(mode & (1 << 2))) { @@ -1811,10 +1769,9 @@ void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, } } - d->ZMM_S(0) = float32_round_to_int(s->ZMM_S(0), &env->sse_status); - d->ZMM_S(1) = float32_round_to_int(s->ZMM_S(1), &env->sse_status); - d->ZMM_S(2) = float32_round_to_int(s->ZMM_S(2), &env->sse_status); - d->ZMM_S(3) = float32_round_to_int(s->ZMM_S(3), &env->sse_status); + for (i = 0; i < 2 << SHIFT; i++) { + d->ZMM_S(i) = float32_round_to_int(s->ZMM_S(i), &env->sse_status); + } if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & @@ -1829,6 +1786,7 @@ void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, { uint8_t old_flags = get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; + int i; prev_rounding_mode = env->sse_status.float_rounding_mode; if (!(mode & (1 << 2))) { @@ -1848,8 +1806,9 @@ void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, } } - d->ZMM_D(0) = float64_round_to_int(s->ZMM_D(0), &env->sse_status); - d->ZMM_D(1) = float64_round_to_int(s->ZMM_D(1), &env->sse_status); + for (i = 0; i < 1 << SHIFT; i++) { + d->ZMM_D(i) = float64_round_to_int(s->ZMM_D(i), &env->sse_status); + } if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_status) & @@ -1859,6 +1818,7 @@ void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, env->sse_status.float_rounding_mode = prev_rounding_mode; } +#if SHIFT == 1 void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { @@ -1926,89 +1886,109 @@ void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, } env->sse_status.float_rounding_mode = prev_rounding_mode; } +#endif -#define FBLENDP(d, s, m) (m ? s : d) -SSE_HELPER_I(helper_blendps, L, 4, FBLENDP) -SSE_HELPER_I(helper_blendpd, Q, 2, FBLENDP) -SSE_HELPER_I(helper_pblendw, W, 8, FBLENDP) +#define FBLENDP(v, s, m) (m ? s : v) +SSE_HELPER_I(helper_blendps, L, 2 << SHIFT, FBLENDP) +SSE_HELPER_I(helper_blendpd, Q, 1 << SHIFT, FBLENDP) +SSE_HELPER_I(helper_pblendw, W, 4 << SHIFT, FBLENDP) -void glue(helper_dpps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mask) +void glue(helper_dpps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, + uint32_t mask) { - float32 iresult = float32_zero; + Reg *v = d; + float32 prod1, prod2, temp2, temp3, temp4; + int i; - if (mask & (1 << 4)) { - iresult = float32_add(iresult, - float32_mul(d->ZMM_S(0), s->ZMM_S(0), - &env->sse_status), - &env->sse_status); + for (i = 0; i < 2 << SHIFT; i += 4) { + /* + * We must evaluate (A+B)+(C+D), not ((A+B)+C)+D + * to correctly round the intermediate results + */ + if (mask & (1 << 4)) { + prod1 = float32_mul(v->ZMM_S(i), s->ZMM_S(i), &env->sse_status); + } else { + prod1 = float32_zero; + } + if (mask & (1 << 5)) { + prod2 = float32_mul(v->ZMM_S(i+1), s->ZMM_S(i+1), &env->sse_status); + } else { + prod2 = float32_zero; + } + temp2 = float32_add(prod1, prod2, &env->sse_status); + if (mask & (1 << 6)) { + prod1 = float32_mul(v->ZMM_S(i+2), s->ZMM_S(i+2), &env->sse_status); + } else { + prod1 = float32_zero; + } + if (mask & (1 << 7)) { + prod2 = float32_mul(v->ZMM_S(i+3), s->ZMM_S(i+3), &env->sse_status); + } else { + prod2 = float32_zero; + } + temp3 = float32_add(prod1, prod2, &env->sse_status); + temp4 = float32_add(temp2, temp3, &env->sse_status); + + d->ZMM_S(i) = (mask & (1 << 0)) ? temp4 : float32_zero; + d->ZMM_S(i+1) = (mask & (1 << 1)) ? temp4 : float32_zero; + d->ZMM_S(i+2) = (mask & (1 << 2)) ? temp4 : float32_zero; + d->ZMM_S(i+3) = (mask & (1 << 3)) ? temp4 : float32_zero; } - if (mask & (1 << 5)) { - iresult = float32_add(iresult, - float32_mul(d->ZMM_S(1), s->ZMM_S(1), - &env->sse_status), - &env->sse_status); - } - if (mask & (1 << 6)) { - iresult = float32_add(iresult, - float32_mul(d->ZMM_S(2), s->ZMM_S(2), - &env->sse_status), - &env->sse_status); - } - if (mask & (1 << 7)) { - iresult = float32_add(iresult, - float32_mul(d->ZMM_S(3), s->ZMM_S(3), - &env->sse_status), - &env->sse_status); - } - d->ZMM_S(0) = (mask & (1 << 0)) ? iresult : float32_zero; - d->ZMM_S(1) = (mask & (1 << 1)) ? iresult : float32_zero; - d->ZMM_S(2) = (mask & (1 << 2)) ? iresult : float32_zero; - d->ZMM_S(3) = (mask & (1 << 3)) ? iresult : float32_zero; } -void glue(helper_dppd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mask) +#if SHIFT == 1 +/* Oddly, there is no ymm version of dppd */ +void glue(helper_dppd, SUFFIX)(CPUX86State *env, + Reg *d, Reg *s, uint32_t mask) { - float64 iresult = float64_zero; + Reg *v = d; + float64 prod1, prod2, temp2; if (mask & (1 << 4)) { - iresult = float64_add(iresult, - float64_mul(d->ZMM_D(0), s->ZMM_D(0), - &env->sse_status), - &env->sse_status); + prod1 = float64_mul(v->ZMM_D(0), s->ZMM_D(0), &env->sse_status); + } else { + prod1 = float64_zero; } if (mask & (1 << 5)) { - iresult = float64_add(iresult, - float64_mul(d->ZMM_D(1), s->ZMM_D(1), - &env->sse_status), - &env->sse_status); + prod2 = float64_mul(v->ZMM_D(1), s->ZMM_D(1), &env->sse_status); + } else { + prod2 = float64_zero; } - d->ZMM_D(0) = (mask & (1 << 0)) ? iresult : float64_zero; - d->ZMM_D(1) = (mask & (1 << 1)) ? iresult : float64_zero; + temp2 = float64_add(prod1, prod2, &env->sse_status); + d->ZMM_D(0) = (mask & (1 << 0)) ? temp2 : float64_zero; + d->ZMM_D(1) = (mask & (1 << 1)) ? temp2 : float64_zero; } +#endif void glue(helper_mpsadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t offset) { - int s0 = (offset & 3) << 2; - int d0 = (offset & 4) << 0; - int i; - Reg r; + Reg *v = d; + int i, j; + uint16_t r[8]; - for (i = 0; i < 8; i++, d0++) { - r.W(i) = 0; - r.W(i) += abs1(d->B(d0 + 0) - s->B(s0 + 0)); - r.W(i) += abs1(d->B(d0 + 1) - s->B(s0 + 1)); - r.W(i) += abs1(d->B(d0 + 2) - s->B(s0 + 2)); - r.W(i) += abs1(d->B(d0 + 3) - s->B(s0 + 3)); + for (j = 0; j < 4 << SHIFT; ) { + int s0 = (j * 2) + ((offset & 3) << 2); + int d0 = (j * 2) + ((offset & 4) << 0); + for (i = 0; i < LANE_WIDTH / 2; i++, d0++) { + r[i] = 0; + r[i] += abs1(v->B(d0 + 0) - s->B(s0 + 0)); + r[i] += abs1(v->B(d0 + 1) - s->B(s0 + 1)); + r[i] += abs1(v->B(d0 + 2) - s->B(s0 + 2)); + r[i] += abs1(v->B(d0 + 3) - s->B(s0 + 3)); + } + for (i = 0; i < LANE_WIDTH / 2; i++, j++) { + d->W(j) = r[i]; + } + offset >>= 3; } - - MOVE(*d, r); } /* SSE4.2 op helpers */ #define FCMPGTQ(d, s) ((int64_t)d > (int64_t)s ? -1 : 0) SSE_HELPER_Q(helper_pcmpgtq, FCMPGTQ) +#if SHIFT == 1 static inline int pcmp_elen(CPUX86State *env, int reg, uint32_t ctrl) { target_long val, limit; @@ -2229,14 +2209,16 @@ target_ulong helper_crc32(uint32_t crc1, target_ulong msg, uint32_t len) return crc; } -void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, - uint32_t ctrl) +#endif + +#if SHIFT == 1 +static void clmulq(uint64_t *dest_l, uint64_t *dest_h, + uint64_t a, uint64_t b) { - uint64_t ah, al, b, resh, resl; + uint64_t al, ah, resh, resl; ah = 0; - al = d->Q((ctrl & 1) != 0); - b = s->Q((ctrl & 16) != 0); + al = a; resh = resl = 0; while (b) { @@ -2249,8 +2231,23 @@ void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, b >>= 1; } - d->Q(0) = resl; - d->Q(1) = resh; + *dest_l = resl; + *dest_h = resh; +} +#endif + +void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, + uint32_t ctrl) +{ + Reg *v = d; + uint64_t a, b; + int i; + + for (i = 0; i < 1 << SHIFT; i += 2) { + a = v->Q(((ctrl & 1) != 0) + i); + b = s->Q(((ctrl & 16) != 0) + i); + clmulq(&d->Q(i), &d->Q(i + 1), a, b); + } } void glue(helper_aesdec, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) @@ -2259,11 +2256,12 @@ void glue(helper_aesdec, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) Reg st = *d; Reg rk = *s; - for (i = 0 ; i < 4 ; i++) { - d->L(i) = rk.L(i) ^ bswap32(AES_Td0[st.B(AES_ishifts[4*i+0])] ^ - AES_Td1[st.B(AES_ishifts[4*i+1])] ^ - AES_Td2[st.B(AES_ishifts[4*i+2])] ^ - AES_Td3[st.B(AES_ishifts[4*i+3])]); + for (i = 0 ; i < 2 << SHIFT ; i++) { + int j = i & 3; + d->L(i) = rk.L(i) ^ bswap32(AES_Td0[st.B(AES_ishifts[4 * j + 0])] ^ + AES_Td1[st.B(AES_ishifts[4 * j + 1])] ^ + AES_Td2[st.B(AES_ishifts[4 * j + 2])] ^ + AES_Td3[st.B(AES_ishifts[4 * j + 3])]); } } @@ -2273,8 +2271,8 @@ void glue(helper_aesdeclast, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) Reg st = *d; Reg rk = *s; - for (i = 0; i < 16; i++) { - d->B(i) = rk.B(i) ^ (AES_isbox[st.B(AES_ishifts[i])]); + for (i = 0; i < 8 << SHIFT; i++) { + d->B(i) = rk.B(i) ^ (AES_isbox[st.B(AES_ishifts[i & 15] + (i & ~15))]); } } @@ -2284,11 +2282,12 @@ void glue(helper_aesenc, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) Reg st = *d; Reg rk = *s; - for (i = 0 ; i < 4 ; i++) { - d->L(i) = rk.L(i) ^ bswap32(AES_Te0[st.B(AES_shifts[4*i+0])] ^ - AES_Te1[st.B(AES_shifts[4*i+1])] ^ - AES_Te2[st.B(AES_shifts[4*i+2])] ^ - AES_Te3[st.B(AES_shifts[4*i+3])]); + for (i = 0 ; i < 2 << SHIFT ; i++) { + int j = i & 3; + d->L(i) = rk.L(i) ^ bswap32(AES_Te0[st.B(AES_shifts[4 * j + 0])] ^ + AES_Te1[st.B(AES_shifts[4 * j + 1])] ^ + AES_Te2[st.B(AES_shifts[4 * j + 2])] ^ + AES_Te3[st.B(AES_shifts[4 * j + 3])]); } } @@ -2298,22 +2297,22 @@ void glue(helper_aesenclast, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) Reg st = *d; Reg rk = *s; - for (i = 0; i < 16; i++) { - d->B(i) = rk.B(i) ^ (AES_sbox[st.B(AES_shifts[i])]); + for (i = 0; i < 8 << SHIFT; i++) { + d->B(i) = rk.B(i) ^ (AES_sbox[st.B(AES_shifts[i & 15] + (i & ~15))]); } - } +#if SHIFT == 1 void glue(helper_aesimc, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { int i; Reg tmp = *s; for (i = 0 ; i < 4 ; i++) { - d->L(i) = bswap32(AES_imc[tmp.B(4*i+0)][0] ^ - AES_imc[tmp.B(4*i+1)][1] ^ - AES_imc[tmp.B(4*i+2)][2] ^ - AES_imc[tmp.B(4*i+3)][3]); + d->L(i) = bswap32(AES_imc[tmp.B(4 * i + 0)][0] ^ + AES_imc[tmp.B(4 * i + 1)][1] ^ + AES_imc[tmp.B(4 * i + 2)][2] ^ + AES_imc[tmp.B(4 * i + 3)][3]); } } @@ -2331,6 +2330,9 @@ void glue(helper_aeskeygenassist, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, d->L(3) = (d->L(2) << 24 | d->L(2) >> 8) ^ ctrl; } #endif +#endif + +#undef SSE_HELPER_S #undef SHIFT #undef XMM_ONLY @@ -2340,4 +2342,3 @@ void glue(helper_aeskeygenassist, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, #undef L #undef Q #undef SUFFIX -#undef SIZE diff --git a/target/i386/ops_sse_header.h b/target/i386/ops_sse_header.h index cef28f2aae..400b24c091 100644 --- a/target/i386/ops_sse_header.h +++ b/target/i386/ops_sse_header.h @@ -122,8 +122,8 @@ DEF_HELPER_2(glue(movq_mm_T0, SUFFIX), void, Reg, i64) #if SHIFT == 0 DEF_HELPER_3(glue(pshufw, SUFFIX), void, Reg, Reg, int) #else -DEF_HELPER_3(shufps, void, Reg, Reg, int) -DEF_HELPER_3(shufpd, void, Reg, Reg, int) +DEF_HELPER_3(glue(shufps, SUFFIX), void, Reg, Reg, int) +DEF_HELPER_3(glue(shufpd, SUFFIX), void, Reg, Reg, int) DEF_HELPER_3(glue(pshufd, SUFFIX), void, Reg, Reg, int) DEF_HELPER_3(glue(pshuflw, SUFFIX), void, Reg, Reg, int) DEF_HELPER_3(glue(pshufhw, SUFFIX), void, Reg, Reg, int) @@ -134,9 +134,9 @@ DEF_HELPER_3(glue(pshufhw, SUFFIX), void, Reg, Reg, int) /* XXX: not accurate */ #define SSE_HELPER_S(name, F) \ - DEF_HELPER_3(name ## ps, void, env, Reg, Reg) \ + DEF_HELPER_3(glue(name ## ps, SUFFIX), void, env, Reg, Reg) \ DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \ - DEF_HELPER_3(name ## pd, void, env, Reg, Reg) \ + DEF_HELPER_3(glue(name ## pd, SUFFIX), void, env, Reg, Reg) \ DEF_HELPER_3(name ## sd, void, env, Reg, Reg) SSE_HELPER_S(add, FPU_ADD) @@ -148,12 +148,12 @@ SSE_HELPER_S(max, FPU_MAX) SSE_HELPER_S(sqrt, FPU_SQRT) -DEF_HELPER_3(cvtps2pd, void, env, Reg, Reg) -DEF_HELPER_3(cvtpd2ps, void, env, Reg, Reg) +DEF_HELPER_3(glue(cvtps2pd, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_3(glue(cvtpd2ps, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(cvtss2sd, void, env, Reg, Reg) DEF_HELPER_3(cvtsd2ss, void, env, Reg, Reg) -DEF_HELPER_3(cvtdq2ps, void, env, Reg, Reg) -DEF_HELPER_3(cvtdq2pd, void, env, Reg, Reg) +DEF_HELPER_3(glue(cvtdq2ps, SUFFIX), void, env, Reg, Reg) +DEF_HELPER_3(glue(cvtdq2pd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(cvtpi2ps, void, env, ZMMReg, MMXReg) DEF_HELPER_3(cvtpi2pd, void, env, ZMMReg, MMXReg) DEF_HELPER_3(cvtsi2ss, void, env, ZMMReg, i32) @@ -164,8 +164,8 @@ DEF_HELPER_3(cvtsq2ss, void, env, ZMMReg, i64) DEF_HELPER_3(cvtsq2sd, void, env, ZMMReg, i64) #endif -DEF_HELPER_3(cvtps2dq, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(cvtpd2dq, void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(cvtps2dq, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(cvtpd2dq, SUFFIX), void, env, ZMMReg, ZMMReg) DEF_HELPER_3(cvtps2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_3(cvtpd2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_2(cvtss2si, s32, env, ZMMReg) @@ -175,8 +175,8 @@ DEF_HELPER_2(cvtss2sq, s64, env, ZMMReg) DEF_HELPER_2(cvtsd2sq, s64, env, ZMMReg) #endif -DEF_HELPER_3(cvttps2dq, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(cvttpd2dq, void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(cvttps2dq, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(cvttpd2dq, SUFFIX), void, env, ZMMReg, ZMMReg) DEF_HELPER_3(cvttps2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_3(cvttpd2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_2(cvttss2si, s32, env, ZMMReg) @@ -186,42 +186,42 @@ DEF_HELPER_2(cvttss2sq, s64, env, ZMMReg) DEF_HELPER_2(cvttsd2sq, s64, env, ZMMReg) #endif -DEF_HELPER_3(rsqrtps, void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(rsqrtps, SUFFIX), void, env, ZMMReg, ZMMReg) DEF_HELPER_3(rsqrtss, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(rcpps, void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(rcpps, SUFFIX), void, env, ZMMReg, ZMMReg) DEF_HELPER_3(rcpss, void, env, ZMMReg, ZMMReg) DEF_HELPER_3(extrq_r, void, env, ZMMReg, ZMMReg) DEF_HELPER_4(extrq_i, void, env, ZMMReg, int, int) DEF_HELPER_3(insertq_r, void, env, ZMMReg, ZMMReg) -DEF_HELPER_4(insertq_i, void, env, ZMMReg, int, int) -DEF_HELPER_3(haddps, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(haddpd, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(hsubps, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(hsubpd, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(addsubps, void, env, ZMMReg, ZMMReg) -DEF_HELPER_3(addsubpd, void, env, ZMMReg, ZMMReg) +DEF_HELPER_5(insertq_i, void, env, ZMMReg, ZMMReg, int, int) +DEF_HELPER_3(glue(haddps, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(haddpd, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(hsubps, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(hsubpd, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(addsubps, SUFFIX), void, env, ZMMReg, ZMMReg) +DEF_HELPER_3(glue(addsubpd, SUFFIX), void, env, ZMMReg, ZMMReg) -#define SSE_HELPER_CMP(name, F) \ - DEF_HELPER_3(name ## ps, void, env, Reg, Reg) \ - DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \ - DEF_HELPER_3(name ## pd, void, env, Reg, Reg) \ +#define SSE_HELPER_CMP(name, F, C) \ + DEF_HELPER_3(glue(name ## ps, SUFFIX), void, env, Reg, Reg) \ + DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \ + DEF_HELPER_3(glue(name ## pd, SUFFIX), void, env, Reg, Reg) \ DEF_HELPER_3(name ## sd, void, env, Reg, Reg) -SSE_HELPER_CMP(cmpeq, FPU_CMPEQ) -SSE_HELPER_CMP(cmplt, FPU_CMPLT) -SSE_HELPER_CMP(cmple, FPU_CMPLE) -SSE_HELPER_CMP(cmpunord, FPU_CMPUNORD) -SSE_HELPER_CMP(cmpneq, FPU_CMPNEQ) -SSE_HELPER_CMP(cmpnlt, FPU_CMPNLT) -SSE_HELPER_CMP(cmpnle, FPU_CMPNLE) -SSE_HELPER_CMP(cmpord, FPU_CMPORD) +SSE_HELPER_CMP(cmpeq, FPU_CMPQ, FPU_EQ) +SSE_HELPER_CMP(cmplt, FPU_CMPS, FPU_LT) +SSE_HELPER_CMP(cmple, FPU_CMPS, FPU_LE) +SSE_HELPER_CMP(cmpunord, FPU_CMPQ, FPU_UNORD) +SSE_HELPER_CMP(cmpneq, FPU_CMPQ, !FPU_EQ) +SSE_HELPER_CMP(cmpnlt, FPU_CMPS, !FPU_LT) +SSE_HELPER_CMP(cmpnle, FPU_CMPS, !FPU_LE) +SSE_HELPER_CMP(cmpord, FPU_CMPQ, !FPU_UNORD) DEF_HELPER_3(ucomiss, void, env, Reg, Reg) DEF_HELPER_3(comiss, void, env, Reg, Reg) DEF_HELPER_3(ucomisd, void, env, Reg, Reg) DEF_HELPER_3(comisd, void, env, Reg, Reg) -DEF_HELPER_2(movmskps, i32, env, Reg) -DEF_HELPER_2(movmskpd, i32, env, Reg) +DEF_HELPER_2(glue(movmskps, SUFFIX), i32, env, Reg) +DEF_HELPER_2(glue(movmskpd, SUFFIX), i32, env, Reg) #endif DEF_HELPER_2(glue(pmovmskb, SUFFIX), i32, env, Reg) diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c index c1ffa1c0ef..7c3c8dc7fe 100644 --- a/target/i386/tcg/excp_helper.c +++ b/target/i386/tcg/excp_helper.c @@ -140,3 +140,16 @@ G_NORETURN void raise_exception_ra(CPUX86State *env, int exception_index, { raise_interrupt2(env, exception_index, 0, 0, 0, retaddr); } + +G_NORETURN void handle_unaligned_access(CPUX86State *env, vaddr vaddr, + MMUAccessType access_type, + uintptr_t retaddr) +{ + /* + * Unaligned accesses are currently only triggered by SSE/AVX + * instructions that impose alignment requirements on memory + * operands. These instructions raise #GP(0) upon accessing an + * unaligned address. + */ + raise_exception_ra(env, EXCP0D_GPF, retaddr); +} diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index 34167e2e29..cd1723389a 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -42,17 +42,6 @@ void x86_cpu_do_interrupt(CPUState *cpu); bool x86_cpu_exec_interrupt(CPUState *cpu, int int_req); #endif -/* helper.c */ -#ifdef CONFIG_USER_ONLY -void x86_cpu_record_sigsegv(CPUState *cs, vaddr addr, - MMUAccessType access_type, - bool maperr, uintptr_t ra); -#else -bool x86_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); -#endif - void breakpoint_handler(CPUState *cs); /* n must be a constant to be efficient */ @@ -78,6 +67,23 @@ G_NORETURN void raise_exception_err_ra(CPUX86State *env, int exception_index, int error_code, uintptr_t retaddr); G_NORETURN void raise_interrupt(CPUX86State *nenv, int intno, int is_int, int error_code, int next_eip_addend); +G_NORETURN void handle_unaligned_access(CPUX86State *env, vaddr vaddr, + MMUAccessType access_type, + uintptr_t retaddr); +#ifdef CONFIG_USER_ONLY +void x86_cpu_record_sigsegv(CPUState *cs, vaddr addr, + MMUAccessType access_type, + bool maperr, uintptr_t ra); +void x86_cpu_record_sigbus(CPUState *cs, vaddr addr, + MMUAccessType access_type, uintptr_t ra); +#else +bool x86_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); +G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); +#endif /* cc_helper.c */ extern const uint8_t parity_table[256]; diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 48feba7e75..796dc2a1f3 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -439,3 +439,11 @@ bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, } return true; } + +G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) +{ + X86CPU *cpu = X86_CPU(cs); + handle_unaligned_access(&cpu->env, vaddr, access_type, retaddr); +} diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 6fdfdf9598..6cf14c83ff 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -51,7 +51,7 @@ static void x86_cpu_synchronize_from_tb(CPUState *cs, { X86CPU *cpu = X86_CPU(cs); - cpu->env.eip = tb->pc - tb->cs_base; + cpu->env.eip = tb_pc(tb) - tb->cs_base; } #ifndef CONFIG_USER_ONLY @@ -75,10 +75,12 @@ static const struct TCGCPUOps x86_tcg_ops = { #ifdef CONFIG_USER_ONLY .fake_user_interrupt = x86_cpu_do_interrupt, .record_sigsegv = x86_cpu_record_sigsegv, + .record_sigbus = x86_cpu_record_sigbus, #else .tlb_fill = x86_cpu_tlb_fill, .do_interrupt = x86_cpu_do_interrupt, .cpu_exec_interrupt = x86_cpu_exec_interrupt, + .do_unaligned_access = x86_cpu_do_unaligned_access, .debug_excp_handler = breakpoint_handler, .debug_check_breakpoint = x86_debug_check_breakpoint, #endif /* !CONFIG_USER_ONLY */ diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index e74c4eabb1..987f3e64dd 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -136,6 +136,7 @@ typedef struct DisasContext { TCGv_i64 tmp1_i64; sigjmp_buf jmpbuf; + TCGOp *prev_insn_end; } DisasContext; /* The environment in which user-only runs is constrained. */ @@ -2028,6 +2029,12 @@ static uint64_t advance_pc(CPUX86State *env, DisasContext *s, int num_bytes) { uint64_t pc = s->pc; + /* This is a subsequent insn that crosses a page boundary. */ + if (s->base.num_insns > 1 && + !is_same_page(&s->base, s->pc + num_bytes - 1)) { + siglongjmp(s->jmpbuf, 2); + } + s->pc += num_bytes; if (unlikely(s->pc - s->pc_start > X86_MAX_INSN_LENGTH)) { /* If the instruction's 16th byte is on a different page than the 1st, a @@ -2053,7 +2060,7 @@ static inline uint8_t x86_ldub_code(CPUX86State *env, DisasContext *s) static inline int16_t x86_ldsw_code(CPUX86State *env, DisasContext *s) { - return translator_ldsw(env, &s->base, advance_pc(env, s, 2)); + return translator_lduw(env, &s->base, advance_pc(env, s, 2)); } static inline uint16_t x86_lduw_code(CPUX86State *env, DisasContext *s) @@ -2302,6 +2309,31 @@ static void gen_ldst_modrm(CPUX86State *env, DisasContext *s, int modrm, } } +static target_ulong insn_get_addr(CPUX86State *env, DisasContext *s, MemOp ot) +{ + target_ulong ret; + + switch (ot) { + case MO_8: + ret = x86_ldub_code(env, s); + break; + case MO_16: + ret = x86_lduw_code(env, s); + break; + case MO_32: + ret = x86_ldl_code(env, s); + break; +#ifdef TARGET_X86_64 + case MO_64: + ret = x86_ldq_code(env, s); + break; +#endif + default: + g_assert_not_reached(); + } + return ret; +} + static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, MemOp ot) { uint32_t ret; @@ -2751,21 +2783,23 @@ static inline void gen_stq_env_A0(DisasContext *s, int offset) tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ); } -static inline void gen_ldo_env_A0(DisasContext *s, int offset) +static inline void gen_ldo_env_A0(DisasContext *s, int offset, bool align) { int mem_index = s->mem_index; - tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ); + tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, + MO_LEUQ | (align ? MO_ALIGN_16 : 0)); tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(0))); tcg_gen_addi_tl(s->tmp0, s->A0, 8); tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(1))); } -static inline void gen_sto_env_A0(DisasContext *s, int offset) +static inline void gen_sto_env_A0(DisasContext *s, int offset, bool align) { int mem_index = s->mem_index; tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(0))); - tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, MO_LEUQ); + tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, + MO_LEUQ | (align ? MO_ALIGN_16 : 0)); tcg_gen_addi_tl(s->tmp0, s->A0, 8); tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(1))); tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEUQ); @@ -2797,157 +2831,209 @@ static inline void gen_op_movq_env_0(DisasContext *s, int d_offset) tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset); } +#define ZMM_OFFSET(reg) offsetof(CPUX86State, xmm_regs[reg]) + typedef void (*SSEFunc_i_ep)(TCGv_i32 val, TCGv_ptr env, TCGv_ptr reg); typedef void (*SSEFunc_l_ep)(TCGv_i64 val, TCGv_ptr env, TCGv_ptr reg); typedef void (*SSEFunc_0_epi)(TCGv_ptr env, TCGv_ptr reg, TCGv_i32 val); typedef void (*SSEFunc_0_epl)(TCGv_ptr env, TCGv_ptr reg, TCGv_i64 val); typedef void (*SSEFunc_0_epp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b); +typedef void (*SSEFunc_0_eppp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, + TCGv_ptr reg_c); typedef void (*SSEFunc_0_eppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv val); -#define SSE_SPECIAL ((void *)1) -#define SSE_DUMMY ((void *)2) +#define SSE_OPF_CMP (1 << 1) /* does not write for first operand */ +#define SSE_OPF_SPECIAL (1 << 3) /* magic */ +#define SSE_OPF_3DNOW (1 << 4) /* 3DNow! instruction */ +#define SSE_OPF_MMX (1 << 5) /* MMX/integer/AVX2 instruction */ +#define SSE_OPF_SCALAR (1 << 6) /* Has SSE scalar variants */ +#define SSE_OPF_SHUF (1 << 9) /* pshufx/shufpx */ -#define MMX_OP2(x) { gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm } -#define SSE_FOP(x) { gen_helper_ ## x ## ps, gen_helper_ ## x ## pd, \ - gen_helper_ ## x ## ss, gen_helper_ ## x ## sd, } +#define OP(op, flags, a, b, c, d) \ + {flags, {{.op = a}, {.op = b}, {.op = c}, {.op = d} } } -static const SSEFunc_0_epp sse_op_table1[256][4] = { +#define MMX_OP(x) OP(op1, SSE_OPF_MMX, \ + gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm, NULL, NULL) + +#define SSE_FOP(name) OP(op1, SSE_OPF_SCALAR, \ + gen_helper_##name##ps##_xmm, gen_helper_##name##pd##_xmm, \ + gen_helper_##name##ss, gen_helper_##name##sd) +#define SSE_OP(sname, dname, op, flags) OP(op, flags, \ + gen_helper_##sname##_xmm, gen_helper_##dname##_xmm, NULL, NULL) + +typedef union SSEFuncs { + SSEFunc_0_epp op1; + SSEFunc_0_ppi op1i; + SSEFunc_0_eppt op1t; +} SSEFuncs; + +struct SSEOpHelper_table1 { + int flags; + SSEFuncs fn[4]; +}; + +#define SSE_3DNOW { SSE_OPF_3DNOW } +#define SSE_SPECIAL { SSE_OPF_SPECIAL } + +static const struct SSEOpHelper_table1 sse_op_table1[256] = { /* 3DNow! extensions */ - [0x0e] = { SSE_DUMMY }, /* femms */ - [0x0f] = { SSE_DUMMY }, /* pf... */ + [0x0e] = SSE_SPECIAL, /* femms */ + [0x0f] = SSE_3DNOW, /* pf... (sse_op_table5) */ /* pure SSE operations */ - [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ - [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ - [0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd, movsldup, movddup */ - [0x13] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */ - [0x14] = { gen_helper_punpckldq_xmm, gen_helper_punpcklqdq_xmm }, - [0x15] = { gen_helper_punpckhdq_xmm, gen_helper_punpckhqdq_xmm }, - [0x16] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd, movshdup */ - [0x17] = { SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd */ + [0x10] = SSE_SPECIAL, /* movups, movupd, movss, movsd */ + [0x11] = SSE_SPECIAL, /* movups, movupd, movss, movsd */ + [0x12] = SSE_SPECIAL, /* movlps, movlpd, movsldup, movddup */ + [0x13] = SSE_SPECIAL, /* movlps, movlpd */ + [0x14] = SSE_OP(punpckldq, punpcklqdq, op1, 0), /* unpcklps, unpcklpd */ + [0x15] = SSE_OP(punpckhdq, punpckhqdq, op1, 0), /* unpckhps, unpckhpd */ + [0x16] = SSE_SPECIAL, /* movhps, movhpd, movshdup */ + [0x17] = SSE_SPECIAL, /* movhps, movhpd */ - [0x28] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */ - [0x29] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */ - [0x2a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtpi2ps, cvtpi2pd, cvtsi2ss, cvtsi2sd */ - [0x2b] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movntps, movntpd, movntss, movntsd */ - [0x2c] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */ - [0x2d] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */ - [0x2e] = { gen_helper_ucomiss, gen_helper_ucomisd }, - [0x2f] = { gen_helper_comiss, gen_helper_comisd }, - [0x50] = { SSE_SPECIAL, SSE_SPECIAL }, /* movmskps, movmskpd */ - [0x51] = SSE_FOP(sqrt), - [0x52] = { gen_helper_rsqrtps, NULL, gen_helper_rsqrtss, NULL }, - [0x53] = { gen_helper_rcpps, NULL, gen_helper_rcpss, NULL }, - [0x54] = { gen_helper_pand_xmm, gen_helper_pand_xmm }, /* andps, andpd */ - [0x55] = { gen_helper_pandn_xmm, gen_helper_pandn_xmm }, /* andnps, andnpd */ - [0x56] = { gen_helper_por_xmm, gen_helper_por_xmm }, /* orps, orpd */ - [0x57] = { gen_helper_pxor_xmm, gen_helper_pxor_xmm }, /* xorps, xorpd */ + [0x28] = SSE_SPECIAL, /* movaps, movapd */ + [0x29] = SSE_SPECIAL, /* movaps, movapd */ + [0x2a] = SSE_SPECIAL, /* cvtpi2ps, cvtpi2pd, cvtsi2ss, cvtsi2sd */ + [0x2b] = SSE_SPECIAL, /* movntps, movntpd, movntss, movntsd */ + [0x2c] = SSE_SPECIAL, /* cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */ + [0x2d] = SSE_SPECIAL, /* cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */ + [0x2e] = OP(op1, SSE_OPF_CMP | SSE_OPF_SCALAR, + gen_helper_ucomiss, gen_helper_ucomisd, NULL, NULL), + [0x2f] = OP(op1, SSE_OPF_CMP | SSE_OPF_SCALAR, + gen_helper_comiss, gen_helper_comisd, NULL, NULL), + [0x50] = SSE_SPECIAL, /* movmskps, movmskpd */ + [0x51] = OP(op1, SSE_OPF_SCALAR, + gen_helper_sqrtps_xmm, gen_helper_sqrtpd_xmm, + gen_helper_sqrtss, gen_helper_sqrtsd), + [0x52] = OP(op1, SSE_OPF_SCALAR, + gen_helper_rsqrtps_xmm, NULL, gen_helper_rsqrtss, NULL), + [0x53] = OP(op1, SSE_OPF_SCALAR, + gen_helper_rcpps_xmm, NULL, gen_helper_rcpss, NULL), + [0x54] = SSE_OP(pand, pand, op1, 0), /* andps, andpd */ + [0x55] = SSE_OP(pandn, pandn, op1, 0), /* andnps, andnpd */ + [0x56] = SSE_OP(por, por, op1, 0), /* orps, orpd */ + [0x57] = SSE_OP(pxor, pxor, op1, 0), /* xorps, xorpd */ [0x58] = SSE_FOP(add), [0x59] = SSE_FOP(mul), - [0x5a] = { gen_helper_cvtps2pd, gen_helper_cvtpd2ps, - gen_helper_cvtss2sd, gen_helper_cvtsd2ss }, - [0x5b] = { gen_helper_cvtdq2ps, gen_helper_cvtps2dq, gen_helper_cvttps2dq }, + [0x5a] = OP(op1, SSE_OPF_SCALAR, + gen_helper_cvtps2pd_xmm, gen_helper_cvtpd2ps_xmm, + gen_helper_cvtss2sd, gen_helper_cvtsd2ss), + [0x5b] = OP(op1, 0, + gen_helper_cvtdq2ps_xmm, gen_helper_cvtps2dq_xmm, + gen_helper_cvttps2dq_xmm, NULL), [0x5c] = SSE_FOP(sub), [0x5d] = SSE_FOP(min), [0x5e] = SSE_FOP(div), [0x5f] = SSE_FOP(max), - [0xc2] = SSE_FOP(cmpeq), - [0xc6] = { (SSEFunc_0_epp)gen_helper_shufps, - (SSEFunc_0_epp)gen_helper_shufpd }, /* XXX: casts */ + [0xc2] = SSE_FOP(cmpeq), /* sse_op_table4 */ + [0xc6] = SSE_OP(shufps, shufpd, op1i, SSE_OPF_SHUF), /* SSSE3, SSE4, MOVBE, CRC32, BMI1, BMI2, ADX. */ - [0x38] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, - [0x3a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, + [0x38] = SSE_SPECIAL, + [0x3a] = SSE_SPECIAL, /* MMX ops and their SSE extensions */ - [0x60] = MMX_OP2(punpcklbw), - [0x61] = MMX_OP2(punpcklwd), - [0x62] = MMX_OP2(punpckldq), - [0x63] = MMX_OP2(packsswb), - [0x64] = MMX_OP2(pcmpgtb), - [0x65] = MMX_OP2(pcmpgtw), - [0x66] = MMX_OP2(pcmpgtl), - [0x67] = MMX_OP2(packuswb), - [0x68] = MMX_OP2(punpckhbw), - [0x69] = MMX_OP2(punpckhwd), - [0x6a] = MMX_OP2(punpckhdq), - [0x6b] = MMX_OP2(packssdw), - [0x6c] = { NULL, gen_helper_punpcklqdq_xmm }, - [0x6d] = { NULL, gen_helper_punpckhqdq_xmm }, - [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */ - [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */ - [0x70] = { (SSEFunc_0_epp)gen_helper_pshufw_mmx, - (SSEFunc_0_epp)gen_helper_pshufd_xmm, - (SSEFunc_0_epp)gen_helper_pshufhw_xmm, - (SSEFunc_0_epp)gen_helper_pshuflw_xmm }, /* XXX: casts */ - [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */ - [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */ - [0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */ - [0x74] = MMX_OP2(pcmpeqb), - [0x75] = MMX_OP2(pcmpeqw), - [0x76] = MMX_OP2(pcmpeql), - [0x77] = { SSE_DUMMY }, /* emms */ - [0x78] = { NULL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* extrq_i, insertq_i */ - [0x79] = { NULL, gen_helper_extrq_r, NULL, gen_helper_insertq_r }, - [0x7c] = { NULL, gen_helper_haddpd, NULL, gen_helper_haddps }, - [0x7d] = { NULL, gen_helper_hsubpd, NULL, gen_helper_hsubps }, - [0x7e] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movd, movd, , movq */ - [0x7f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, movdqu */ - [0xc4] = { SSE_SPECIAL, SSE_SPECIAL }, /* pinsrw */ - [0xc5] = { SSE_SPECIAL, SSE_SPECIAL }, /* pextrw */ - [0xd0] = { NULL, gen_helper_addsubpd, NULL, gen_helper_addsubps }, - [0xd1] = MMX_OP2(psrlw), - [0xd2] = MMX_OP2(psrld), - [0xd3] = MMX_OP2(psrlq), - [0xd4] = MMX_OP2(paddq), - [0xd5] = MMX_OP2(pmullw), - [0xd6] = { NULL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, - [0xd7] = { SSE_SPECIAL, SSE_SPECIAL }, /* pmovmskb */ - [0xd8] = MMX_OP2(psubusb), - [0xd9] = MMX_OP2(psubusw), - [0xda] = MMX_OP2(pminub), - [0xdb] = MMX_OP2(pand), - [0xdc] = MMX_OP2(paddusb), - [0xdd] = MMX_OP2(paddusw), - [0xde] = MMX_OP2(pmaxub), - [0xdf] = MMX_OP2(pandn), - [0xe0] = MMX_OP2(pavgb), - [0xe1] = MMX_OP2(psraw), - [0xe2] = MMX_OP2(psrad), - [0xe3] = MMX_OP2(pavgw), - [0xe4] = MMX_OP2(pmulhuw), - [0xe5] = MMX_OP2(pmulhw), - [0xe6] = { NULL, gen_helper_cvttpd2dq, gen_helper_cvtdq2pd, gen_helper_cvtpd2dq }, - [0xe7] = { SSE_SPECIAL , SSE_SPECIAL }, /* movntq, movntq */ - [0xe8] = MMX_OP2(psubsb), - [0xe9] = MMX_OP2(psubsw), - [0xea] = MMX_OP2(pminsw), - [0xeb] = MMX_OP2(por), - [0xec] = MMX_OP2(paddsb), - [0xed] = MMX_OP2(paddsw), - [0xee] = MMX_OP2(pmaxsw), - [0xef] = MMX_OP2(pxor), - [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu */ - [0xf1] = MMX_OP2(psllw), - [0xf2] = MMX_OP2(pslld), - [0xf3] = MMX_OP2(psllq), - [0xf4] = MMX_OP2(pmuludq), - [0xf5] = MMX_OP2(pmaddwd), - [0xf6] = MMX_OP2(psadbw), - [0xf7] = { (SSEFunc_0_epp)gen_helper_maskmov_mmx, - (SSEFunc_0_epp)gen_helper_maskmov_xmm }, /* XXX: casts */ - [0xf8] = MMX_OP2(psubb), - [0xf9] = MMX_OP2(psubw), - [0xfa] = MMX_OP2(psubl), - [0xfb] = MMX_OP2(psubq), - [0xfc] = MMX_OP2(paddb), - [0xfd] = MMX_OP2(paddw), - [0xfe] = MMX_OP2(paddl), + [0x60] = MMX_OP(punpcklbw), + [0x61] = MMX_OP(punpcklwd), + [0x62] = MMX_OP(punpckldq), + [0x63] = MMX_OP(packsswb), + [0x64] = MMX_OP(pcmpgtb), + [0x65] = MMX_OP(pcmpgtw), + [0x66] = MMX_OP(pcmpgtl), + [0x67] = MMX_OP(packuswb), + [0x68] = MMX_OP(punpckhbw), + [0x69] = MMX_OP(punpckhwd), + [0x6a] = MMX_OP(punpckhdq), + [0x6b] = MMX_OP(packssdw), + [0x6c] = OP(op1, SSE_OPF_MMX, + NULL, gen_helper_punpcklqdq_xmm, NULL, NULL), + [0x6d] = OP(op1, SSE_OPF_MMX, + NULL, gen_helper_punpckhqdq_xmm, NULL, NULL), + [0x6e] = SSE_SPECIAL, /* movd mm, ea */ + [0x6f] = SSE_SPECIAL, /* movq, movdqa, , movqdu */ + [0x70] = OP(op1i, SSE_OPF_SHUF | SSE_OPF_MMX, + gen_helper_pshufw_mmx, gen_helper_pshufd_xmm, + gen_helper_pshufhw_xmm, gen_helper_pshuflw_xmm), + [0x71] = SSE_SPECIAL, /* shiftw */ + [0x72] = SSE_SPECIAL, /* shiftd */ + [0x73] = SSE_SPECIAL, /* shiftq */ + [0x74] = MMX_OP(pcmpeqb), + [0x75] = MMX_OP(pcmpeqw), + [0x76] = MMX_OP(pcmpeql), + [0x77] = SSE_SPECIAL, /* emms */ + [0x78] = SSE_SPECIAL, /* extrq_i, insertq_i (sse4a) */ + [0x79] = OP(op1, 0, + NULL, gen_helper_extrq_r, NULL, gen_helper_insertq_r), + [0x7c] = OP(op1, 0, + NULL, gen_helper_haddpd_xmm, NULL, gen_helper_haddps_xmm), + [0x7d] = OP(op1, 0, + NULL, gen_helper_hsubpd_xmm, NULL, gen_helper_hsubps_xmm), + [0x7e] = SSE_SPECIAL, /* movd, movd, , movq */ + [0x7f] = SSE_SPECIAL, /* movq, movdqa, movdqu */ + [0xc4] = SSE_SPECIAL, /* pinsrw */ + [0xc5] = SSE_SPECIAL, /* pextrw */ + [0xd0] = OP(op1, 0, + NULL, gen_helper_addsubpd_xmm, NULL, gen_helper_addsubps_xmm), + [0xd1] = MMX_OP(psrlw), + [0xd2] = MMX_OP(psrld), + [0xd3] = MMX_OP(psrlq), + [0xd4] = MMX_OP(paddq), + [0xd5] = MMX_OP(pmullw), + [0xd6] = SSE_SPECIAL, + [0xd7] = SSE_SPECIAL, /* pmovmskb */ + [0xd8] = MMX_OP(psubusb), + [0xd9] = MMX_OP(psubusw), + [0xda] = MMX_OP(pminub), + [0xdb] = MMX_OP(pand), + [0xdc] = MMX_OP(paddusb), + [0xdd] = MMX_OP(paddusw), + [0xde] = MMX_OP(pmaxub), + [0xdf] = MMX_OP(pandn), + [0xe0] = MMX_OP(pavgb), + [0xe1] = MMX_OP(psraw), + [0xe2] = MMX_OP(psrad), + [0xe3] = MMX_OP(pavgw), + [0xe4] = MMX_OP(pmulhuw), + [0xe5] = MMX_OP(pmulhw), + [0xe6] = OP(op1, 0, + NULL, gen_helper_cvttpd2dq_xmm, + gen_helper_cvtdq2pd_xmm, gen_helper_cvtpd2dq_xmm), + [0xe7] = SSE_SPECIAL, /* movntq, movntq */ + [0xe8] = MMX_OP(psubsb), + [0xe9] = MMX_OP(psubsw), + [0xea] = MMX_OP(pminsw), + [0xeb] = MMX_OP(por), + [0xec] = MMX_OP(paddsb), + [0xed] = MMX_OP(paddsw), + [0xee] = MMX_OP(pmaxsw), + [0xef] = MMX_OP(pxor), + [0xf0] = SSE_SPECIAL, /* lddqu */ + [0xf1] = MMX_OP(psllw), + [0xf2] = MMX_OP(pslld), + [0xf3] = MMX_OP(psllq), + [0xf4] = MMX_OP(pmuludq), + [0xf5] = MMX_OP(pmaddwd), + [0xf6] = MMX_OP(psadbw), + [0xf7] = OP(op1t, SSE_OPF_MMX, + gen_helper_maskmov_mmx, gen_helper_maskmov_xmm, NULL, NULL), + [0xf8] = MMX_OP(psubb), + [0xf9] = MMX_OP(psubw), + [0xfa] = MMX_OP(psubl), + [0xfb] = MMX_OP(psubq), + [0xfc] = MMX_OP(paddb), + [0xfd] = MMX_OP(paddw), + [0xfe] = MMX_OP(paddl), }; +#undef MMX_OP +#undef OP +#undef SSE_FOP +#undef SSE_OP +#undef SSE_SPECIAL + +#define MMX_OP2(x) { gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm } static const SSEFunc_0_epp sse_op_table2[3 * 8][2] = { [0 + 2] = MMX_OP2(psrlw), @@ -2990,16 +3076,20 @@ static const SSEFunc_l_ep sse_op_table3bq[] = { }; #endif +#define SSE_CMP(x) { \ + gen_helper_ ## x ## ps ## _xmm, gen_helper_ ## x ## pd ## _xmm, \ + gen_helper_ ## x ## ss, gen_helper_ ## x ## sd} static const SSEFunc_0_epp sse_op_table4[8][4] = { - SSE_FOP(cmpeq), - SSE_FOP(cmplt), - SSE_FOP(cmple), - SSE_FOP(cmpunord), - SSE_FOP(cmpneq), - SSE_FOP(cmpnlt), - SSE_FOP(cmpnle), - SSE_FOP(cmpord), + SSE_CMP(cmpeq), + SSE_CMP(cmplt), + SSE_CMP(cmple), + SSE_CMP(cmpunord), + SSE_CMP(cmpneq), + SSE_CMP(cmpnlt), + SSE_CMP(cmpnle), + SSE_CMP(cmpord), }; +#undef SSE_CMP static const SSEFunc_0_epp sse_op_table5[256] = { [0x0c] = gen_helper_pi2fw, @@ -3025,117 +3115,146 @@ static const SSEFunc_0_epp sse_op_table5[256] = { [0xb6] = gen_helper_movq, /* pfrcpit2 */ [0xb7] = gen_helper_pmulhrw_mmx, [0xbb] = gen_helper_pswapd, - [0xbf] = gen_helper_pavgb_mmx /* pavgusb */ + [0xbf] = gen_helper_pavgb_mmx, }; -struct SSEOpHelper_epp { - SSEFunc_0_epp op[2]; +struct SSEOpHelper_table6 { + SSEFuncs fn[2]; uint32_t ext_mask; + int flags; }; -struct SSEOpHelper_eppi { - SSEFunc_0_eppi op[2]; +struct SSEOpHelper_table7 { + union { + SSEFunc_0_eppi op1; + } fn[2]; uint32_t ext_mask; + int flags; }; -#define SSSE3_OP(x) { MMX_OP2(x), CPUID_EXT_SSSE3 } -#define SSE41_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE41 } -#define SSE42_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE42 } -#define SSE41_SPECIAL { { NULL, SSE_SPECIAL }, CPUID_EXT_SSE41 } -#define PCLMULQDQ_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, \ - CPUID_EXT_PCLMULQDQ } -#define AESNI_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_AES } +#define gen_helper_special_xmm NULL -static const struct SSEOpHelper_epp sse_op_table6[256] = { - [0x00] = SSSE3_OP(pshufb), - [0x01] = SSSE3_OP(phaddw), - [0x02] = SSSE3_OP(phaddd), - [0x03] = SSSE3_OP(phaddsw), - [0x04] = SSSE3_OP(pmaddubsw), - [0x05] = SSSE3_OP(phsubw), - [0x06] = SSSE3_OP(phsubd), - [0x07] = SSSE3_OP(phsubsw), - [0x08] = SSSE3_OP(psignb), - [0x09] = SSSE3_OP(psignw), - [0x0a] = SSSE3_OP(psignd), - [0x0b] = SSSE3_OP(pmulhrsw), - [0x10] = SSE41_OP(pblendvb), - [0x14] = SSE41_OP(blendvps), - [0x15] = SSE41_OP(blendvpd), - [0x17] = SSE41_OP(ptest), - [0x1c] = SSSE3_OP(pabsb), - [0x1d] = SSSE3_OP(pabsw), - [0x1e] = SSSE3_OP(pabsd), - [0x20] = SSE41_OP(pmovsxbw), - [0x21] = SSE41_OP(pmovsxbd), - [0x22] = SSE41_OP(pmovsxbq), - [0x23] = SSE41_OP(pmovsxwd), - [0x24] = SSE41_OP(pmovsxwq), - [0x25] = SSE41_OP(pmovsxdq), - [0x28] = SSE41_OP(pmuldq), - [0x29] = SSE41_OP(pcmpeqq), - [0x2a] = SSE41_SPECIAL, /* movntqda */ - [0x2b] = SSE41_OP(packusdw), - [0x30] = SSE41_OP(pmovzxbw), - [0x31] = SSE41_OP(pmovzxbd), - [0x32] = SSE41_OP(pmovzxbq), - [0x33] = SSE41_OP(pmovzxwd), - [0x34] = SSE41_OP(pmovzxwq), - [0x35] = SSE41_OP(pmovzxdq), - [0x37] = SSE42_OP(pcmpgtq), - [0x38] = SSE41_OP(pminsb), - [0x39] = SSE41_OP(pminsd), - [0x3a] = SSE41_OP(pminuw), - [0x3b] = SSE41_OP(pminud), - [0x3c] = SSE41_OP(pmaxsb), - [0x3d] = SSE41_OP(pmaxsd), - [0x3e] = SSE41_OP(pmaxuw), - [0x3f] = SSE41_OP(pmaxud), - [0x40] = SSE41_OP(pmulld), - [0x41] = SSE41_OP(phminposuw), - [0xdb] = AESNI_OP(aesimc), - [0xdc] = AESNI_OP(aesenc), - [0xdd] = AESNI_OP(aesenclast), - [0xde] = AESNI_OP(aesdec), - [0xdf] = AESNI_OP(aesdeclast), +#define OP(name, op, flags, ext, mmx_name) \ + {{{.op = mmx_name}, {.op = gen_helper_ ## name ## _xmm} }, \ + CPUID_EXT_ ## ext, flags} +#define BINARY_OP_MMX(name, ext) \ + OP(name, op1, SSE_OPF_MMX, ext, gen_helper_ ## name ## _mmx) +#define BINARY_OP(name, ext, flags) \ + OP(name, op1, flags, ext, NULL) +#define UNARY_OP_MMX(name, ext) \ + OP(name, op1, SSE_OPF_MMX, ext, gen_helper_ ## name ## _mmx) +#define UNARY_OP(name, ext, flags) \ + OP(name, op1, flags, ext, NULL) +#define BLENDV_OP(name, ext, flags) OP(name, op1, 0, ext, NULL) +#define CMP_OP(name, ext) OP(name, op1, SSE_OPF_CMP, ext, NULL) +#define SPECIAL_OP(ext) OP(special, op1, SSE_OPF_SPECIAL, ext, NULL) + +/* prefix [66] 0f 38 */ +static const struct SSEOpHelper_table6 sse_op_table6[256] = { + [0x00] = BINARY_OP_MMX(pshufb, SSSE3), + [0x01] = BINARY_OP_MMX(phaddw, SSSE3), + [0x02] = BINARY_OP_MMX(phaddd, SSSE3), + [0x03] = BINARY_OP_MMX(phaddsw, SSSE3), + [0x04] = BINARY_OP_MMX(pmaddubsw, SSSE3), + [0x05] = BINARY_OP_MMX(phsubw, SSSE3), + [0x06] = BINARY_OP_MMX(phsubd, SSSE3), + [0x07] = BINARY_OP_MMX(phsubsw, SSSE3), + [0x08] = BINARY_OP_MMX(psignb, SSSE3), + [0x09] = BINARY_OP_MMX(psignw, SSSE3), + [0x0a] = BINARY_OP_MMX(psignd, SSSE3), + [0x0b] = BINARY_OP_MMX(pmulhrsw, SSSE3), + [0x10] = BLENDV_OP(pblendvb, SSE41, SSE_OPF_MMX), + [0x14] = BLENDV_OP(blendvps, SSE41, 0), + [0x15] = BLENDV_OP(blendvpd, SSE41, 0), + [0x17] = CMP_OP(ptest, SSE41), + [0x1c] = UNARY_OP_MMX(pabsb, SSSE3), + [0x1d] = UNARY_OP_MMX(pabsw, SSSE3), + [0x1e] = UNARY_OP_MMX(pabsd, SSSE3), + [0x20] = UNARY_OP(pmovsxbw, SSE41, SSE_OPF_MMX), + [0x21] = UNARY_OP(pmovsxbd, SSE41, SSE_OPF_MMX), + [0x22] = UNARY_OP(pmovsxbq, SSE41, SSE_OPF_MMX), + [0x23] = UNARY_OP(pmovsxwd, SSE41, SSE_OPF_MMX), + [0x24] = UNARY_OP(pmovsxwq, SSE41, SSE_OPF_MMX), + [0x25] = UNARY_OP(pmovsxdq, SSE41, SSE_OPF_MMX), + [0x28] = BINARY_OP(pmuldq, SSE41, SSE_OPF_MMX), + [0x29] = BINARY_OP(pcmpeqq, SSE41, SSE_OPF_MMX), + [0x2a] = SPECIAL_OP(SSE41), /* movntdqa */ + [0x2b] = BINARY_OP(packusdw, SSE41, SSE_OPF_MMX), + [0x30] = UNARY_OP(pmovzxbw, SSE41, SSE_OPF_MMX), + [0x31] = UNARY_OP(pmovzxbd, SSE41, SSE_OPF_MMX), + [0x32] = UNARY_OP(pmovzxbq, SSE41, SSE_OPF_MMX), + [0x33] = UNARY_OP(pmovzxwd, SSE41, SSE_OPF_MMX), + [0x34] = UNARY_OP(pmovzxwq, SSE41, SSE_OPF_MMX), + [0x35] = UNARY_OP(pmovzxdq, SSE41, SSE_OPF_MMX), + [0x37] = BINARY_OP(pcmpgtq, SSE41, SSE_OPF_MMX), + [0x38] = BINARY_OP(pminsb, SSE41, SSE_OPF_MMX), + [0x39] = BINARY_OP(pminsd, SSE41, SSE_OPF_MMX), + [0x3a] = BINARY_OP(pminuw, SSE41, SSE_OPF_MMX), + [0x3b] = BINARY_OP(pminud, SSE41, SSE_OPF_MMX), + [0x3c] = BINARY_OP(pmaxsb, SSE41, SSE_OPF_MMX), + [0x3d] = BINARY_OP(pmaxsd, SSE41, SSE_OPF_MMX), + [0x3e] = BINARY_OP(pmaxuw, SSE41, SSE_OPF_MMX), + [0x3f] = BINARY_OP(pmaxud, SSE41, SSE_OPF_MMX), + [0x40] = BINARY_OP(pmulld, SSE41, SSE_OPF_MMX), + [0x41] = UNARY_OP(phminposuw, SSE41, 0), + [0xdb] = UNARY_OP(aesimc, AES, 0), + [0xdc] = BINARY_OP(aesenc, AES, 0), + [0xdd] = BINARY_OP(aesenclast, AES, 0), + [0xde] = BINARY_OP(aesdec, AES, 0), + [0xdf] = BINARY_OP(aesdeclast, AES, 0), }; -static const struct SSEOpHelper_eppi sse_op_table7[256] = { - [0x08] = SSE41_OP(roundps), - [0x09] = SSE41_OP(roundpd), - [0x0a] = SSE41_OP(roundss), - [0x0b] = SSE41_OP(roundsd), - [0x0c] = SSE41_OP(blendps), - [0x0d] = SSE41_OP(blendpd), - [0x0e] = SSE41_OP(pblendw), - [0x0f] = SSSE3_OP(palignr), - [0x14] = SSE41_SPECIAL, /* pextrb */ - [0x15] = SSE41_SPECIAL, /* pextrw */ - [0x16] = SSE41_SPECIAL, /* pextrd/pextrq */ - [0x17] = SSE41_SPECIAL, /* extractps */ - [0x20] = SSE41_SPECIAL, /* pinsrb */ - [0x21] = SSE41_SPECIAL, /* insertps */ - [0x22] = SSE41_SPECIAL, /* pinsrd/pinsrq */ - [0x40] = SSE41_OP(dpps), - [0x41] = SSE41_OP(dppd), - [0x42] = SSE41_OP(mpsadbw), - [0x44] = PCLMULQDQ_OP(pclmulqdq), - [0x60] = SSE42_OP(pcmpestrm), - [0x61] = SSE42_OP(pcmpestri), - [0x62] = SSE42_OP(pcmpistrm), - [0x63] = SSE42_OP(pcmpistri), - [0xdf] = AESNI_OP(aeskeygenassist), +/* prefix [66] 0f 3a */ +static const struct SSEOpHelper_table7 sse_op_table7[256] = { + [0x08] = UNARY_OP(roundps, SSE41, 0), + [0x09] = UNARY_OP(roundpd, SSE41, 0), + [0x0a] = UNARY_OP(roundss, SSE41, SSE_OPF_SCALAR), + [0x0b] = UNARY_OP(roundsd, SSE41, SSE_OPF_SCALAR), + [0x0c] = BINARY_OP(blendps, SSE41, 0), + [0x0d] = BINARY_OP(blendpd, SSE41, 0), + [0x0e] = BINARY_OP(pblendw, SSE41, SSE_OPF_MMX), + [0x0f] = BINARY_OP_MMX(palignr, SSSE3), + [0x14] = SPECIAL_OP(SSE41), /* pextrb */ + [0x15] = SPECIAL_OP(SSE41), /* pextrw */ + [0x16] = SPECIAL_OP(SSE41), /* pextrd/pextrq */ + [0x17] = SPECIAL_OP(SSE41), /* extractps */ + [0x20] = SPECIAL_OP(SSE41), /* pinsrb */ + [0x21] = SPECIAL_OP(SSE41), /* insertps */ + [0x22] = SPECIAL_OP(SSE41), /* pinsrd/pinsrq */ + [0x40] = BINARY_OP(dpps, SSE41, 0), + [0x41] = BINARY_OP(dppd, SSE41, 0), + [0x42] = BINARY_OP(mpsadbw, SSE41, SSE_OPF_MMX), + [0x44] = BINARY_OP(pclmulqdq, PCLMULQDQ, 0), + [0x60] = CMP_OP(pcmpestrm, SSE42), + [0x61] = CMP_OP(pcmpestri, SSE42), + [0x62] = CMP_OP(pcmpistrm, SSE42), + [0x63] = CMP_OP(pcmpistri, SSE42), + [0xdf] = UNARY_OP(aeskeygenassist, AES, 0), }; +#undef OP +#undef BINARY_OP_MMX +#undef BINARY_OP +#undef UNARY_OP_MMX +#undef UNARY_OP +#undef BLENDV_OP +#undef SPECIAL_OP + +/* VEX prefix not allowed */ +#define CHECK_NO_VEX(s) do { \ + if (s->prefix & PREFIX_VEX) \ + goto illegal_op; \ + } while (0) + static void gen_sse(CPUX86State *env, DisasContext *s, int b, target_ulong pc_start) { int b1, op1_offset, op2_offset, is_xmm, val; int modrm, mod, rm, reg; - SSEFunc_0_epp sse_fn_epp; - SSEFunc_0_eppi sse_fn_eppi; - SSEFunc_0_ppi sse_fn_ppi; - SSEFunc_0_eppt sse_fn_eppt; + int sse_op_flags; + SSEFuncs sse_op_fn; + const struct SSEOpHelper_table6 *op6; + const struct SSEOpHelper_table7 *op7; MemOp ot; b &= 0xff; @@ -3147,8 +3266,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, b1 = 3; else b1 = 0; - sse_fn_epp = sse_op_table1[b][b1]; - if (!sse_fn_epp) { + sse_op_flags = sse_op_table1[b].flags; + sse_op_fn = sse_op_table1[b].fn[b1]; + if ((sse_op_flags & (SSE_OPF_SPECIAL | SSE_OPF_3DNOW)) == 0 + && !sse_op_fn.op1) { goto unknown_op; } if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) { @@ -3161,6 +3282,11 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, is_xmm = 1; } } + if (sse_op_flags & SSE_OPF_3DNOW) { + if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) { + goto illegal_op; + } + } /* simple MMX/SSE operation */ if (s->flags & HF_TS_MASK) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); @@ -3202,10 +3328,11 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, reg |= REX_R(s); } mod = (modrm >> 6) & 3; - if (sse_fn_epp == SSE_SPECIAL) { + if (sse_op_flags & SSE_OPF_SPECIAL) { b |= (b1 << 8); switch(b) { case 0x0e7: /* movntq */ + CHECK_NO_VEX(s); if (mod == 3) { goto illegal_op; } @@ -3214,17 +3341,17 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, break; case 0x1e7: /* movntdq */ case 0x02b: /* movntps */ - case 0x12b: /* movntps */ + case 0x12b: /* movntpd */ if (mod == 3) goto illegal_op; gen_lea_modrm(env, s, modrm); - gen_sto_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); + gen_sto_env_A0(s, ZMM_OFFSET(reg), true); break; case 0x3f0: /* lddqu */ if (mod == 3) goto illegal_op; gen_lea_modrm(env, s, modrm); - gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); + gen_ldo_env_A0(s, ZMM_OFFSET(reg), false); break; case 0x22b: /* movntss */ case 0x32b: /* movntsd */ @@ -3241,6 +3368,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } break; case 0x6e: /* movd mm, ea */ + CHECK_NO_VEX(s); #ifdef TARGET_X86_64 if (s->dflag == MO_64) { gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 0); @@ -3260,20 +3388,19 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, #ifdef TARGET_X86_64 if (s->dflag == MO_64) { gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 0); - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(reg)); gen_helper_movq_mm_T0_xmm(s->ptr0, s->T0); } else #endif { gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 0); - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(reg)); tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_movl_mm_T0_xmm(s->ptr0, s->tmp2_i32); } break; case 0x6f: /* movq mm, ea */ + CHECK_NO_VEX(s); if (mod != 3) { gen_lea_modrm(env, s, modrm); gen_ldq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx)); @@ -3293,11 +3420,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x26f: /* movdqu xmm, ea */ if (mod != 3) { gen_lea_modrm(env, s, modrm); - gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); + gen_ldo_env_A0(s, ZMM_OFFSET(reg), + /* movaps, movapd, movdqa */ + b == 0x028 || b == 0x128 || b == 0x16f); } else { rm = (modrm & 7) | REX_B(s); - gen_op_movo(s, offsetof(CPUX86State, xmm_regs[reg]), - offsetof(CPUX86State,xmm_regs[rm])); + gen_op_movo(s, ZMM_OFFSET(reg), ZMM_OFFSET(rm)); } break; case 0x210: /* movss xmm, ea */ @@ -3315,8 +3443,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3))); } else { rm = (modrm & 7) | REX_B(s); - gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)), - offsetof(CPUX86State,xmm_regs[rm].ZMM_L(0))); + tcg_gen_ld_i32(s->tmp2_i32, cpu_env, + offsetof(CPUX86State, xmm_regs[rm].ZMM_L(0))); + tcg_gen_st_i32(s->tmp2_i32, cpu_env, + offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0))); } break; case 0x310: /* movsd xmm, ea */ @@ -3332,7 +3462,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } else { rm = (modrm & 7) | REX_B(s); gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)), - offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0))); + offsetof(CPUX86State, xmm_regs[rm].ZMM_Q(0))); } break; case 0x012: /* movlps */ @@ -3351,7 +3481,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x212: /* movsldup */ if (mod != 3) { gen_lea_modrm(env, s, modrm); - gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); + gen_ldo_env_A0(s, ZMM_OFFSET(reg), true); } else { rm = (modrm & 7) | REX_B(s); gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)), @@ -3393,7 +3523,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x216: /* movshdup */ if (mod != 3) { gen_lea_modrm(env, s, modrm); - gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); + gen_ldo_env_A0(s, ZMM_OFFSET(reg), true); } else { rm = (modrm & 7) | REX_B(s); gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(1)), @@ -3408,6 +3538,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, break; case 0x178: case 0x378: + CHECK_NO_VEX(s); { int bit_index, field_length; @@ -3415,19 +3546,29 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, goto illegal_op; field_length = x86_ldub_code(env, s) & 0x3F; bit_index = x86_ldub_code(env, s) & 0x3F; - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State,xmm_regs[reg])); + tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(reg)); if (b1 == 1) gen_helper_extrq_i(cpu_env, s->ptr0, tcg_const_i32(bit_index), tcg_const_i32(field_length)); - else - gen_helper_insertq_i(cpu_env, s->ptr0, + else { + if (mod != 3) { + gen_lea_modrm(env, s, modrm); + op2_offset = offsetof(CPUX86State, xmm_t0); + gen_ldq_env_A0(s, offsetof(CPUX86State, xmm_t0.ZMM_D(0))); + } else { + rm = (modrm & 7) | REX_B(s); + op2_offset = ZMM_OFFSET(rm); + } + tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); + gen_helper_insertq_i(cpu_env, s->ptr0, s->ptr1, tcg_const_i32(bit_index), tcg_const_i32(field_length)); + } } break; case 0x7e: /* movd ea, mm */ + CHECK_NO_VEX(s); #ifdef TARGET_X86_64 if (s->dflag == MO_64) { tcg_gen_ld_i64(s->T0, cpu_env, @@ -3468,6 +3609,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, gen_op_movq_env_0(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1))); break; case 0x7f: /* movq ea, mm */ + CHECK_NO_VEX(s); if (mod != 3) { gen_lea_modrm(env, s, modrm); gen_stq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx)); @@ -3485,11 +3627,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x27f: /* movdqu ea, xmm */ if (mod != 3) { gen_lea_modrm(env, s, modrm); - gen_sto_env_A0(s, offsetof(CPUX86State, xmm_regs[reg])); + gen_sto_env_A0(s, ZMM_OFFSET(reg), + /* movaps, movapd, movdqa */ + b == 0x029 || b == 0x129 || b == 0x17f); } else { rm = (modrm & 7) | REX_B(s); - gen_op_movo(s, offsetof(CPUX86State, xmm_regs[rm]), - offsetof(CPUX86State,xmm_regs[reg])); + gen_op_movo(s, ZMM_OFFSET(rm), ZMM_OFFSET(reg)); } break; case 0x211: /* movss ea, xmm */ @@ -3551,6 +3694,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, offsetof(CPUX86State, xmm_t0.ZMM_L(1))); op1_offset = offsetof(CPUX86State,xmm_t0); } else { + CHECK_NO_VEX(s); tcg_gen_movi_tl(s->T0, val); tcg_gen_st32_tl(s->T0, cpu_env, offsetof(CPUX86State, mmx_t0.MMX_L(0))); @@ -3560,38 +3704,37 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, op1_offset = offsetof(CPUX86State,mmx_t0); } assert(b1 < 2); - sse_fn_epp = sse_op_table2[((b - 1) & 3) * 8 + + SSEFunc_0_epp fn = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1]; - if (!sse_fn_epp) { + if (!fn) { goto unknown_op; } if (is_xmm) { rm = (modrm & 7) | REX_B(s); - op2_offset = offsetof(CPUX86State,xmm_regs[rm]); + op2_offset = ZMM_OFFSET(rm); } else { rm = (modrm & 7); op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); } tcg_gen_addi_ptr(s->ptr0, cpu_env, op2_offset); tcg_gen_addi_ptr(s->ptr1, cpu_env, op1_offset); - sse_fn_epp(cpu_env, s->ptr0, s->ptr1); + fn(cpu_env, s->ptr0, s->ptr1); break; case 0x050: /* movmskps */ rm = (modrm & 7) | REX_B(s); - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State,xmm_regs[rm])); - gen_helper_movmskps(s->tmp2_i32, cpu_env, s->ptr0); + tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(rm)); + gen_helper_movmskps_xmm(s->tmp2_i32, cpu_env, s->ptr0); tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32); break; case 0x150: /* movmskpd */ rm = (modrm & 7) | REX_B(s); - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State,xmm_regs[rm])); - gen_helper_movmskpd(s->tmp2_i32, cpu_env, s->ptr0); + tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(rm)); + gen_helper_movmskpd_xmm(s->tmp2_i32, cpu_env, s->ptr0); tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32); break; case 0x02a: /* cvtpi2ps */ case 0x12a: /* cvtpi2pd */ + CHECK_NO_VEX(s); gen_helper_enter_mmx(cpu_env); if (mod != 3) { gen_lea_modrm(env, s, modrm); @@ -3601,7 +3744,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, rm = (modrm & 7); op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); } - op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + op1_offset = ZMM_OFFSET(reg); tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); switch(b >> 8) { @@ -3618,7 +3761,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x32a: /* cvtsi2sd */ ot = mo_64_32(s->dflag); gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + op1_offset = ZMM_OFFSET(reg); tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); if (ot == MO_32) { SSEFunc_0_epi sse_fn_epi = sse_op_table3ai[(b >> 8) & 1]; @@ -3637,14 +3780,16 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x12c: /* cvttpd2pi */ case 0x02d: /* cvtps2pi */ case 0x12d: /* cvtpd2pi */ + CHECK_NO_VEX(s); gen_helper_enter_mmx(cpu_env); if (mod != 3) { gen_lea_modrm(env, s, modrm); op2_offset = offsetof(CPUX86State,xmm_t0); - gen_ldo_env_A0(s, op2_offset); + /* FIXME: should be 64-bit access if b1 == 0. */ + gen_ldo_env_A0(s, op2_offset, !!b1); } else { rm = (modrm & 7) | REX_B(s); - op2_offset = offsetof(CPUX86State,xmm_regs[rm]); + op2_offset = ZMM_OFFSET(rm); } op1_offset = offsetof(CPUX86State,fpregs[reg & 7].mmx); tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); @@ -3681,7 +3826,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, op2_offset = offsetof(CPUX86State,xmm_t0); } else { rm = (modrm & 7) | REX_B(s); - op2_offset = offsetof(CPUX86State,xmm_regs[rm]); + op2_offset = ZMM_OFFSET(rm); } tcg_gen_addi_ptr(s->ptr0, cpu_env, op2_offset); if (ot == MO_32) { @@ -3710,6 +3855,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_st16_tl(s->T0, cpu_env, offsetof(CPUX86State,xmm_regs[reg].ZMM_W(val))); } else { + CHECK_NO_VEX(s); val &= 3; tcg_gen_st16_tl(s->T0, cpu_env, offsetof(CPUX86State,fpregs[reg].mmx.MMX_W(val))); @@ -3749,6 +3895,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } break; case 0x2d6: /* movq2dq */ + CHECK_NO_VEX(s); gen_helper_enter_mmx(cpu_env); rm = (modrm & 7); gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)), @@ -3756,6 +3903,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, gen_op_movq_env_0(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1))); break; case 0x3d6: /* movdq2q */ + CHECK_NO_VEX(s); gen_helper_enter_mmx(cpu_env); rm = (modrm & 7) | REX_B(s); gen_op_movq(s, offsetof(CPUX86State, fpregs[reg & 7].mmx), @@ -3767,10 +3915,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, goto illegal_op; if (b1) { rm = (modrm & 7) | REX_B(s); - tcg_gen_addi_ptr(s->ptr0, cpu_env, - offsetof(CPUX86State, xmm_regs[rm])); + tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(rm)); gen_helper_pmovmskb_xmm(s->tmp2_i32, cpu_env, s->ptr0); } else { + CHECK_NO_VEX(s); rm = (modrm & 7); tcg_gen_addi_ptr(s->ptr0, cpu_env, offsetof(CPUX86State, fpregs[rm].mmx)); @@ -3792,17 +3940,18 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, mod = (modrm >> 6) & 3; assert(b1 < 2); - sse_fn_epp = sse_op_table6[b].op[b1]; - if (!sse_fn_epp) { + op6 = &sse_op_table6[b]; + if (op6->ext_mask == 0) { goto unknown_op; } - if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask)) + if (!(s->cpuid_ext_features & op6->ext_mask)) { goto illegal_op; + } if (b1) { - op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + op1_offset = ZMM_OFFSET(reg); if (mod == 3) { - op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]); + op2_offset = ZMM_OFFSET(rm | REX_B(s)); } else { op2_offset = offsetof(CPUX86State,xmm_t0); gen_lea_modrm(env, s, modrm); @@ -3826,14 +3975,24 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_st16_tl(s->tmp0, cpu_env, op2_offset + offsetof(ZMMReg, ZMM_W(0))); break; - case 0x2a: /* movntqda */ - gen_ldo_env_A0(s, op1_offset); + case 0x2a: /* movntdqa */ + gen_ldo_env_A0(s, op1_offset, true); return; default: - gen_ldo_env_A0(s, op2_offset); + gen_ldo_env_A0(s, op2_offset, true); } } + if (!op6->fn[b1].op1) { + goto illegal_op; + } + tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); + op6->fn[b1].op1(cpu_env, s->ptr0, s->ptr1); } else { + CHECK_NO_VEX(s); + if ((op6->flags & SSE_OPF_MMX) == 0) { + goto unknown_op; + } op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); if (mod == 3) { op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); @@ -3842,16 +4001,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, gen_lea_modrm(env, s, modrm); gen_ldq_env_A0(s, op2_offset); } - } - if (sse_fn_epp == SSE_SPECIAL) { - goto unknown_op; + tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); + op6->fn[0].op1(cpu_env, s->ptr0, s->ptr1); } - tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); - tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - sse_fn_epp(cpu_env, s->ptr0, s->ptr1); - - if (b == 0x17) { + if (op6->flags & SSE_OPF_CMP) { set_cc_op(s, CC_OP_EFLAGS); } break; @@ -3868,6 +4023,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x3f0: /* crc32 Gd,Eb */ case 0x3f1: /* crc32 Gd,Ey */ do_crc32: + CHECK_NO_VEX(s); if (!(s->cpuid_ext_features & CPUID_EXT_SSE42)) { goto illegal_op; } @@ -3890,6 +4046,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x1f0: /* crc32 or movbe */ case 0x1f1: + CHECK_NO_VEX(s); /* For these insns, the f3 prefix is supposed to have priority over the 66 prefix, but that's not what we implement above setting b1. */ @@ -3899,6 +4056,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, /* FALLTHRU */ case 0x0f0: /* movbe Gy,My */ case 0x0f1: /* movbe My,Gy */ + CHECK_NO_VEX(s); if (!(s->cpuid_ext_features & CPUID_EXT_MOVBE)) { goto illegal_op; } @@ -4065,6 +4223,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, case 0x1f6: /* adcx Gy, Ey */ case 0x2f6: /* adox Gy, Ey */ + CHECK_NO_VEX(s); if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_ADX)) { goto illegal_op; } else { @@ -4220,16 +4379,21 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, mod = (modrm >> 6) & 3; assert(b1 < 2); - sse_fn_eppi = sse_op_table7[b].op[b1]; - if (!sse_fn_eppi) { + op7 = &sse_op_table7[b]; + if (op7->ext_mask == 0) { goto unknown_op; } - if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask)) + if (!(s->cpuid_ext_features & op7->ext_mask)) { goto illegal_op; + } s->rip_offset = 1; - if (sse_fn_eppi == SSE_SPECIAL) { + if (op7->flags & SSE_OPF_SPECIAL) { + /* None of the "special" ops are valid on mmx registers */ + if (b1 == 0) { + goto illegal_op; + } ot = mo_64_32(s->dflag); rm = (modrm & 7) | REX_B(s); if (mod != 3) @@ -4364,16 +4528,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, return; } - if (b1) { - op1_offset = offsetof(CPUX86State,xmm_regs[reg]); - if (mod == 3) { - op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]); - } else { - op2_offset = offsetof(CPUX86State,xmm_t0); - gen_lea_modrm(env, s, modrm); - gen_ldo_env_A0(s, op2_offset); + if (b1 == 0) { + CHECK_NO_VEX(s); + /* MMX */ + if ((op7->flags & SSE_OPF_MMX) == 0) { + goto illegal_op; } - } else { op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); if (mod == 3) { op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); @@ -4382,9 +4542,29 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, gen_lea_modrm(env, s, modrm); gen_ldq_env_A0(s, op2_offset); } - } - val = x86_ldub_code(env, s); + val = x86_ldub_code(env, s); + tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); + /* We only actually have one MMX instuction (palignr) */ + assert(b == 0x0f); + + op7->fn[0].op1(cpu_env, s->ptr0, s->ptr1, + tcg_const_i32(val)); + break; + } + + /* SSE */ + op1_offset = ZMM_OFFSET(reg); + if (mod == 3) { + op2_offset = ZMM_OFFSET(rm | REX_B(s)); + } else { + op2_offset = offsetof(CPUX86State, xmm_t0); + gen_lea_modrm(env, s, modrm); + gen_ldo_env_A0(s, op2_offset, true); + } + + val = x86_ldub_code(env, s); if ((b & 0xfc) == 0x60) { /* pcmpXstrX */ set_cc_op(s, CC_OP_EFLAGS); @@ -4396,7 +4576,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - sse_fn_eppi(cpu_env, s->ptr0, s->ptr1, tcg_const_i32(val)); + op7->fn[b1].op1(cpu_env, s->ptr0, s->ptr1, tcg_const_i32(val)); + if (op7->flags & SSE_OPF_CMP) { + set_cc_op(s, CC_OP_EFLAGS); + } break; case 0x33a: @@ -4447,33 +4630,29 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, break; } if (is_xmm) { - op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + op1_offset = ZMM_OFFSET(reg); if (mod != 3) { int sz = 4; gen_lea_modrm(env, s, modrm); - op2_offset = offsetof(CPUX86State,xmm_t0); + op2_offset = offsetof(CPUX86State, xmm_t0); - switch (b) { - case 0x50 ... 0x5a: - case 0x5c ... 0x5f: - case 0xc2: - /* Most sse scalar operations. */ - if (b1 == 2) { - sz = 2; - } else if (b1 == 3) { - sz = 3; - } - break; - - case 0x2e: /* ucomis[sd] */ - case 0x2f: /* comis[sd] */ - if (b1 == 0) { - sz = 2; + if (sse_op_flags & SSE_OPF_SCALAR) { + if (sse_op_flags & SSE_OPF_CMP) { + /* ucomis[sd], comis[sd] */ + if (b1 == 0) { + sz = 2; + } else { + sz = 3; + } } else { - sz = 3; + /* Most sse scalar operations. */ + if (b1 == 2) { + sz = 2; + } else if (b1 == 3) { + sz = 3; + } } - break; } switch (sz) { @@ -4481,7 +4660,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, /* 32 bit access */ gen_op_ld_v(s, MO_32, s->T0, s->A0); tcg_gen_st32_tl(s->T0, cpu_env, - offsetof(CPUX86State,xmm_t0.ZMM_L(0))); + offsetof(CPUX86State, xmm_t0.ZMM_L(0))); break; case 3: /* 64 bit access */ @@ -4489,14 +4668,15 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, break; default: /* 128 bit access */ - gen_ldo_env_A0(s, op2_offset); + gen_ldo_env_A0(s, op2_offset, true); break; } } else { rm = (modrm & 7) | REX_B(s); - op2_offset = offsetof(CPUX86State,xmm_regs[rm]); + op2_offset = ZMM_OFFSET(rm); } } else { + CHECK_NO_VEX(s); op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); if (mod != 3) { gen_lea_modrm(env, s, modrm); @@ -4506,60 +4686,42 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, rm = (modrm & 7); op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); } + if (sse_op_flags & SSE_OPF_3DNOW) { + /* 3DNow! data insns */ + val = x86_ldub_code(env, s); + SSEFunc_0_epp op_3dnow = sse_op_table5[val]; + if (!op_3dnow) { + goto unknown_op; + } + tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); + op_3dnow(cpu_env, s->ptr0, s->ptr1); + return; + } } - switch(b) { - case 0x0f: /* 3DNow! data insns */ + tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); + if (sse_op_flags & SSE_OPF_SHUF) { val = x86_ldub_code(env, s); - sse_fn_epp = sse_op_table5[val]; - if (!sse_fn_epp) { - goto unknown_op; - } - if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) { - goto illegal_op; - } - tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); - tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - sse_fn_epp(cpu_env, s->ptr0, s->ptr1); - break; - case 0x70: /* pshufx insn */ - case 0xc6: /* pshufx insn */ - val = x86_ldub_code(env, s); - tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); - tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - /* XXX: introduce a new table? */ - sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_epp; - sse_fn_ppi(s->ptr0, s->ptr1, tcg_const_i32(val)); - break; - case 0xc2: - /* compare insns, bits 7:3 (7:5 for AVX) are ignored */ - val = x86_ldub_code(env, s) & 7; - sse_fn_epp = sse_op_table4[val][b1]; - - tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); - tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - sse_fn_epp(cpu_env, s->ptr0, s->ptr1); - break; - case 0xf7: + sse_op_fn.op1i(s->ptr0, s->ptr1, tcg_const_i32(val)); + } else if (b == 0xf7) { /* maskmov : we must prepare A0 */ - if (mod != 3) + if (mod != 3) { goto illegal_op; + } tcg_gen_mov_tl(s->A0, cpu_regs[R_EDI]); gen_extu(s->aflag, s->A0); gen_add_A0_ds_seg(s); - - tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); - tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - /* XXX: introduce a new table? */ - sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp; - sse_fn_eppt(cpu_env, s->ptr0, s->ptr1, s->A0); - break; - default: - tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset); - tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset); - sse_fn_epp(cpu_env, s->ptr0, s->ptr1); - break; + sse_op_fn.op1t(cpu_env, s->ptr0, s->ptr1, s->A0); + } else if (b == 0xc2) { + /* compare insns, bits 7:3 (7:5 for AVX) are ignored */ + val = x86_ldub_code(env, s) & 7; + sse_op_table4[val][b1](cpu_env, s->ptr0, s->ptr1); + } else { + sse_op_fn.op1(cpu_env, s->ptr0, s->ptr1); } - if (b == 0x2e || b == 0x2f) { + + if (sse_op_flags & SSE_OPF_CMP) { set_cc_op(s, CC_OP_EFLAGS); } } @@ -4576,6 +4738,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) int modrm, reg, rm, mod, op, opreg, val; target_ulong next_eip, tval; target_ulong pc_start = s->base.pc_next; + bool orig_cc_op_dirty = s->cc_op_dirty; + CCOp orig_cc_op = s->cc_op; s->pc_start = s->pc = pc_start; s->override = -1; @@ -4588,9 +4752,22 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) s->rip_offset = 0; /* for relative ip address */ s->vex_l = 0; s->vex_v = 0; - if (sigsetjmp(s->jmpbuf, 0) != 0) { + switch (sigsetjmp(s->jmpbuf, 0)) { + case 0: + break; + case 1: gen_exception_gpf(s); return s->pc; + case 2: + /* Restore state that may affect the next instruction. */ + s->cc_op_dirty = orig_cc_op_dirty; + s->cc_op = orig_cc_op; + s->base.num_insns--; + tcg_remove_ops_after(s->prev_insn_end); + s->base.is_jmp = DISAS_TOO_MANY; + return pc_start; + default: + g_assert_not_reached(); } prefixes = 0; @@ -4601,9 +4778,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) switch (b) { case 0xf3: prefixes |= PREFIX_REPZ; + prefixes &= ~PREFIX_REPNZ; goto next_byte; case 0xf2: prefixes |= PREFIX_REPNZ; + prefixes &= ~PREFIX_REPZ; goto next_byte; case 0xf0: prefixes |= PREFIX_LOCK; @@ -5717,16 +5896,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) target_ulong offset_addr; ot = mo_b_d(b, dflag); - switch (s->aflag) { -#ifdef TARGET_X86_64 - case MO_64: - offset_addr = x86_ldq_code(env, s); - break; -#endif - default: - offset_addr = insn_get(env, s, s->aflag); - break; - } + offset_addr = insn_get_addr(env, s, s->aflag); tcg_gen_movi_tl(s->A0, offset_addr); gen_add_A0_ds_seg(s); if ((b & 2) == 0) { @@ -8652,6 +8822,7 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); + dc->prev_insn_end = tcg_last_op(); tcg_gen_insn_start(dc->base.pc_next, dc->cc_op); } @@ -8672,31 +8843,22 @@ static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) #endif pc_next = disas_insn(dc, cpu); - - if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) { - /* if single step mode, we generate only one instruction and - generate an exception */ - /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear - the flag and abort the translation to give the irqs a - chance to happen */ - dc->base.is_jmp = DISAS_TOO_MANY; - } else if ((tb_cflags(dc->base.tb) & CF_USE_ICOUNT) - && ((pc_next & TARGET_PAGE_MASK) - != ((pc_next + TARGET_MAX_INSN_SIZE - 1) - & TARGET_PAGE_MASK) - || (pc_next & ~TARGET_PAGE_MASK) == 0)) { - /* Do not cross the boundary of the pages in icount mode, - it can cause an exception. Do it only when boundary is - crossed by the first instruction in the block. - If current instruction already crossed the bound - it's ok, - because an exception hasn't stopped this code. - */ - dc->base.is_jmp = DISAS_TOO_MANY; - } else if ((pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32)) { - dc->base.is_jmp = DISAS_TOO_MANY; - } - dc->base.pc_next = pc_next; + + if (dc->base.is_jmp == DISAS_NEXT) { + if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) { + /* + * If single step mode, we generate only one instruction and + * generate an exception. + * If irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear + * the flag and abort the translation to give the irqs a + * chance to happen. + */ + dc->base.is_jmp = DISAS_TOO_MANY; + } else if (!is_same_page(&dc->base, pc_next)) { + dc->base.is_jmp = DISAS_TOO_MANY; + } + } } static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) @@ -8728,11 +8890,12 @@ static const TranslatorOps i386_tr_ops = { }; /* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc; - translator_loop(&i386_tr_ops, &dc.base, cpu, tb, max_insns); + translator_loop(cpu, tb, max_insns, pc, host_pc, &i386_tr_ops, &dc.base); } void restore_state_to_opc(CPUX86State *env, TranslationBlock *tb, diff --git a/target/i386/tcg/user/excp_helper.c b/target/i386/tcg/user/excp_helper.c index cd507e2a1b..b3bdb7831a 100644 --- a/target/i386/tcg/user/excp_helper.c +++ b/target/i386/tcg/user/excp_helper.c @@ -48,3 +48,10 @@ void x86_cpu_record_sigsegv(CPUState *cs, vaddr addr, cpu_loop_exit_restore(cs, ra); } + +void x86_cpu_record_sigbus(CPUState *cs, vaddr addr, + MMUAccessType access_type, uintptr_t ra) +{ + X86CPU *cpu = X86_CPU(cs); + handle_unaligned_access(&cpu->env, addr, access_type, ra); +} diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index b22a3314b4..8e4969edeb 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -1225,14 +1225,12 @@ static void whpx_translate_cpu_breakpoints( } } - if (breakpoints->breakpoints) { - /* - * Free the previous breakpoint list. This can be optimized by keeping - * it as shadow buffer for the next computation instead of freeing - * it immediately. - */ - g_free(breakpoints->breakpoints); - } + /* + * Free the previous breakpoint list. This can be optimized by keeping + * it as shadow buffer for the next computation instead of freeing + * it immediately. + */ + g_free(breakpoints->breakpoints); breakpoints->breakpoints = new_breakpoints; } diff --git a/target/loongarch/README b/target/loongarch/README index 9f5edd10c8..0b9dc0d40a 100644 --- a/target/loongarch/README +++ b/target/loongarch/README @@ -11,54 +11,7 @@ - System emulation - Mainly emulate a virt 3A5000 board and ls7a bridge that is not exactly the same as the host. - 3A5000 support multiple interrupt cascading while here we just emulate the extioi interrupt - cascading. LS7A1000 host bridge support multiple devices, such as sata, gmac, uart, rtc - and so on. But we just realize the rtc. Others use the qemu common devices. It does not affect - the general use. We also introduced the emulation of devices at docs/system/loongarch/loongson3.rst. - - This version only supports running binary files in ELF format, and does not depend on BIOS and kernel file. - You can compile the test program with 'make & make check-tcg' and run the test case with the following command: - - 1. Install LoongArch cross-tools on X86 machines. - - Download cross-tools. - - wget https://github.com/loongson/build-tools/releases/download/2022.05.29/loongarch64-clfs-5.0-cross-tools-gcc-full.tar.xz - - tar -vxf loongarch64-clfs-5.0-cross-tools-gcc-full.tar.xz -C /opt - - Config cross-tools env. - - . setenv.sh - - setenv.sh: - - #!/bin/sh - set -x - CC_PREFIX=/opt/cross-tools - - export PATH=$CC_PREFIX/bin:$PATH - export LD_LIBRARY_PATH=$CC_PREFIX/lib:$LD_LIBRARY_PATH - export LD_LIBRARY_PATH=$CC_PREFIX/loongarch64-unknown-linux-gnu/lib/:$LD_LIBRARY_PATH - set +x - - 2. Test tests/tcg/multiarch. - - ./configure --disable-rdma --disable-pvrdma --prefix=/usr \ - --target-list="loongarch64-softmmu" \ - --disable-libiscsi --disable-libnfs --disable-libpmem \ - --disable-glusterfs --enable-libusb --enable-usb-redir \ - --disable-opengl --disable-xen --enable-spice --disable-werror \ - --enable-debug --disable-capstone --disable-kvm --enable-profiler - - cd build/ - - make && make check-tcg - - or - - ./build/qemu-system-loongarch64 -machine virt -m 4G -cpu Loongson-3A5000 -smp 1 -kernel build/tests/tcg/loongarch64-softmmu/hello -monitor none -display none -chardev file,path=hello.out,id=output -serial chardev:output + You can reference docs/system/loongarch/loongson3.rst to get the information about system emulation of LoongArch. - Linux-user emulation diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 1c69a76f2b..1722ed2a4d 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -82,6 +82,14 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) env->pc = value; } +static vaddr loongarch_cpu_get_pc(CPUState *cs) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + return env->pc; +} + #ifndef CONFIG_USER_ONLY #include "hw/loongarch/virt.h" @@ -309,7 +317,7 @@ static void loongarch_cpu_synchronize_from_tb(CPUState *cs, LoongArchCPU *cpu = LOONGARCH_CPU(cs); CPULoongArchState *env = &cpu->env; - env->pc = tb->pc; + env->pc = tb_pc(tb); } #endif /* CONFIG_TCG */ @@ -661,6 +669,11 @@ static const struct SysemuCPUOps loongarch_sysemu_ops = { }; #endif +static gchar *loongarch_gdb_arch_name(CPUState *cs) +{ + return g_strdup("loongarch64"); +} + static void loongarch_cpu_class_init(ObjectClass *c, void *data) { LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c); @@ -675,6 +688,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) cc->has_work = loongarch_cpu_has_work; cc->dump_state = loongarch_cpu_dump_state; cc->set_pc = loongarch_cpu_set_pc; + cc->get_pc = loongarch_cpu_get_pc; #ifndef CONFIG_USER_ONLY dc->vmsd = &vmstate_loongarch_cpu; cc->sysemu_ops = &loongarch_sysemu_ops; @@ -683,9 +697,10 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) cc->gdb_read_register = loongarch_cpu_gdb_read_register; cc->gdb_write_register = loongarch_cpu_gdb_write_register; cc->disas_set_info = loongarch_cpu_disas_set_info; - cc->gdb_num_core_regs = 34; + cc->gdb_num_core_regs = 35; cc->gdb_core_xml_file = "loongarch-base64.xml"; cc->gdb_stop_before_watchpoint = true; + cc->gdb_arch_name = loongarch_gdb_arch_name; #ifdef CONFIG_TCG cc->tcg_ops = &loongarch_tcg_ops; diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index a36349df83..dce999aaac 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -47,11 +47,23 @@ FIELD(FCSR0, FLAGS, 16, 5) FIELD(FCSR0, CAUSE, 24, 5) #define GET_FP_CAUSE(REG) FIELD_EX32(REG, FCSR0, CAUSE) -#define SET_FP_CAUSE(REG, V) FIELD_DP32(REG, FCSR0, CAUSE, V) +#define SET_FP_CAUSE(REG, V) \ + do { \ + (REG) = FIELD_DP32(REG, FCSR0, CAUSE, V); \ + } while (0) + #define GET_FP_ENABLES(REG) FIELD_EX32(REG, FCSR0, ENABLES) -#define SET_FP_ENABLES(REG, V) FIELD_DP32(REG, FCSR0, ENABLES, V) +#define SET_FP_ENABLES(REG, V) \ + do { \ + (REG) = FIELD_DP32(REG, FCSR0, ENABLES, V); \ + } while (0) + #define GET_FP_FLAGS(REG) FIELD_EX32(REG, FCSR0, FLAGS) -#define SET_FP_FLAGS(REG, V) FIELD_DP32(REG, FCSR0, FLAGS, V) +#define SET_FP_FLAGS(REG, V) \ + do { \ + (REG) = FIELD_DP32(REG, FCSR0, FLAGS, V); \ + } while (0) + #define UPDATE_FP_FLAGS(REG, V) \ do { \ (REG) |= FIELD_DP32(0, FCSR0, FLAGS, V); \ diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index bd76529219..4b9637210a 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -872,8 +872,8 @@ uint64_t helper_ftint_w_d(CPULoongArchState *env, uint64_t fj) return fd; } -void helper_set_rounding_mode(CPULoongArchState *env, uint32_t fcsr0) +void helper_set_rounding_mode(CPULoongArchState *env) { - set_float_rounding_mode(ieee_rm[(fcsr0 >> FCSR0_RM) & 0x3], + set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3], &env->fp_status); } diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c index 24e126fb2d..a4d1e28e36 100644 --- a/target/loongarch/gdbstub.c +++ b/target/loongarch/gdbstub.c @@ -11,6 +11,24 @@ #include "internals.h" #include "exec/gdbstub.h" +uint64_t read_fcc(CPULoongArchState *env) +{ + uint64_t ret = 0; + + for (int i = 0; i < 8; ++i) { + ret |= (uint64_t)env->cf[i] << (i * 8); + } + + return ret; +} + +void write_fcc(CPULoongArchState *env, uint64_t val) +{ + for (int i = 0; i < 8; ++i) { + env->cf[i] = (val >> (i * 8)) & 1; + } +} + int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { LoongArchCPU *cpu = LOONGARCH_CPU(cs); @@ -19,8 +37,11 @@ int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) if (0 <= n && n < 32) { return gdb_get_regl(mem_buf, env->gpr[n]); } else if (n == 32) { - return gdb_get_regl(mem_buf, env->pc); + /* orig_a0 */ + return gdb_get_regl(mem_buf, 0); } else if (n == 33) { + return gdb_get_regl(mem_buf, env->pc); + } else if (n == 34) { return gdb_get_regl(mem_buf, env->CSR_BADV); } return 0; @@ -36,7 +57,7 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) if (0 <= n && n < 32) { env->gpr[n] = tmp; length = sizeof(target_ulong); - } else if (n == 32) { + } else if (n == 33) { env->pc = tmp; length = sizeof(target_ulong); } @@ -48,9 +69,10 @@ static int loongarch_gdb_get_fpu(CPULoongArchState *env, { if (0 <= n && n < 32) { return gdb_get_reg64(mem_buf, env->fpr[n]); - } else if (32 <= n && n < 40) { - return gdb_get_reg8(mem_buf, env->cf[n - 32]); - } else if (n == 40) { + } else if (n == 32) { + uint64_t val = read_fcc(env); + return gdb_get_reg64(mem_buf, val); + } else if (n == 33) { return gdb_get_reg32(mem_buf, env->fcsr0); } return 0; @@ -64,10 +86,11 @@ static int loongarch_gdb_set_fpu(CPULoongArchState *env, if (0 <= n && n < 32) { env->fpr[n] = ldq_p(mem_buf); length = 8; - } else if (32 <= n && n < 40) { - env->cf[n - 32] = ldub_p(mem_buf); - length = 1; - } else if (n == 40) { + } else if (n == 32) { + uint64_t val = ldq_p(mem_buf); + write_fcc(env, val); + length = 8; + } else if (n == 33) { env->fcsr0 = ldl_p(mem_buf); length = 4; } @@ -77,5 +100,5 @@ static int loongarch_gdb_set_fpu(CPULoongArchState *env, void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs) { gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu, - 41, "loongarch-fpu64.xml", 0); + 41, "loongarch-fpu.xml", 0); } diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index cbbe008f32..9c01823a26 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -91,7 +91,7 @@ DEF_HELPER_2(ftint_w_d, i64, env, i64) DEF_HELPER_2(frint_s, i64, env, i64) DEF_HELPER_2(frint_d, i64, env, i64) -DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32) +DEF_HELPER_FLAGS_1(set_rounding_mode, TCG_CALL_NO_RWG, void, env) DEF_HELPER_1(rdtime_d, i64, env) diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/insn_trans/trans_fmov.c.inc index 24753d4568..5537e3dd35 100644 --- a/target/loongarch/insn_trans/trans_fmov.c.inc +++ b/target/loongarch/insn_trans/trans_fmov.c.inc @@ -60,38 +60,39 @@ static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE); if (mask == UINT32_MAX) { - tcg_gen_extrl_i64_i32(cpu_fcsr0, Rj); + tcg_gen_st32_i64(Rj, cpu_env, offsetof(CPULoongArchState, fcsr0)); } else { + TCGv_i32 fcsr0 = tcg_temp_new_i32(); TCGv_i32 temp = tcg_temp_new_i32(); + tcg_gen_ld_i32(fcsr0, cpu_env, offsetof(CPULoongArchState, fcsr0)); tcg_gen_extrl_i64_i32(temp, Rj); tcg_gen_andi_i32(temp, temp, mask); - tcg_gen_andi_i32(cpu_fcsr0, cpu_fcsr0, ~mask); - tcg_gen_or_i32(cpu_fcsr0, cpu_fcsr0, temp); + tcg_gen_andi_i32(fcsr0, fcsr0, ~mask); + tcg_gen_or_i32(fcsr0, fcsr0, temp); + tcg_gen_st_i32(fcsr0, cpu_env, offsetof(CPULoongArchState, fcsr0)); + tcg_temp_free_i32(temp); - - /* - * Install the new rounding mode to fpu_status, if changed. - * Note that FCSR3 is exactly the rounding mode field. - */ - if (mask != FCSR0_M3) { - return true; - } + tcg_temp_free_i32(fcsr0); } - gen_helper_set_rounding_mode(cpu_env, cpu_fcsr0); + /* + * Install the new rounding mode to fpu_status, if changed. + * Note that FCSR3 is exactly the rounding mode field. + */ + if (mask & FCSR0_M3) { + gen_helper_set_rounding_mode(cpu_env); + } return true; } static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) { - TCGv_i32 temp = tcg_temp_new_i32(); TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); - tcg_gen_andi_i32(temp, cpu_fcsr0, fcsr_mask[a->fcsrs]); - tcg_gen_ext_i32_i64(dest, temp); + tcg_gen_ld32u_i64(dest, cpu_env, offsetof(CPULoongArchState, fcsr0)); + tcg_gen_andi_i64(dest, dest, fcsr_mask[a->fcsrs]); gen_set_gpr(a->rd, dest, EXT_NONE); - tcg_temp_free_i32(temp); return true; } diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index ea227362b6..f01635aed6 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -51,6 +51,9 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); #endif /* !CONFIG_USER_ONLY */ +uint64_t read_fcc(CPULoongArchState *env); +void write_fcc(CPULoongArchState *env, uint64_t val); + int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n); void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs); diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index c9afd11420..95b37ea180 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -22,7 +22,6 @@ /* Global register indices */ TCGv cpu_gpr[32], cpu_pc; static TCGv cpu_lladdr, cpu_llval; -TCGv_i32 cpu_fcsr0; TCGv_i64 cpu_fpr[32]; #include "exec/gen-icount.h" @@ -242,11 +241,13 @@ static const TranslatorOps loongarch_tr_ops = { .disas_log = loongarch_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&loongarch_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, + &loongarch_tr_ops, &ctx.base); } void loongarch_translate_init(void) @@ -266,8 +267,6 @@ void loongarch_translate_init(void) } cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPULoongArchState, pc), "pc"); - cpu_fcsr0 = tcg_global_mem_new_i32(cpu_env, - offsetof(CPULoongArchState, fcsr0), "fcsr0"); cpu_lladdr = tcg_global_mem_new(cpu_env, offsetof(CPULoongArchState, lladdr), "lladdr"); cpu_llval = tcg_global_mem_new(cpu_env, diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 5bbefda575..1e902e1ef0 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -31,6 +31,13 @@ static void m68k_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.pc = value; } +static vaddr m68k_cpu_get_pc(CPUState *cs) +{ + M68kCPU *cpu = M68K_CPU(cs); + + return cpu->env.pc; +} + static bool m68k_cpu_has_work(CPUState *cs) { return cs->interrupt_request & CPU_INTERRUPT_HARD; @@ -38,12 +45,12 @@ static bool m68k_cpu_has_work(CPUState *cs) static void m68k_set_feature(CPUM68KState *env, int feature) { - env->features |= (1u << feature); + env->features |= BIT_ULL(feature); } static void m68k_unset_feature(CPUM68KState *env, int feature) { - env->features &= (-1u - (1u << feature)); + env->features &= ~BIT_ULL(feature); } static void m68k_cpu_reset(DeviceState *dev) @@ -102,6 +109,7 @@ static void m5206_cpu_initfn(Object *obj) CPUM68KState *env = &cpu->env; m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); + m68k_set_feature(env, M68K_FEATURE_MOVEFROMSR_PRIV); } /* Base feature set, including isns. for m68k family */ @@ -110,7 +118,7 @@ static void m68000_cpu_initfn(Object *obj) M68kCPU *cpu = M68K_CPU(obj); CPUM68KState *env = &cpu->env; - m68k_set_feature(env, M68K_FEATURE_M68000); + m68k_set_feature(env, M68K_FEATURE_M68K); m68k_set_feature(env, M68K_FEATURE_USP); m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); m68k_set_feature(env, M68K_FEATURE_MOVEP); @@ -129,6 +137,7 @@ static void m68010_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_RTD); m68k_set_feature(env, M68K_FEATURE_BKPT); m68k_set_feature(env, M68K_FEATURE_MOVEC); + m68k_set_feature(env, M68K_FEATURE_MOVEFROMSR_PRIV); } /* @@ -241,6 +250,7 @@ static void m5208_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_BRAL); m68k_set_feature(env, M68K_FEATURE_CF_EMAC); m68k_set_feature(env, M68K_FEATURE_USP); + m68k_set_feature(env, M68K_FEATURE_MOVEFROMSR_PRIV); } static void cfv4e_cpu_initfn(Object *obj) @@ -254,6 +264,7 @@ static void cfv4e_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_CF_FPU); m68k_set_feature(env, M68K_FEATURE_CF_EMAC); m68k_set_feature(env, M68K_FEATURE_USP); + m68k_set_feature(env, M68K_FEATURE_MOVEFROMSR_PRIV); } static void any_cpu_initfn(Object *obj) @@ -275,6 +286,7 @@ static void any_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_USP); m68k_set_feature(env, M68K_FEATURE_EXT_FULL); m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); + m68k_set_feature(env, M68K_FEATURE_MOVEFROMSR_PRIV); } static void m68k_cpu_realizefn(DeviceState *dev, Error **errp) @@ -535,6 +547,7 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) cc->has_work = m68k_cpu_has_work; cc->dump_state = m68k_cpu_dump_state; cc->set_pc = m68k_cpu_set_pc; + cc->get_pc = m68k_cpu_get_pc; cc->gdb_read_register = m68k_cpu_gdb_read_register; cc->gdb_write_register = m68k_cpu_gdb_write_register; #if defined(CONFIG_SOFTMMU) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 4d8f48e8c7..3a9cfe2f33 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -154,7 +154,7 @@ typedef struct CPUArchState { struct {} end_reset_fields; /* Fields from here on are preserved across CPU reset. */ - uint32_t features; + uint64_t features; } CPUM68KState; /* @@ -480,8 +480,9 @@ void do_m68k_semihosting(CPUM68KState *env, int nr); */ enum m68k_features { - /* Base m68k instruction set */ - M68K_FEATURE_M68000, + /* Base Motorola CPU set (not set for Coldfire CPUs) */ + M68K_FEATURE_M68K, + /* Motorola CPU feature sets */ M68K_FEATURE_M68010, M68K_FEATURE_M68020, M68K_FEATURE_M68030, @@ -536,11 +537,13 @@ enum m68k_features { M68K_FEATURE_UNALIGNED_DATA, /* TRAPcc insn. (680[2346]0, and CPU32) */ M68K_FEATURE_TRAPCC, + /* MOVE from SR privileged (from 68010) */ + M68K_FEATURE_MOVEFROMSR_PRIV, }; -static inline int m68k_feature(CPUM68KState *env, int feature) +static inline bool m68k_feature(CPUM68KState *env, int feature) { - return (env->features & (1u << feature)) != 0; + return (env->features & BIT_ULL(feature)) != 0; } void m68k_cpu_list(void); diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 5728e48585..4621cf2402 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -460,7 +460,7 @@ void m68k_switch_sp(CPUM68KState *env) int new_sp; env->sp[env->current_sp] = env->aregs[7]; - if (m68k_feature(env, M68K_FEATURE_M68000)) { + if (m68k_feature(env, M68K_FEATURE_M68K)) { if (env->sr & SR_S) { /* SR:Master-Mode bit unimplemented then ISP is not available */ if (!m68k_feature(env, M68K_FEATURE_MSP) || env->sr & SR_M) { diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c index d0697ddbd1..87b1314925 100644 --- a/target/m68k/m68k-semi.c +++ b/target/m68k/m68k-semi.c @@ -21,6 +21,7 @@ #include "cpu.h" #include "exec/gdbstub.h" +#include "semihosting/syscalls.h" #include "semihosting/softmmu-uaccess.h" #include "hw/boards.h" #include "qemu/log.h" @@ -40,54 +41,33 @@ #define HOSTED_ISATTY 12 #define HOSTED_SYSTEM 13 -static int translate_openflags(int flags) +static int host_to_gdb_errno(int err) { - int hf; - - if (flags & GDB_O_WRONLY) - hf = O_WRONLY; - else if (flags & GDB_O_RDWR) - hf = O_RDWR; - else - hf = O_RDONLY; - - if (flags & GDB_O_APPEND) hf |= O_APPEND; - if (flags & GDB_O_CREAT) hf |= O_CREAT; - if (flags & GDB_O_TRUNC) hf |= O_TRUNC; - if (flags & GDB_O_EXCL) hf |= O_EXCL; - - return hf; -} - -static void translate_stat(CPUM68KState *env, target_ulong addr, struct stat *s) -{ - struct gdb_stat *p; - - p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0); - if (!p) { - /* FIXME - should this return an error code? */ - return; +#define E(X) case E##X: return GDB_E##X + switch (err) { + E(PERM); + E(NOENT); + E(INTR); + E(BADF); + E(ACCES); + E(FAULT); + E(BUSY); + E(EXIST); + E(NODEV); + E(NOTDIR); + E(ISDIR); + E(INVAL); + E(NFILE); + E(MFILE); + E(FBIG); + E(NOSPC); + E(SPIPE); + E(ROFS); + E(NAMETOOLONG); + default: + return GDB_EUNKNOWN; } - p->gdb_st_dev = cpu_to_be32(s->st_dev); - p->gdb_st_ino = cpu_to_be32(s->st_ino); - p->gdb_st_mode = cpu_to_be32(s->st_mode); - p->gdb_st_nlink = cpu_to_be32(s->st_nlink); - p->gdb_st_uid = cpu_to_be32(s->st_uid); - p->gdb_st_gid = cpu_to_be32(s->st_gid); - p->gdb_st_rdev = cpu_to_be32(s->st_rdev); - p->gdb_st_size = cpu_to_be64(s->st_size); -#ifdef _WIN32 - /* Windows stat is missing some fields. */ - p->gdb_st_blksize = 0; - p->gdb_st_blocks = 0; -#else - p->gdb_st_blksize = cpu_to_be64(s->st_blksize); - p->gdb_st_blocks = cpu_to_be64(s->st_blocks); -#endif - p->gdb_st_atime = cpu_to_be32(s->st_atime); - p->gdb_st_mtime = cpu_to_be32(s->st_mtime); - p->gdb_st_ctime = cpu_to_be32(s->st_ctime); - unlock_user(p, addr, sizeof(struct gdb_stat)); +#undef E } static void m68k_semi_u32_cb(CPUState *cs, uint64_t ret, int err) @@ -97,7 +77,7 @@ static void m68k_semi_u32_cb(CPUState *cs, uint64_t ret, int err) target_ulong args = env->dregs[1]; if (put_user_u32(ret, args) || - put_user_u32(err, args + 4)) { + put_user_u32(host_to_gdb_errno(err), args + 4)) { /* * The m68k semihosting ABI does not provide any way to report this * error to the guest, so the best we can do is log it in qemu. @@ -116,7 +96,7 @@ static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err) target_ulong args = env->dregs[1]; if (put_user_u32(ret >> 32, args) || put_user_u32(ret, args + 4) || - put_user_u32(err, args + 8)) { + put_user_u32(host_to_gdb_errno(err), args + 8)) { /* No way to report this via m68k semihosting ABI; just log it */ qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value " "discarded because argument block not writable\n"); @@ -129,248 +109,109 @@ static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err) */ #define GET_ARG(n) do { \ if (get_user_ual(arg ## n, args + (n) * 4)) { \ - result = -1; \ - errno = EFAULT; \ goto failed; \ } \ } while (0) +#define GET_ARG64(n) do { \ + if (get_user_ual(arg ## n, args + (n) * 4)) { \ + goto failed64; \ + } \ +} while (0) + + void do_m68k_semihosting(CPUM68KState *env, int nr) { CPUState *cs = env_cpu(env); uint32_t args; target_ulong arg0, arg1, arg2, arg3; - void *p; - void *q; - uint32_t len; - uint32_t result; args = env->dregs[1]; switch (nr) { case HOSTED_EXIT: gdb_exit(env->dregs[0]); exit(env->dregs[0]); + case HOSTED_OPEN: GET_ARG(0); GET_ARG(1); GET_ARG(2); GET_ARG(3); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "open,%s,%x,%x", arg0, (int)arg1, - arg2, arg3); - return; - } else { - p = lock_user_string(arg0); - if (!p) { - /* FIXME - check error code? */ - result = -1; - } else { - result = open(p, translate_openflags(arg2), arg3); - unlock_user(p, arg0, 0); - } - } + semihost_sys_open(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3); break; + case HOSTED_CLOSE: - { - /* Ignore attempts to close stdin/out/err. */ - GET_ARG(0); - int fd = arg0; - if (fd > 2) { - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "close,%x", arg0); - return; - } else { - result = close(fd); - } - } else { - result = 0; - } - break; - } + GET_ARG(0); + semihost_sys_close(cs, m68k_semi_u32_cb, arg0); + break; + case HOSTED_READ: GET_ARG(0); GET_ARG(1); GET_ARG(2); - len = arg2; - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "read,%x,%x,%x", - arg0, arg1, len); - return; - } else { - p = lock_user(VERIFY_WRITE, arg1, len, 0); - if (!p) { - /* FIXME - check error code? */ - result = -1; - } else { - result = read(arg0, p, len); - unlock_user(p, arg1, len); - } - } + semihost_sys_read(cs, m68k_semi_u32_cb, arg0, arg1, arg2); break; + case HOSTED_WRITE: GET_ARG(0); GET_ARG(1); GET_ARG(2); - len = arg2; - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "write,%x,%x,%x", - arg0, arg1, len); - return; - } else { - p = lock_user(VERIFY_READ, arg1, len, 1); - if (!p) { - /* FIXME - check error code? */ - result = -1; - } else { - result = write(arg0, p, len); - unlock_user(p, arg0, 0); - } - } + semihost_sys_write(cs, m68k_semi_u32_cb, arg0, arg1, arg2); break; + case HOSTED_LSEEK: - { - uint64_t off; - GET_ARG(0); - GET_ARG(1); - GET_ARG(2); - GET_ARG(3); - off = (uint32_t)arg2 | ((uint64_t)arg1 << 32); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u64_cb, "fseek,%x,%lx,%x", - arg0, off, arg3); - } else { - off = lseek(arg0, off, arg3); - m68k_semi_u64_cb(cs, off, errno); - } - return; - } + GET_ARG64(0); + GET_ARG64(1); + GET_ARG64(2); + GET_ARG64(3); + semihost_sys_lseek(cs, m68k_semi_u64_cb, arg0, + deposit64(arg2, arg1, 32, 32), arg3); + break; + case HOSTED_RENAME: GET_ARG(0); GET_ARG(1); GET_ARG(2); GET_ARG(3); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "rename,%s,%s", - arg0, (int)arg1, arg2, (int)arg3); - return; - } else { - p = lock_user_string(arg0); - q = lock_user_string(arg2); - if (!p || !q) { - /* FIXME - check error code? */ - result = -1; - } else { - result = rename(p, q); - } - unlock_user(p, arg0, 0); - unlock_user(q, arg2, 0); - } + semihost_sys_rename(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3); break; + case HOSTED_UNLINK: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "unlink,%s", - arg0, (int)arg1); - return; - } else { - p = lock_user_string(arg0); - if (!p) { - /* FIXME - check error code? */ - result = -1; - } else { - result = unlink(p); - unlock_user(p, arg0, 0); - } - } + semihost_sys_remove(cs, m68k_semi_u32_cb, arg0, arg1); break; + case HOSTED_STAT: GET_ARG(0); GET_ARG(1); GET_ARG(2); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "stat,%s,%x", - arg0, (int)arg1, arg2); - return; - } else { - struct stat s; - p = lock_user_string(arg0); - if (!p) { - /* FIXME - check error code? */ - result = -1; - } else { - result = stat(p, &s); - unlock_user(p, arg0, 0); - } - if (result == 0) { - translate_stat(env, arg2, &s); - } - } + semihost_sys_stat(cs, m68k_semi_u32_cb, arg0, arg1, arg2); break; + case HOSTED_FSTAT: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "fstat,%x,%x", - arg0, arg1); - return; - } else { - struct stat s; - result = fstat(arg0, &s); - if (result == 0) { - translate_stat(env, arg1, &s); - } - } + semihost_sys_fstat(cs, m68k_semi_u32_cb, arg0, arg1); break; + case HOSTED_GETTIMEOFDAY: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "gettimeofday,%x,%x", - arg0, arg1); - return; - } else { - struct gdb_timeval *p; - int64_t rt = g_get_real_time(); - p = lock_user(VERIFY_WRITE, arg0, sizeof(struct gdb_timeval), 0); - if (!p) { - /* FIXME - check error code? */ - result = -1; - } else { - result = 0; - p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC); - p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC); - unlock_user(p, arg0, sizeof(struct gdb_timeval)); - } - } + semihost_sys_gettimeofday(cs, m68k_semi_u32_cb, arg0, arg1); break; + case HOSTED_ISATTY: GET_ARG(0); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "isatty,%x", arg0); - return; - } else { - result = isatty(arg0); - } + semihost_sys_isatty(cs, m68k_semi_u32_cb, arg0); break; + case HOSTED_SYSTEM: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_u32_cb, "system,%s", - arg0, (int)arg1); - return; - } else { - p = lock_user_string(arg0); - if (!p) { - /* FIXME - check error code? */ - result = -1; - } else { - result = system(p); - unlock_user(p, arg0, 0); - } - } + semihost_sys_system(cs, m68k_semi_u32_cb, arg0, arg1); break; + case HOSTED_INIT_SIM: /* * FIXME: This is wrong for boards where RAM does not start at @@ -379,10 +220,15 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) env->dregs[1] = current_machine->ram_size; env->aregs[7] = current_machine->ram_size; return; + default: cpu_abort(env_cpu(env), "Unsupported semihosting syscall %d\n", nr); - result = 0; + + failed: + m68k_semi_u32_cb(cs, -1, EFAULT); + break; + failed64: + m68k_semi_u64_cb(cs, -1, EFAULT); + break; } -failed: - m68k_semi_u32_cb(cs, result, errno); } diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index d9937ca8dc..5da176d642 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -203,8 +203,7 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw) cf_rte(env); return; case EXCP_HALT_INSN: - if (semihosting_enabled() - && (env->sr & SR_S) != 0 + if (semihosting_enabled((env->sr & SR_S) == 0) && (env->pc & 3) == 0 && cpu_lduw_code(env, env->pc - 4) == 0x4e71 && cpu_ldl_code(env, env->pc) == 0x4e7bf000) { @@ -433,7 +432,7 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw) static void do_interrupt_all(CPUM68KState *env, int is_hw) { - if (m68k_feature(env, M68K_FEATURE_M68000)) { + if (m68k_feature(env, M68K_FEATURE_M68K)) { m68k_interrupt_all(env, is_hw); return; } diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 8f3c298ad0..9df17aa4b2 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -471,7 +471,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) return NULL_QREG; - if (m68k_feature(s->env, M68K_FEATURE_M68000) && + if (m68k_feature(s->env, M68K_FEATURE_M68K) && !m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX)) { ext &= ~(3 << 9); } @@ -804,7 +804,7 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s, reg = get_areg(s, reg0); tmp = mark_to_release(s, tcg_temp_new()); if (reg0 == 7 && opsize == OS_BYTE && - m68k_feature(s->env, M68K_FEATURE_M68000)) { + m68k_feature(s->env, M68K_FEATURE_M68K)) { tcg_gen_subi_i32(tmp, reg, 2); } else { tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize)); @@ -888,7 +888,7 @@ static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0, if (what == EA_STORE || !addrp) { TCGv tmp = tcg_temp_new(); if (reg0 == 7 && opsize == OS_BYTE && - m68k_feature(s->env, M68K_FEATURE_M68000)) { + m68k_feature(s->env, M68K_FEATURE_M68K)) { tcg_gen_addi_i32(tmp, reg, 2); } else { tcg_gen_addi_i32(tmp, reg, opsize_bytes(opsize)); @@ -2210,7 +2210,7 @@ DISAS_INSN(bitop_im) op = (insn >> 6) & 3; bitnum = read_im16(env, s); - if (m68k_feature(s->env, M68K_FEATURE_M68000)) { + if (m68k_feature(s->env, M68K_FEATURE_M68K)) { if (bitnum & 0xfe00) { disas_undef(env, s, insn); return; @@ -2285,9 +2285,9 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0); tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0); } else { - TCGv sr = tcg_const_i32(val); - gen_helper_set_sr(cpu_env, sr); - tcg_temp_free(sr); + /* Must writeback before changing security state. */ + do_writebacks(s); + gen_helper_set_sr(cpu_env, tcg_constant_i32(val)); } set_cc_op(s, CC_OP_FLAGS); } @@ -2297,6 +2297,8 @@ static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only) if (ccr_only) { gen_helper_set_ccr(cpu_env, val); } else { + /* Must writeback before changing security state. */ + do_writebacks(s); gen_helper_set_sr(cpu_env, val); } set_cc_op(s, CC_OP_FLAGS); @@ -2373,6 +2375,7 @@ DISAS_INSN(arith_im) tcg_gen_or_i32(dest, src1, im); if (with_SR) { gen_set_sr(s, dest, opsize == OS_BYTE); + gen_exit_tb(s); } else { DEST_EA(env, insn, opsize, dest, &addr); gen_logic_cc(s, dest, opsize); @@ -2382,6 +2385,7 @@ DISAS_INSN(arith_im) tcg_gen_and_i32(dest, src1, im); if (with_SR) { gen_set_sr(s, dest, opsize == OS_BYTE); + gen_exit_tb(s); } else { DEST_EA(env, insn, opsize, dest, &addr); gen_logic_cc(s, dest, opsize); @@ -2405,6 +2409,7 @@ DISAS_INSN(arith_im) tcg_gen_xor_i32(dest, src1, im); if (with_SR) { gen_set_sr(s, dest, opsize == OS_BYTE); + gen_exit_tb(s); } else { DEST_EA(env, insn, opsize, dest, &addr); gen_logic_cc(s, dest, opsize); @@ -2825,19 +2830,39 @@ DISAS_INSN(illegal) gen_exception(s, s->base.pc_next, EXCP_ILLEGAL); } -/* ??? This should be atomic. */ DISAS_INSN(tas) { - TCGv dest; - TCGv src1; - TCGv addr; + int mode = extract32(insn, 3, 3); + int reg0 = REG(insn, 0); - dest = tcg_temp_new(); - SRC_EA(env, src1, OS_BYTE, 1, &addr); - gen_logic_cc(s, src1, OS_BYTE); - tcg_gen_ori_i32(dest, src1, 0x80); - DEST_EA(env, insn, OS_BYTE, dest, &addr); - tcg_temp_free(dest); + if (mode == 0) { + /* data register direct */ + TCGv dest = cpu_dregs[reg0]; + gen_logic_cc(s, dest, OS_BYTE); + tcg_gen_ori_tl(dest, dest, 0x80); + } else { + TCGv src1, addr; + + addr = gen_lea_mode(env, s, mode, reg0, OS_BYTE); + if (IS_NULL_QREG(addr)) { + gen_addr_fault(s); + return; + } + src1 = tcg_temp_new(); + tcg_gen_atomic_fetch_or_tl(src1, addr, tcg_constant_tl(0x80), + IS_USER(s), MO_SB); + gen_logic_cc(s, src1, OS_BYTE); + tcg_temp_free(src1); + + switch (mode) { + case 3: /* Indirect postincrement. */ + tcg_gen_addi_i32(AREG(insn, 0), addr, 1); + break; + case 4: /* Indirect predecrememnt. */ + tcg_gen_mov_i32(AREG(insn, 0), addr); + break; + } + } } DISAS_INSN(mull) @@ -2875,7 +2900,7 @@ DISAS_INSN(mull) return; } SRC_EA(env, src1, OS_LONG, 0, NULL); - if (m68k_feature(s->env, M68K_FEATURE_M68000)) { + if (m68k_feature(s->env, M68K_FEATURE_M68K)) { tcg_gen_movi_i32(QREG_CC_C, 0); if (sign) { tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12)); @@ -3470,7 +3495,7 @@ static inline void shift_im(DisasContext *s, uint16_t insn, int opsize) * while M68000 sets if the most significant bit is changed at * any time during the shift operation. */ - if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) { + if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) { /* if shift count >= bits, V is (reg != 0) */ if (count >= bits) { tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, reg, QREG_CC_V); @@ -3554,7 +3579,7 @@ static inline void shift_reg(DisasContext *s, uint16_t insn, int opsize) * int64_t t = (int64_t)(intN_t)reg << count; * V = ((s ^ t) & (-1 << (bits - 1))) != 0 */ - if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) { + if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) { TCGv_i64 tt = tcg_const_i64(32); /* if shift is greater than 32, use 32 */ tcg_gen_movcond_i64(TCG_COND_GT, s64, s64, tt, tt, s64); @@ -3647,7 +3672,7 @@ DISAS_INSN(shift_mem) * while M68000 sets if the most significant bit is changed at * any time during the shift operation */ - if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) { + if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) { src = gen_extend(s, src, OS_WORD, 1); tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src); } @@ -4592,13 +4617,14 @@ DISAS_INSN(strldsr) } gen_push(s, gen_get_sr(s)); gen_set_sr_im(s, ext, 0); + gen_exit_tb(s); } DISAS_INSN(move_from_sr) { TCGv sr; - if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) { + if (IS_USER(s) && m68k_feature(env, M68K_FEATURE_MOVEFROMSR_PRIV)) { gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE); return; } @@ -5892,8 +5918,10 @@ DISAS_INSN(from_mext) DISAS_INSN(macsr_to_ccr) { TCGv tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_MACSR, 0xf); - gen_helper_set_sr(cpu_env, tmp); + + /* Note that X and C are always cleared. */ + tcg_gen_andi_i32(tmp, QREG_MACSR, CCF_N | CCF_Z | CCF_V); + gen_helper_set_ccr(cpu_env, tmp); tcg_temp_free(tmp); set_cc_op(s, CC_OP_FLAGS); } @@ -6011,7 +6039,7 @@ void register_m68k_insns (CPUM68KState *env) } while(0) BASE(undef, 0000, 0000); INSN(arith_im, 0080, fff8, CF_ISA_A); - INSN(arith_im, 0000, ff00, M68000); + INSN(arith_im, 0000, ff00, M68K); INSN(chk2, 00c0, f9c0, CHK2); INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC); BASE(bitop_reg, 0100, f1c0); @@ -6020,26 +6048,26 @@ void register_m68k_insns (CPUM68KState *env) BASE(bitop_reg, 01c0, f1c0); INSN(movep, 0108, f138, MOVEP); INSN(arith_im, 0280, fff8, CF_ISA_A); - INSN(arith_im, 0200, ff00, M68000); - INSN(undef, 02c0, ffc0, M68000); + INSN(arith_im, 0200, ff00, M68K); + INSN(undef, 02c0, ffc0, M68K); INSN(byterev, 02c0, fff8, CF_ISA_APLUSC); INSN(arith_im, 0480, fff8, CF_ISA_A); - INSN(arith_im, 0400, ff00, M68000); - INSN(undef, 04c0, ffc0, M68000); - INSN(arith_im, 0600, ff00, M68000); - INSN(undef, 06c0, ffc0, M68000); + INSN(arith_im, 0400, ff00, M68K); + INSN(undef, 04c0, ffc0, M68K); + INSN(arith_im, 0600, ff00, M68K); + INSN(undef, 06c0, ffc0, M68K); INSN(ff1, 04c0, fff8, CF_ISA_APLUSC); INSN(arith_im, 0680, fff8, CF_ISA_A); INSN(arith_im, 0c00, ff38, CF_ISA_A); - INSN(arith_im, 0c00, ff00, M68000); + INSN(arith_im, 0c00, ff00, M68K); BASE(bitop_im, 0800, ffc0); BASE(bitop_im, 0840, ffc0); BASE(bitop_im, 0880, ffc0); BASE(bitop_im, 08c0, ffc0); INSN(arith_im, 0a80, fff8, CF_ISA_A); - INSN(arith_im, 0a00, ff00, M68000); + INSN(arith_im, 0a00, ff00, M68K); #if defined(CONFIG_SOFTMMU) - INSN(moves, 0e00, ff00, M68000); + INSN(moves, 0e00, ff00, M68K); #endif INSN(cas, 0ac0, ffc0, CAS); INSN(cas, 0cc0, ffc0, CAS); @@ -6049,44 +6077,44 @@ void register_m68k_insns (CPUM68KState *env) BASE(move, 1000, f000); BASE(move, 2000, f000); BASE(move, 3000, f000); - INSN(chk, 4000, f040, M68000); + INSN(chk, 4000, f040, M68K); INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC); INSN(negx, 4080, fff8, CF_ISA_A); - INSN(negx, 4000, ff00, M68000); - INSN(undef, 40c0, ffc0, M68000); + INSN(negx, 4000, ff00, M68K); + INSN(undef, 40c0, ffc0, M68K); INSN(move_from_sr, 40c0, fff8, CF_ISA_A); - INSN(move_from_sr, 40c0, ffc0, M68000); + INSN(move_from_sr, 40c0, ffc0, M68K); BASE(lea, 41c0, f1c0); BASE(clr, 4200, ff00); BASE(undef, 42c0, ffc0); INSN(move_from_ccr, 42c0, fff8, CF_ISA_A); - INSN(move_from_ccr, 42c0, ffc0, M68000); + INSN(move_from_ccr, 42c0, ffc0, M68K); INSN(neg, 4480, fff8, CF_ISA_A); - INSN(neg, 4400, ff00, M68000); - INSN(undef, 44c0, ffc0, M68000); + INSN(neg, 4400, ff00, M68K); + INSN(undef, 44c0, ffc0, M68K); BASE(move_to_ccr, 44c0, ffc0); INSN(not, 4680, fff8, CF_ISA_A); - INSN(not, 4600, ff00, M68000); + INSN(not, 4600, ff00, M68K); #if defined(CONFIG_SOFTMMU) BASE(move_to_sr, 46c0, ffc0); #endif - INSN(nbcd, 4800, ffc0, M68000); - INSN(linkl, 4808, fff8, M68000); + INSN(nbcd, 4800, ffc0, M68K); + INSN(linkl, 4808, fff8, M68K); BASE(pea, 4840, ffc0); BASE(swap, 4840, fff8); INSN(bkpt, 4848, fff8, BKPT); INSN(movem, 48d0, fbf8, CF_ISA_A); INSN(movem, 48e8, fbf8, CF_ISA_A); - INSN(movem, 4880, fb80, M68000); + INSN(movem, 4880, fb80, M68K); BASE(ext, 4880, fff8); BASE(ext, 48c0, fff8); BASE(ext, 49c0, fff8); BASE(tst, 4a00, ff00); INSN(tas, 4ac0, ffc0, CF_ISA_B); - INSN(tas, 4ac0, ffc0, M68000); + INSN(tas, 4ac0, ffc0, M68K); #if defined(CONFIG_SOFTMMU) INSN(halt, 4ac8, ffff, CF_ISA_A); - INSN(halt, 4ac8, ffff, M68060); + INSN(halt, 4ac8, ffff, M68K); #endif INSN(pulse, 4acc, ffff, CF_ISA_A); BASE(illegal, 4afc, ffff); @@ -6101,7 +6129,7 @@ void register_m68k_insns (CPUM68KState *env) #if defined(CONFIG_SOFTMMU) INSN(move_to_usp, 4e60, fff8, USP); INSN(move_from_usp, 4e68, fff8, USP); - INSN(reset, 4e70, ffff, M68000); + INSN(reset, 4e70, ffff, M68K); BASE(stop, 4e72, ffff); BASE(rte, 4e73, ffff); INSN(cf_movec, 4e7b, ffff, CF_ISA_A); @@ -6110,15 +6138,15 @@ void register_m68k_insns (CPUM68KState *env) BASE(nop, 4e71, ffff); INSN(rtd, 4e74, ffff, RTD); BASE(rts, 4e75, ffff); - INSN(trapv, 4e76, ffff, M68000); - INSN(rtr, 4e77, ffff, M68000); + INSN(trapv, 4e76, ffff, M68K); + INSN(rtr, 4e77, ffff, M68K); BASE(jump, 4e80, ffc0); BASE(jump, 4ec0, ffc0); - INSN(addsubq, 5000, f080, M68000); + INSN(addsubq, 5000, f080, M68K); BASE(addsubq, 5080, f0c0); INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */ - INSN(scc, 50c0, f0c0, M68000); /* Scc.B */ - INSN(dbcc, 50c8, f0f8, M68000); + INSN(scc, 50c0, f0c0, M68K); /* Scc.B */ + INSN(dbcc, 50c8, f0f8, M68K); INSN(trapcc, 50fa, f0fe, TRAPCC); /* opmode 010, 011 */ INSN(trapcc, 50fc, f0ff, TRAPCC); /* opmode 100 */ INSN(trapcc, 51fa, fffe, CF_ISA_A); /* TPF (trapf) opmode 010, 011 */ @@ -6137,15 +6165,15 @@ void register_m68k_insns (CPUM68KState *env) INSN(mvzs, 7100, f100, CF_ISA_B); BASE(or, 8000, f000); BASE(divw, 80c0, f0c0); - INSN(sbcd_reg, 8100, f1f8, M68000); - INSN(sbcd_mem, 8108, f1f8, M68000); + INSN(sbcd_reg, 8100, f1f8, M68K); + INSN(sbcd_mem, 8108, f1f8, M68K); BASE(addsub, 9000, f000); INSN(undef, 90c0, f0c0, CF_ISA_A); INSN(subx_reg, 9180, f1f8, CF_ISA_A); - INSN(subx_reg, 9100, f138, M68000); - INSN(subx_mem, 9108, f138, M68000); + INSN(subx_reg, 9100, f138, M68K); + INSN(subx_mem, 9108, f138, M68K); INSN(suba, 91c0, f1c0, CF_ISA_A); - INSN(suba, 90c0, f0c0, M68000); + INSN(suba, 90c0, f0c0, M68K); BASE(undef_mac, a000, f000); INSN(mac, a000, f100, CF_EMAC); @@ -6166,41 +6194,41 @@ void register_m68k_insns (CPUM68KState *env) INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */ INSN(cmp, b080, f1c0, CF_ISA_A); INSN(cmpa, b1c0, f1c0, CF_ISA_A); - INSN(cmp, b000, f100, M68000); - INSN(eor, b100, f100, M68000); - INSN(cmpm, b108, f138, M68000); - INSN(cmpa, b0c0, f0c0, M68000); + INSN(cmp, b000, f100, M68K); + INSN(eor, b100, f100, M68K); + INSN(cmpm, b108, f138, M68K); + INSN(cmpa, b0c0, f0c0, M68K); INSN(eor, b180, f1c0, CF_ISA_A); BASE(and, c000, f000); - INSN(exg_dd, c140, f1f8, M68000); - INSN(exg_aa, c148, f1f8, M68000); - INSN(exg_da, c188, f1f8, M68000); + INSN(exg_dd, c140, f1f8, M68K); + INSN(exg_aa, c148, f1f8, M68K); + INSN(exg_da, c188, f1f8, M68K); BASE(mulw, c0c0, f0c0); - INSN(abcd_reg, c100, f1f8, M68000); - INSN(abcd_mem, c108, f1f8, M68000); + INSN(abcd_reg, c100, f1f8, M68K); + INSN(abcd_mem, c108, f1f8, M68K); BASE(addsub, d000, f000); INSN(undef, d0c0, f0c0, CF_ISA_A); INSN(addx_reg, d180, f1f8, CF_ISA_A); - INSN(addx_reg, d100, f138, M68000); - INSN(addx_mem, d108, f138, M68000); + INSN(addx_reg, d100, f138, M68K); + INSN(addx_mem, d108, f138, M68K); INSN(adda, d1c0, f1c0, CF_ISA_A); - INSN(adda, d0c0, f0c0, M68000); + INSN(adda, d0c0, f0c0, M68K); INSN(shift_im, e080, f0f0, CF_ISA_A); INSN(shift_reg, e0a0, f0f0, CF_ISA_A); - INSN(shift8_im, e000, f0f0, M68000); - INSN(shift16_im, e040, f0f0, M68000); - INSN(shift_im, e080, f0f0, M68000); - INSN(shift8_reg, e020, f0f0, M68000); - INSN(shift16_reg, e060, f0f0, M68000); - INSN(shift_reg, e0a0, f0f0, M68000); - INSN(shift_mem, e0c0, fcc0, M68000); - INSN(rotate_im, e090, f0f0, M68000); - INSN(rotate8_im, e010, f0f0, M68000); - INSN(rotate16_im, e050, f0f0, M68000); - INSN(rotate_reg, e0b0, f0f0, M68000); - INSN(rotate8_reg, e030, f0f0, M68000); - INSN(rotate16_reg, e070, f0f0, M68000); - INSN(rotate_mem, e4c0, fcc0, M68000); + INSN(shift8_im, e000, f0f0, M68K); + INSN(shift16_im, e040, f0f0, M68K); + INSN(shift_im, e080, f0f0, M68K); + INSN(shift8_reg, e020, f0f0, M68K); + INSN(shift16_reg, e060, f0f0, M68K); + INSN(shift_reg, e0a0, f0f0, M68K); + INSN(shift_mem, e0c0, fcc0, M68K); + INSN(rotate_im, e090, f0f0, M68K); + INSN(rotate8_im, e010, f0f0, M68K); + INSN(rotate16_im, e050, f0f0, M68K); + INSN(rotate_reg, e0b0, f0f0, M68K); + INSN(rotate8_reg, e030, f0f0, M68K); + INSN(rotate16_reg, e070, f0f0, M68K); + INSN(rotate_mem, e4c0, fcc0, M68K); INSN(bfext_mem, e9c0, fdc0, BITFIELD); /* bfextu & bfexts */ INSN(bfext_reg, e9c0, fdf8, BITFIELD); INSN(bfins_mem, efc0, ffc0, BITFIELD); @@ -6361,10 +6389,11 @@ static const TranslatorOps m68k_tr_ops = { .disas_log = m68k_tr_disas_log, }; -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc; - translator_loop(&m68k_tr_ops, &dc.base, cpu, tb, max_insns); + translator_loop(cpu, tb, max_insns, pc, host_pc, &m68k_tr_ops, &dc.base); } static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index aed200dcff..c10b8ac029 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -84,12 +84,19 @@ static void mb_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.iflags = 0; } +static vaddr mb_cpu_get_pc(CPUState *cs) +{ + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + + return cpu->env.pc; +} + static void mb_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); - cpu->env.pc = tb->pc; + cpu->env.pc = tb_pc(tb); cpu->env.iflags = tb->flags & IFLAGS_TB_MASK; } @@ -391,6 +398,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) cc->dump_state = mb_cpu_dump_state; cc->set_pc = mb_cpu_set_pc; + cc->get_pc = mb_cpu_get_pc; cc->gdb_read_register = mb_cpu_gdb_read_register; cc->gdb_write_register = mb_cpu_gdb_write_register; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index bf01384d33..c5546f93aa 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1849,10 +1849,11 @@ static const TranslatorOps mb_tr_ops = { .disas_log = mb_tr_disas_log, }; -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc; - translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); + translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base); } void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index c15c955367..da58eb8892 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -128,6 +128,13 @@ static void mips_cpu_set_pc(CPUState *cs, vaddr value) mips_env_set_pc(&cpu->env, value); } +static vaddr mips_cpu_get_pc(CPUState *cs) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + + return cpu->env.active_tc.PC; +} + static bool mips_cpu_has_work(CPUState *cs) { MIPSCPU *cpu = MIPS_CPU(cs); @@ -557,6 +564,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) cc->has_work = mips_cpu_has_work; cc->dump_state = mips_cpu_dump_state; cc->set_pc = mips_cpu_set_pc; + cc->get_pc = mips_cpu_get_pc; cc->gdb_read_register = mips_cpu_gdb_read_register; cc->gdb_write_register = mips_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/mips/tcg/exception.c b/target/mips/tcg/exception.c index 2bd77a61de..96e61170e6 100644 --- a/target/mips/tcg/exception.c +++ b/target/mips/tcg/exception.c @@ -82,7 +82,7 @@ void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) MIPSCPU *cpu = MIPS_CPU(cs); CPUMIPSState *env = &cpu->env; - env->active_tc.PC = tb->pc; + env->active_tc.PC = tb_pc(tb); env->hflags &= ~MIPS_HFLAG_BMASK; env->hflags |= tb->flags & MIPS_HFLAG_BMASK; } diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc index 274caf2c3c..632895cc9e 100644 --- a/target/mips/tcg/micromips_translate.c.inc +++ b/target/mips/tcg/micromips_translate.c.inc @@ -825,8 +825,8 @@ static void gen_pool16c_insn(DisasContext *ctx) generate_exception_break(ctx, extract32(ctx->opcode, 0, 4)); break; case SDBBP16: - if (is_uhi(extract32(ctx->opcode, 0, 4))) { - generate_exception_end(ctx, EXCP_SEMIHOST); + if (is_uhi(ctx, extract32(ctx->opcode, 0, 4))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { /* * XXX: not clear which exception should be raised @@ -941,8 +941,8 @@ static void gen_pool16c_r6_insn(DisasContext *ctx) break; case R6_SDBBP16: /* SDBBP16 */ - if (is_uhi(extract32(ctx->opcode, 6, 4))) { - generate_exception_end(ctx, EXCP_SEMIHOST); + if (is_uhi(ctx, extract32(ctx->opcode, 6, 4))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { if (ctx->hflags & MIPS_HFLAG_SBRI) { generate_exception(ctx, EXCP_RI); @@ -1310,8 +1310,8 @@ static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs) generate_exception_end(ctx, EXCP_SYSCALL); break; case SDBBP: - if (is_uhi(extract32(ctx->opcode, 16, 10))) { - generate_exception_end(ctx, EXCP_SEMIHOST); + if (is_uhi(ctx, extract32(ctx->opcode, 16, 10))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { check_insn(ctx, ISA_MIPS_R1); if (ctx->hflags & MIPS_HFLAG_SBRI) { diff --git a/target/mips/tcg/mips16e_translate.c.inc b/target/mips/tcg/mips16e_translate.c.inc index 0a3ba252e4..918b15d55c 100644 --- a/target/mips/tcg/mips16e_translate.c.inc +++ b/target/mips/tcg/mips16e_translate.c.inc @@ -951,8 +951,8 @@ static int decode_ase_mips16e(CPUMIPSState *env, DisasContext *ctx) } break; case RR_SDBBP: - if (is_uhi(extract32(ctx->opcode, 5, 6))) { - generate_exception_end(ctx, EXCP_SEMIHOST); + if (is_uhi(ctx, extract32(ctx->opcode, 5, 6))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { /* * XXX: not clear which exception should be raised diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc index ecb0ebed57..812c111e3c 100644 --- a/target/mips/tcg/nanomips_translate.c.inc +++ b/target/mips/tcg/nanomips_translate.c.inc @@ -3694,8 +3694,8 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) generate_exception_end(ctx, EXCP_BREAK); break; case NM_SDBBP: - if (is_uhi(extract32(ctx->opcode, 0, 19))) { - generate_exception_end(ctx, EXCP_SEMIHOST); + if (is_uhi(ctx, extract32(ctx->opcode, 0, 19))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { if (ctx->hflags & MIPS_HFLAG_SBRI) { gen_reserved_instruction(ctx); @@ -4633,8 +4633,8 @@ static int decode_isa_nanomips(CPUMIPSState *env, DisasContext *ctx) generate_exception_end(ctx, EXCP_BREAK); break; case NM_SDBBP16: - if (is_uhi(extract32(ctx->opcode, 0, 3))) { - generate_exception_end(ctx, EXCP_SEMIHOST); + if (is_uhi(ctx, extract32(ctx->opcode, 0, 3))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { if (ctx->hflags & MIPS_HFLAG_SBRI) { gen_reserved_instruction(ctx); diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c index 5fb1ad9092..85f0567a7f 100644 --- a/target/mips/tcg/sysemu/mips-semi.c +++ b/target/mips/tcg/sysemu/mips-semi.c @@ -321,6 +321,9 @@ void mips_semihosting(CPUMIPSState *env) if (use_gdb_syscalls()) { addr = gpr[29] - str->len; p = lock_user(VERIFY_WRITE, addr, str->len, 0); + if (!p) { + report_fault(env); + } memcpy(p, str->str, str->len); unlock_user(p, addr, str->len); semihost_sys_write(cs, uhi_cb, 2, addr, str->len); diff --git a/target/mips/tcg/sysemu/special_helper.c b/target/mips/tcg/sysemu/special_helper.c index f4f8fe8afc..3c5f35c759 100644 --- a/target/mips/tcg/sysemu/special_helper.c +++ b/target/mips/tcg/sysemu/special_helper.c @@ -94,7 +94,7 @@ bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb) CPUMIPSState *env = &cpu->env; if ((env->hflags & MIPS_HFLAG_BMASK) != 0 - && env->active_tc.PC != tb->pc) { + && env->active_tc.PC != tb_pc(tb)) { env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); env->hflags &= ~MIPS_HFLAG_BMASK; return true; diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c index 57ffad2902..9d16859c0a 100644 --- a/target/mips/tcg/sysemu/tlb_helper.c +++ b/target/mips/tcg/sysemu/tlb_helper.c @@ -1056,6 +1056,7 @@ void mips_cpu_do_interrupt(CPUState *cs) case EXCP_SEMIHOST: cs->exception_index = EXCP_NONE; mips_semihosting(env); + env->active_tc.PC += env->error_code; return; case EXCP_DSS: env->CP0_Debug |= 1 << CP0DB_DSS; diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 1f6a779808..c3f92ea652 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -1213,9 +1213,6 @@ TCGv_i64 fpu_f64[32]; #include "exec/gen-icount.h" -#define DISAS_STOP DISAS_TARGET_0 -#define DISAS_EXIT DISAS_TARGET_1 - static const char regnames_HI[][4] = { "HI0", "HI1", "HI2", "HI3", }; @@ -12085,12 +12082,13 @@ static void gen_cache_operation(DisasContext *ctx, uint32_t op, int base, tcg_temp_free_i32(t0); } -static inline bool is_uhi(int sdbbp_code) +static inline bool is_uhi(DisasContext *ctx, int sdbbp_code) { #ifdef CONFIG_USER_ONLY return false; #else - return semihosting_enabled() && sdbbp_code == 1; + bool is_user = (ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM; + return semihosting_enabled(is_user) && sdbbp_code == 1; #endif } @@ -13901,8 +13899,8 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) } break; case R6_OPC_SDBBP: - if (is_uhi(extract32(ctx->opcode, 6, 20))) { - generate_exception_end(ctx, EXCP_SEMIHOST); + if (is_uhi(ctx, extract32(ctx->opcode, 6, 20))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { if (ctx->hflags & MIPS_HFLAG_SBRI) { gen_reserved_instruction(ctx); @@ -14313,8 +14311,8 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) gen_cl(ctx, op1, rd, rs); break; case OPC_SDBBP: - if (is_uhi(extract32(ctx->opcode, 6, 20))) { - generate_exception_end(ctx, EXCP_SEMIHOST); + if (is_uhi(ctx, extract32(ctx->opcode, 6, 20))) { + ctx->base.is_jmp = DISAS_SEMIHOST; } else { /* * XXX: not clear which exception should be raised @@ -16098,6 +16096,9 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) if (is_slot) { gen_branch(ctx, insn_bytes); } + if (ctx->base.is_jmp == DISAS_SEMIHOST) { + generate_exception_err(ctx, EXCP_SEMIHOST, insn_bytes); + } ctx->base.pc_next += insn_bytes; if (ctx->base.is_jmp != DISAS_NEXT) { @@ -16155,11 +16156,12 @@ static const TranslatorOps mips_tr_ops = { .disas_log = mips_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&mips_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &mips_tr_ops, &ctx.base); } void mips_tcg_init(void) diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h index 55053226ae..69f85841d2 100644 --- a/target/mips/tcg/translate.h +++ b/target/mips/tcg/translate.h @@ -51,6 +51,10 @@ typedef struct DisasContext { int gi; } DisasContext; +#define DISAS_STOP DISAS_TARGET_0 +#define DISAS_EXIT DISAS_TARGET_1 +#define DISAS_SEMIHOST DISAS_TARGET_2 + /* MIPS major opcodes */ #define MASK_OP_MAJOR(op) (op & (0x3F << 26)) diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c index 19b2409974..2b28429c08 100644 --- a/target/nios2/cpu.c +++ b/target/nios2/cpu.c @@ -34,6 +34,14 @@ static void nios2_cpu_set_pc(CPUState *cs, vaddr value) env->pc = value; } +static vaddr nios2_cpu_get_pc(CPUState *cs) +{ + Nios2CPU *cpu = NIOS2_CPU(cs); + CPUNios2State *env = &cpu->env; + + return env->pc; +} + static bool nios2_cpu_has_work(CPUState *cs) { return cs->interrupt_request & CPU_INTERRUPT_HARD; @@ -362,6 +370,7 @@ static void nios2_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = nios2_cpu_has_work; cc->dump_state = nios2_cpu_dump_state; cc->set_pc = nios2_cpu_set_pc; + cc->get_pc = nios2_cpu_get_pc; cc->disas_set_info = nios2_cpu_disas_set_info; #ifndef CONFIG_USER_ONLY cc->sysemu_ops = &nios2_sysemu_ops; diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c index 55061bb2dc..f76e8588c5 100644 --- a/target/nios2/nios2-semi.c +++ b/target/nios2/nios2-semi.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/gdbstub.h" +#include "semihosting/syscalls.h" #include "semihosting/softmmu-uaccess.h" #include "qemu/log.h" @@ -42,65 +43,33 @@ #define HOSTED_ISATTY 12 #define HOSTED_SYSTEM 13 -static int translate_openflags(int flags) +static int host_to_gdb_errno(int err) { - int hf; - - if (flags & GDB_O_WRONLY) { - hf = O_WRONLY; - } else if (flags & GDB_O_RDWR) { - hf = O_RDWR; - } else { - hf = O_RDONLY; +#define E(X) case E##X: return GDB_E##X + switch (err) { + E(PERM); + E(NOENT); + E(INTR); + E(BADF); + E(ACCES); + E(FAULT); + E(BUSY); + E(EXIST); + E(NODEV); + E(NOTDIR); + E(ISDIR); + E(INVAL); + E(NFILE); + E(MFILE); + E(FBIG); + E(NOSPC); + E(SPIPE); + E(ROFS); + E(NAMETOOLONG); + default: + return GDB_EUNKNOWN; } - - if (flags & GDB_O_APPEND) { - hf |= O_APPEND; - } - if (flags & GDB_O_CREAT) { - hf |= O_CREAT; - } - if (flags & GDB_O_TRUNC) { - hf |= O_TRUNC; - } - if (flags & GDB_O_EXCL) { - hf |= O_EXCL; - } - - return hf; -} - -static bool translate_stat(CPUNios2State *env, target_ulong addr, - struct stat *s) -{ - struct gdb_stat *p; - - p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0); - - if (!p) { - return false; - } - p->gdb_st_dev = cpu_to_be32(s->st_dev); - p->gdb_st_ino = cpu_to_be32(s->st_ino); - p->gdb_st_mode = cpu_to_be32(s->st_mode); - p->gdb_st_nlink = cpu_to_be32(s->st_nlink); - p->gdb_st_uid = cpu_to_be32(s->st_uid); - p->gdb_st_gid = cpu_to_be32(s->st_gid); - p->gdb_st_rdev = cpu_to_be32(s->st_rdev); - p->gdb_st_size = cpu_to_be64(s->st_size); -#ifdef _WIN32 - /* Windows stat is missing some fields. */ - p->gdb_st_blksize = 0; - p->gdb_st_blocks = 0; -#else - p->gdb_st_blksize = cpu_to_be64(s->st_blksize); - p->gdb_st_blocks = cpu_to_be64(s->st_blocks); -#endif - p->gdb_st_atime = cpu_to_be32(s->st_atime); - p->gdb_st_mtime = cpu_to_be32(s->st_mtime); - p->gdb_st_ctime = cpu_to_be32(s->st_ctime); - unlock_user(p, addr, sizeof(struct gdb_stat)); - return true; +#undef E } static void nios2_semi_u32_cb(CPUState *cs, uint64_t ret, int err) @@ -110,7 +79,7 @@ static void nios2_semi_u32_cb(CPUState *cs, uint64_t ret, int err) target_ulong args = env->regs[R_ARG1]; if (put_user_u32(ret, args) || - put_user_u32(err, args + 4)) { + put_user_u32(host_to_gdb_errno(err), args + 4)) { /* * The nios2 semihosting ABI does not provide any way to report this * error to the guest, so the best we can do is log it in qemu. @@ -129,7 +98,7 @@ static void nios2_semi_u64_cb(CPUState *cs, uint64_t ret, int err) if (put_user_u32(ret >> 32, args) || put_user_u32(ret, args + 4) || - put_user_u32(err, args + 8)) { + put_user_u32(host_to_gdb_errno(err), args + 8)) { /* No way to report this via nios2 semihosting ABI; just log it */ qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: return value " "discarded because argument block not writable\n"); @@ -142,22 +111,22 @@ static void nios2_semi_u64_cb(CPUState *cs, uint64_t ret, int err) */ #define GET_ARG(n) do { \ if (get_user_ual(arg ## n, args + (n) * 4)) { \ - result = -1; \ - errno = EFAULT; \ goto failed; \ } \ } while (0) +#define GET_ARG64(n) do { \ + if (get_user_ual(arg ## n, args + (n) * 4)) { \ + goto failed64; \ + } \ +} while (0) + void do_nios2_semihosting(CPUNios2State *env) { CPUState *cs = env_cpu(env); int nr; uint32_t args; target_ulong arg0, arg1, arg2, arg3; - void *p; - void *q; - uint32_t len; - uint32_t result; nr = env->regs[R_ARG0]; args = env->regs[R_ARG1]; @@ -165,234 +134,98 @@ void do_nios2_semihosting(CPUNios2State *env) case HOSTED_EXIT: gdb_exit(env->regs[R_ARG0]); exit(env->regs[R_ARG0]); + case HOSTED_OPEN: GET_ARG(0); GET_ARG(1); GET_ARG(2); GET_ARG(3); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "open,%s,%x,%x", arg0, (int)arg1, - arg2, arg3); - return; - } else { - p = lock_user_string(arg0); - if (!p) { - result = -1; - errno = EFAULT; - } else { - result = open(p, translate_openflags(arg2), arg3); - unlock_user(p, arg0, 0); - } - } + semihost_sys_open(cs, nios2_semi_u32_cb, arg0, arg1, arg2, arg3); break; + case HOSTED_CLOSE: - { - /* Ignore attempts to close stdin/out/err. */ - GET_ARG(0); - int fd = arg0; - if (fd > 2) { - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "close,%x", arg0); - return; - } else { - result = close(fd); - } - } else { - result = 0; - } - break; - } + GET_ARG(0); + semihost_sys_close(cs, nios2_semi_u32_cb, arg0); + break; + case HOSTED_READ: GET_ARG(0); GET_ARG(1); GET_ARG(2); - len = arg2; - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "read,%x,%x,%x", - arg0, arg1, len); - return; - } else { - p = lock_user(VERIFY_WRITE, arg1, len, 0); - if (!p) { - result = -1; - errno = EFAULT; - } else { - result = read(arg0, p, len); - unlock_user(p, arg1, len); - } - } + semihost_sys_read(cs, nios2_semi_u32_cb, arg0, arg1, arg2); break; + case HOSTED_WRITE: GET_ARG(0); GET_ARG(1); GET_ARG(2); - len = arg2; - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "write,%x,%x,%x", - arg0, arg1, len); - return; - } else { - p = lock_user(VERIFY_READ, arg1, len, 1); - if (!p) { - result = -1; - errno = EFAULT; - } else { - result = write(arg0, p, len); - unlock_user(p, arg0, 0); - } - } + semihost_sys_write(cs, nios2_semi_u32_cb, arg0, arg1, arg2); break; + case HOSTED_LSEEK: - { - uint64_t off; - GET_ARG(0); - GET_ARG(1); - GET_ARG(2); - GET_ARG(3); - off = (uint32_t)arg2 | ((uint64_t)arg1 << 32); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u64_cb, "lseek,%x,%lx,%x", - arg0, off, arg3); - } else { - off = lseek(arg0, off, arg3); - nios2_semi_u64_cb(cs, off, errno); - } - return; - } + GET_ARG64(0); + GET_ARG64(1); + GET_ARG64(2); + GET_ARG64(3); + semihost_sys_lseek(cs, nios2_semi_u64_cb, arg0, + deposit64(arg2, arg1, 32, 32), arg3); + break; + case HOSTED_RENAME: GET_ARG(0); GET_ARG(1); GET_ARG(2); GET_ARG(3); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "rename,%s,%s", - arg0, (int)arg1, arg2, (int)arg3); - return; - } else { - p = lock_user_string(arg0); - q = lock_user_string(arg2); - if (!p || !q) { - result = -1; - errno = EFAULT; - } else { - result = rename(p, q); - } - unlock_user(p, arg0, 0); - unlock_user(q, arg2, 0); - } + semihost_sys_rename(cs, nios2_semi_u32_cb, arg0, arg1, arg2, arg3); break; + case HOSTED_UNLINK: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "unlink,%s", - arg0, (int)arg1); - return; - } else { - p = lock_user_string(arg0); - if (!p) { - result = -1; - errno = EFAULT; - } else { - result = unlink(p); - unlock_user(p, arg0, 0); - } - } + semihost_sys_remove(cs, nios2_semi_u32_cb, arg0, arg1); break; + case HOSTED_STAT: GET_ARG(0); GET_ARG(1); GET_ARG(2); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "stat,%s,%x", - arg0, (int)arg1, arg2); - return; - } else { - struct stat s; - p = lock_user_string(arg0); - if (!p) { - result = -1; - errno = EFAULT; - } else { - result = stat(p, &s); - unlock_user(p, arg0, 0); - } - if (result == 0 && !translate_stat(env, arg2, &s)) { - result = -1; - errno = EFAULT; - } - } + semihost_sys_stat(cs, nios2_semi_u32_cb, arg0, arg1, arg2); break; + case HOSTED_FSTAT: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "fstat,%x,%x", - arg0, arg1); - return; - } else { - struct stat s; - result = fstat(arg0, &s); - if (result == 0 && !translate_stat(env, arg1, &s)) { - result = -1; - errno = EFAULT; - } - } + semihost_sys_fstat(cs, nios2_semi_u32_cb, arg0, arg1); break; + case HOSTED_GETTIMEOFDAY: - /* Only the tv parameter is used. tz is assumed NULL. */ GET_ARG(0); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "gettimeofday,%x,%x", - arg0, 0); - return; - } else { - struct gdb_timeval *p; - int64_t rt = g_get_real_time(); - p = lock_user(VERIFY_WRITE, arg0, sizeof(struct gdb_timeval), 0); - if (!p) { - result = -1; - errno = EFAULT; - } else { - result = 0; - p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC); - p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC); - unlock_user(p, arg0, sizeof(struct gdb_timeval)); - } - } + GET_ARG(1); + semihost_sys_gettimeofday(cs, nios2_semi_u32_cb, arg0, arg1); break; + case HOSTED_ISATTY: GET_ARG(0); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "isatty,%x", arg0); - return; - } else { - result = isatty(arg0); - } + semihost_sys_isatty(cs, nios2_semi_u32_cb, arg0); break; + case HOSTED_SYSTEM: GET_ARG(0); GET_ARG(1); - if (use_gdb_syscalls()) { - gdb_do_syscall(nios2_semi_u32_cb, "system,%s", - arg0, (int)arg1); - return; - } else { - p = lock_user_string(arg0); - if (!p) { - result = -1; - errno = EFAULT; - } else { - result = system(p); - unlock_user(p, arg0, 0); - } - } + semihost_sys_system(cs, nios2_semi_u32_cb, arg0, arg1); break; + default: qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: unsupported " "semihosting syscall %d\n", nr); - result = 0; + nios2_semi_u32_cb(cs, -1, ENOSYS); + break; + + failed: + nios2_semi_u32_cb(cs, -1, EFAULT); + break; + failed64: + nios2_semi_u64_cb(cs, -1, EFAULT); + break; } -failed: - nios2_semi_u32_cb(cs, result, errno); } diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 3a037a68cc..8dc0a32c6c 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -817,8 +817,9 @@ static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags) { #ifndef CONFIG_USER_ONLY /* The semihosting instruction is "break 1". */ + bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U); R_TYPE(instr, code); - if (semihosting_enabled() && instr.imm5 == 1) { + if (semihosting_enabled(is_user) && instr.imm5 == 1) { t_gen_helper_raise_exception(dc, EXCP_SEMIHOST); return; } @@ -1038,10 +1039,11 @@ static const TranslatorOps nios2_tr_ops = { .disas_log = nios2_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc; - translator_loop(&nios2_tr_ops, &dc.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base); } void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 41d1b2a24a..f6fd437785 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -31,12 +31,19 @@ static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.dflag = 0; } +static vaddr openrisc_cpu_get_pc(CPUState *cs) +{ + OpenRISCCPU *cpu = OPENRISC_CPU(cs); + + return cpu->env.pc; +} + static void openrisc_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { OpenRISCCPU *cpu = OPENRISC_CPU(cs); - cpu->env.pc = tb->pc; + cpu->env.pc = tb_pc(tb); } @@ -98,7 +105,6 @@ static void openrisc_cpu_set_irq(void *opaque, int irq, int level) cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - cpu->env.picsr = 0; } } #endif @@ -219,6 +225,7 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = openrisc_cpu_has_work; cc->dump_state = openrisc_cpu_dump_state; cc->set_pc = openrisc_cpu_set_pc; + cc->get_pc = openrisc_cpu_get_pc; cc->gdb_read_register = openrisc_cpu_gdb_read_register; cc->gdb_write_register = openrisc_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b9584f10d4..1d5efa5ca2 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -25,6 +25,8 @@ #include "hw/core/cpu.h" #include "qom/object.h" +#define TCG_GUEST_DEFAULT_MO (0) + #define TYPE_OPENRISC_CPU "or1k-cpu" OBJECT_DECLARE_CPU_TYPE(OpenRISCCPU, OpenRISCCPUClass, OPENRISC_CPU) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index e5724f5371..c31c6f12c4 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -83,7 +83,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) [EXCP_TRAP] = "TRAP", }; - qemu_log_mask(CPU_LOG_INT, "INT: %s\n", int_name[exception]); + qemu_log_mask(CPU_LOG_INT, "CPU: %d INT: %s\n", + cs->cpu_index, + int_name[exception]); hwaddr vect_pc = exception << 8; if (env->cpucfgr & CPUCFGR_EVBARP) { diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index d7e1320998..0b8afdbacf 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -148,7 +148,13 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) case SR_DME | SR_IME: /* The mmu is definitely enabled. */ excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, - PAGE_EXEC | PAGE_READ | PAGE_WRITE, + PAGE_READ, + (sr & SR_SM) != 0); + if (!excp) { + return phys_addr; + } + excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, + PAGE_EXEC, (sr & SR_SM) != 0); return excp ? -1 : phys_addr; diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 48674231e7..09b3c97d7c 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -139,12 +139,20 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(9, 0): /* PICMR */ env->picmr = rb; + qemu_mutex_lock_iothread(); + if (env->picsr & env->picmr) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + qemu_mutex_unlock_iothread(); break; case TO_SPR(9, 2): /* PICSR */ env->picsr &= ~rb; break; case TO_SPR(10, 0): /* TTMR */ { + qemu_mutex_lock_iothread(); if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { switch (rb & TTMR_M) { case TIMER_NONE: @@ -168,14 +176,16 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) env->ttmr = rb & ~TTMR_IP; cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } - cpu_openrisc_timer_update(cpu); + qemu_mutex_unlock_iothread(); } break; case TO_SPR(10, 1): /* TTCR */ + qemu_mutex_lock_iothread(); cpu_openrisc_count_set(cpu, rb); cpu_openrisc_timer_update(cpu); + qemu_mutex_unlock_iothread(); break; #endif @@ -303,7 +313,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, return env->ttmr; case TO_SPR(10, 1): /* TTCR */ + qemu_mutex_lock_iothread(); cpu_openrisc_count_update(cpu); + qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); #endif diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 7b8ad43d5f..8154f9d744 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -1705,11 +1705,13 @@ static const TranslatorOps openrisc_tr_ops = { .disas_log = openrisc_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&openrisc_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, + &openrisc_tr_ops, &ctx.base); } void openrisc_cpu_dump_state(CPUState *cs, FILE *f, int flags) diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c index 1139cead9f..f58e6359d5 100644 --- a/target/ppc/arch_dump.c +++ b/target/ppc/arch_dump.c @@ -270,23 +270,23 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) static int ppc_write_all_elf_notes(const char *note_name, WriteCoreDumpFunction f, PowerPCCPU *cpu, int id, - void *opaque) + DumpState *s) { - NoteFuncArg arg = { .state = opaque }; + NoteFuncArg arg = { .state = s }; int ret = -1; int note_size; const NoteFuncDesc *nf; for (nf = note_func; nf->note_contents_func; nf++) { - arg.note.hdr.n_namesz = cpu_to_dump32(opaque, sizeof(arg.note.name)); - arg.note.hdr.n_descsz = cpu_to_dump32(opaque, nf->contents_size); + arg.note.hdr.n_namesz = cpu_to_dump32(s, sizeof(arg.note.name)); + arg.note.hdr.n_descsz = cpu_to_dump32(s, nf->contents_size); strncpy(arg.note.name, note_name, sizeof(arg.note.name)); (*nf->note_contents_func)(&arg, cpu); note_size = sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size; - ret = f(&arg.note, note_size, opaque); + ret = f(&arg.note, note_size, s); if (ret < 0) { return -1; } @@ -295,15 +295,15 @@ static int ppc_write_all_elf_notes(const char *note_name, } int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { PowerPCCPU *cpu = POWERPC_CPU(cs); - return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque); + return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, s); } int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { PowerPCCPU *cpu = POWERPC_CPU(cs); - return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, opaque); + return ppc_write_all_elf_notes("CORE", f, cpu, cpuid, s); } diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index ad7e3c3db9..89ff88f28c 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -158,7 +158,11 @@ struct PowerPCCPUClass { void (*parent_parse_features)(const char *type, char *str, Error **errp); uint32_t pvr; - bool (*pvr_match)(struct PowerPCCPUClass *pcc, uint32_t pvr); + /* + * If @best is false, match if pcc is in the family of pvr + * Else match only if pcc is the best match for pvr in this family. + */ + bool (*pvr_match)(struct PowerPCCPUClass *pcc, uint32_t pvr, bool best); uint64_t pcr_mask; /* Available bits in PCR register */ uint64_t pcr_supported; /* Bits for supported PowerISA versions */ uint32_t svr; diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index 401b6f9e63..0ebac04bc4 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -120,6 +120,8 @@ void ppc_store_fpscr(CPUPPCState *env, target_ulong val) val |= FP_FEX; } env->fpscr = val; + env->fp_status.rebias_overflow = (FP_OE & env->fpscr) ? true : false; + env->fp_status.rebias_underflow = (FP_UE & env->fpscr) ? true : false; if (tcg_enabled()) { fpscr_set_rounding_mode(env); } diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index a4c893cfad..cca6c4e51c 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -246,7 +246,7 @@ typedef union _ppc_vsr_t { #ifdef CONFIG_INT128 __uint128_t u128; #endif - Int128 s128; + Int128 s128; } ppc_vsr_t; typedef ppc_vsr_t ppc_avr_t; @@ -1354,9 +1354,9 @@ void ppc_gdb_gen_spr_xml(PowerPCCPU *cpu); const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name); #endif int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); #ifndef CONFIG_USER_ONLY void ppc_cpu_do_interrupt(CPUState *cpu); bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req); @@ -1506,10 +1506,6 @@ void ppc_compat_add_property(Object *obj, const char *name, #define XER_CMP 8 #define XER_BC 0 #define xer_so (env->so) -#define xer_ov (env->ov) -#define xer_ca (env->ca) -#define xer_ov32 (env->ov) -#define xer_ca32 (env->ca) #define xer_cmp ((env->xer >> XER_CMP) & 0xFF) #define xer_bc ((env->xer >> XER_BC) & 0x7F) @@ -1676,6 +1672,8 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_GIVOR14 (0x1BD) #define SPR_TIR (0x1BE) #define SPR_PTCR (0x1D0) +#define SPR_HASHKEYR (0x1D4) +#define SPR_HASHPKEYR (0x1D5) #define SPR_BOOKE_SPEFSCR (0x200) #define SPR_Exxx_BBEAR (0x201) #define SPR_Exxx_BBTAR (0x202) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index d1493a660c..763a8431be 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5700,6 +5700,33 @@ static void register_power9_mmu_sprs(CPUPPCState *env) #endif } +static void register_power10_hash_sprs(CPUPPCState *env) +{ + /* + * it's the OS responsability to generate a random value for the registers + * in each process' context. So, initialize it with 0 here. + */ + uint64_t hashkeyr_initial_value = 0, hashpkeyr_initial_value = 0; +#if defined(CONFIG_USER_ONLY) + /* in linux-user, setup the hash register with a random value */ + GRand *rand = g_rand_new(); + hashkeyr_initial_value = + ((uint64_t)g_rand_int(rand) << 32) | (uint64_t)g_rand_int(rand); + hashpkeyr_initial_value = + ((uint64_t)g_rand_int(rand) << 32) | (uint64_t)g_rand_int(rand); + g_rand_free(rand); +#endif + spr_register(env, SPR_HASHKEYR, "HASHKEYR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + hashkeyr_initial_value); + spr_register_hv(env, SPR_HASHPKEYR, "HASHPKEYR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + hashpkeyr_initial_value); +} + /* * Initialize PMU counter overflow timers for Power8 and * newer Power chips when using TCG. @@ -5912,15 +5939,25 @@ static void init_proc_POWER7(CPUPPCState *env) ppcPOWER7_irq_init(env_archcpu(env)); } -static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr) +static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best) { - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER7P_BASE) { - return true; + uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK; + uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK; + + if (!best) { + if (base == CPU_POWERPC_POWER7_BASE) { + return true; + } + if (base == CPU_POWERPC_POWER7P_BASE) { + return true; + } } - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER7_BASE) { - return true; + + if (base != pcc_base) { + return false; } - return false; + + return true; } static bool cpu_has_work_POWER7(CPUState *cs) @@ -6073,18 +6110,27 @@ static void init_proc_POWER8(CPUPPCState *env) ppcPOWER7_irq_init(env_archcpu(env)); } -static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr) +static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best) { - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8NVL_BASE) { - return true; + uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK; + uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK; + + if (!best) { + if (base == CPU_POWERPC_POWER8_BASE) { + return true; + } + if (base == CPU_POWERPC_POWER8E_BASE) { + return true; + } + if (base == CPU_POWERPC_POWER8NVL_BASE) { + return true; + } } - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8E_BASE) { - return true; + if (base != pcc_base) { + return false; } - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER8_BASE) { - return true; - } - return false; + + return true; } static bool cpu_has_work_POWER8(CPUState *cs) @@ -6282,11 +6328,26 @@ static void init_proc_POWER9(CPUPPCState *env) ppcPOWER9_irq_init(env_archcpu(env)); } -static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr) +static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best) { - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER9_BASE) { + uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK; + uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK; + + if (!best) { + if (base == CPU_POWERPC_POWER9_BASE) { + return true; + } + } + + if (base != pcc_base) { + return false; + } + + if ((pvr & 0x0f00) == (pcc->pvr & 0x0f00)) { + /* Major DD version matches to power9_v1.0 and power9_v2.0 */ return true; } + return false; } @@ -6484,6 +6545,7 @@ static void init_proc_POWER10(CPUPPCState *env) register_power8_book4_sprs(env); register_power8_rpr_sprs(env); register_power9_mmu_sprs(env); + register_power10_hash_sprs(env); /* FIXME: Filter fields properly based on privilege level */ spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL, @@ -6499,11 +6561,26 @@ static void init_proc_POWER10(CPUPPCState *env) ppcPOWER9_irq_init(env_archcpu(env)); } -static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr) +static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best) { - if ((pvr & CPU_POWERPC_POWER_SERVER_MASK) == CPU_POWERPC_POWER10_BASE) { + uint32_t base = pvr & CPU_POWERPC_POWER_SERVER_MASK; + uint32_t pcc_base = pcc->pvr & CPU_POWERPC_POWER_SERVER_MASK; + + if (!best) { + if (base == CPU_POWERPC_POWER10_BASE) { + return true; + } + } + + if (base != pcc_base) { + return false; + } + + if ((pvr & 0x0f00) == (pcc->pvr & 0x0f00)) { + /* Major DD version matches to power10_v1.0 and power10_v2.0 */ return true; } + return false; } @@ -6910,7 +6987,7 @@ static gint ppc_cpu_compare_class_pvr_mask(gconstpointer a, gconstpointer b) return -1; } - if (pcc->pvr_match(pcc, pvr)) { + if (pcc->pvr_match(pcc, pvr, true)) { return 0; } @@ -7137,6 +7214,13 @@ static void ppc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.nip = value; } +static vaddr ppc_cpu_get_pc(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + + return cpu->env.nip; +} + static bool ppc_cpu_has_work(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -7308,7 +7392,7 @@ static void ppc_cpu_instance_finalize(Object *obj) ppc_hash64_finalize(cpu); } -static bool ppc_pvr_match_default(PowerPCCPUClass *pcc, uint32_t pvr) +static bool ppc_pvr_match_default(PowerPCCPUClass *pcc, uint32_t pvr, bool best) { return pcc->pvr == pvr; } @@ -7395,6 +7479,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = ppc_cpu_has_work; cc->dump_state = ppc_cpu_dump_state; cc->set_pc = ppc_cpu_set_pc; + cc->get_pc = ppc_cpu_get_pc; cc->gdb_read_register = ppc_cpu_gdb_read_register; cc->gdb_write_register = ppc_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index 5ba74b2124..cc024316d5 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -42,13 +42,16 @@ static void get_dfp128(ppc_vsr_t *dst, ppc_fprp_t *dfp) static void set_dfp64(ppc_fprp_t *dfp, ppc_vsr_t *src) { - dfp->VsrD(0) = src->VsrD(1); + dfp[0].VsrD(0) = src->VsrD(1); + dfp[0].VsrD(1) = 0ULL; } static void set_dfp128(ppc_fprp_t *dfp, ppc_vsr_t *src) { dfp[0].VsrD(0) = src->VsrD(0); dfp[1].VsrD(0) = src->VsrD(1); + dfp[0].VsrD(1) = 0ULL; + dfp[1].VsrD(1) = 0ULL; } static void set_dfp128_to_avr(ppc_avr_t *dst, ppc_vsr_t *src) @@ -1144,6 +1147,26 @@ static inline uint8_t dfp_get_bcd_digit_128(ppc_vsr_t *t, unsigned n) return t->VsrD((n & 0x10) ? 0 : 1) >> ((n << 2) & 63) & 15; } +static inline void dfp_invalid_op_vxcvi_64(struct PPC_DFP *dfp) +{ + /* TODO: fpscr is incorrectly not being saved to env */ + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FPSCR_VE); + if ((dfp->env->fpscr & FP_VE) == 0) { + dfp->vt.VsrD(1) = 0x7c00000000000000; /* QNaN */ + } +} + + +static inline void dfp_invalid_op_vxcvi_128(struct PPC_DFP *dfp) +{ + /* TODO: fpscr is incorrectly not being saved to env */ + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FPSCR_VE); + if ((dfp->env->fpscr & FP_VE) == 0) { + dfp->vt.VsrD(0) = 0x7c00000000000000; /* QNaN */ + dfp->vt.VsrD(1) = 0x0; + } +} + #define DFP_HELPER_ENBCD(op, size) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ uint32_t s) \ @@ -1170,7 +1193,8 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ sgn = 0; \ break; \ default: \ - dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ + dfp_invalid_op_vxcvi_##size(&dfp); \ + set_dfp##size(t, &dfp.vt); \ return; \ } \ } \ @@ -1180,7 +1204,8 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb, \ offset++); \ if (digits[(size) / 4 - n] > 10) { \ - dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ + dfp_invalid_op_vxcvi_##size(&dfp); \ + set_dfp##size(t, &dfp.vt); \ return; \ } else { \ nonzero |= (digits[(size) / 4 - n] > 0); \ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index cb752b184a..214acf5ac4 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2015,7 +2015,6 @@ void helper_rfi(CPUPPCState *env) do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); } -#define MSR_BOOK3S_MASK #if defined(TARGET_PPC64) void helper_rfid(CPUPPCState *env) { @@ -2174,6 +2173,89 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, #endif #endif +static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane) +{ + const uint16_t c = 0xfffc; + const uint64_t z0 = 0xfa2561cdf44ac398ULL; + uint16_t z = 0, temp; + uint16_t k[32], eff_k[32], xleft[33], xright[33], fxleft[32]; + + for (int i = 3; i >= 0; i--) { + k[i] = key & 0xffff; + key >>= 16; + } + xleft[0] = x & 0xffff; + xright[0] = (x >> 16) & 0xffff; + + for (int i = 0; i < 28; i++) { + z = (z0 >> (63 - i)) & 1; + temp = ror16(k[i + 3], 3) ^ k[i + 1]; + k[i + 4] = c ^ z ^ k[i] ^ temp ^ ror16(temp, 1); + } + + for (int i = 0; i < 8; i++) { + eff_k[4 * i + 0] = k[4 * i + ((0 + lane) % 4)]; + eff_k[4 * i + 1] = k[4 * i + ((1 + lane) % 4)]; + eff_k[4 * i + 2] = k[4 * i + ((2 + lane) % 4)]; + eff_k[4 * i + 3] = k[4 * i + ((3 + lane) % 4)]; + } + + for (int i = 0; i < 32; i++) { + fxleft[i] = (rol16(xleft[i], 1) & + rol16(xleft[i], 8)) ^ rol16(xleft[i], 2); + xleft[i + 1] = xright[i] ^ fxleft[i] ^ eff_k[i]; + xright[i + 1] = xleft[i]; + } + + return (((uint32_t)xright[32]) << 16) | xleft[32]; +} + +static uint64_t hash_digest(uint64_t ra, uint64_t rb, uint64_t key) +{ + uint64_t stage0_h = 0ULL, stage0_l = 0ULL; + uint64_t stage1_h, stage1_l; + + for (int i = 0; i < 4; i++) { + stage0_h |= ror64(rb & 0xff, 8 * (2 * i + 1)); + stage0_h |= ((ra >> 32) & 0xff) << (8 * 2 * i); + stage0_l |= ror64((rb >> 32) & 0xff, 8 * (2 * i + 1)); + stage0_l |= (ra & 0xff) << (8 * 2 * i); + rb >>= 8; + ra >>= 8; + } + + stage1_h = (uint64_t)helper_SIMON_LIKE_32_64(stage0_h >> 32, key, 0) << 32; + stage1_h |= helper_SIMON_LIKE_32_64(stage0_h, key, 1); + stage1_l = (uint64_t)helper_SIMON_LIKE_32_64(stage0_l >> 32, key, 2) << 32; + stage1_l |= helper_SIMON_LIKE_32_64(stage0_l, key, 3); + + return stage1_h ^ stage1_l; +} + +#include "qemu/guest-random.h" + +#define HELPER_HASH(op, key, store) \ +void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \ + target_ulong rb) \ +{ \ + uint64_t calculated_hash = hash_digest(ra, rb, key), loaded_hash; \ + \ + if (store) { \ + cpu_stq_data_ra(env, ea, calculated_hash, GETPC()); \ + } else { \ + loaded_hash = cpu_ldq_data_ra(env, ea, GETPC()); \ + if (loaded_hash != calculated_hash) { \ + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, \ + POWERPC_EXCP_TRAP, GETPC()); \ + } \ + } \ +} + +HELPER_HASH(HASHST, env->spr[SPR_HASHKEYR], true) +HELPER_HASH(HASHCHK, env->spr[SPR_HASHKEYR], false) +HELPER_HASH(HASHSTP, env->spr[SPR_HASHPKEYR], true) +HELPER_HASH(HASHCHKP, env->spr[SPR_HASHPKEYR], false) + #if !defined(CONFIG_USER_ONLY) #ifdef CONFIG_TCG diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 7ab6beadad..ae25f32d6e 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -348,7 +348,6 @@ static inline int float_overflow_excp(CPUPPCState *env) bool overflow_enabled = !!(env->fpscr & FP_OE); if (overflow_enabled) { - /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ @@ -367,7 +366,6 @@ static inline void float_underflow_excp(CPUPPCState *env) /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (env->fpscr & FP_UE) { - /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ @@ -832,30 +830,21 @@ static void float_invalid_op_sqrt(CPUPPCState *env, int flags, } } -/* fsqrt - fsqrt. */ -float64 helper_fsqrt(CPUPPCState *env, float64 arg) -{ - float64 ret = float64_sqrt(arg, &env->fp_status); - int flags = get_float_exception_flags(&env->fp_status); - - if (unlikely(flags & float_flag_invalid)) { - float_invalid_op_sqrt(env, flags, 1, GETPC()); - } - - return ret; +#define FPU_FSQRT(name, op) \ +float64 helper_##name(CPUPPCState *env, float64 arg) \ +{ \ + float64 ret = op(arg, &env->fp_status); \ + int flags = get_float_exception_flags(&env->fp_status); \ + \ + if (unlikely(flags & float_flag_invalid)) { \ + float_invalid_op_sqrt(env, flags, 1, GETPC()); \ + } \ + \ + return ret; \ } -/* fsqrts - fsqrts. */ -float64 helper_fsqrts(CPUPPCState *env, float64 arg) -{ - float64 ret = float64r32_sqrt(arg, &env->fp_status); - int flags = get_float_exception_flags(&env->fp_status); - - if (unlikely(flags & float_flag_invalid)) { - float_invalid_op_sqrt(env, flags, 1, GETPC()); - } - return ret; -} +FPU_FSQRT(FSQRT, float64_sqrt) +FPU_FSQRT(FSQRTS, float64r32_sqrt) /* fre - fre. */ float64 helper_fre(CPUPPCState *env, float64 arg) @@ -2178,7 +2167,7 @@ VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23) void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ ppc_vsr_t *s1, ppc_vsr_t *s2, ppc_vsr_t *s3) \ { \ - ppc_vsr_t t = *xt; \ + ppc_vsr_t t = { }; \ int i; \ \ helper_reset_fpstatus(env); \ @@ -2639,6 +2628,8 @@ uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ int all_true = 1; \ int all_false = 1; \ \ + helper_reset_fpstatus(env); \ + \ for (i = 0; i < nels; i++) { \ if (unlikely(tp##_is_any_nan(xa->fld) || \ tp##_is_any_nan(xb->fld))) { \ @@ -2692,6 +2683,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ ppc_vsr_t t = { }; \ int i; \ \ + helper_reset_fpstatus(env); \ + \ for (i = 0; i < nels; i++) { \ t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb->sfld, \ @@ -2717,6 +2710,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ ppc_vsr_t t = { }; \ int i; \ \ + helper_reset_fpstatus(env); \ + \ for (i = 0; i < nels; i++) { \ t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb->VsrD(i), \ @@ -2754,6 +2749,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ ppc_vsr_t t = *xt; \ int i; \ \ + helper_reset_fpstatus(env); \ + \ for (i = 0; i < nels; i++) { \ t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb->sfld, \ @@ -2789,6 +2786,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ ppc_vsr_t t = { }; \ int i; \ \ + helper_reset_fpstatus(env); \ + \ for (i = 0; i < nels; i++) { \ t.tfld = stp##_to_##ttp(xb->sfld, 1, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb->sfld, \ @@ -2836,6 +2835,8 @@ void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt, ppc_vsr_t t = { }; float_status tstat; + helper_reset_fpstatus(env); + tstat = env->fp_status; if (ro != 0) { tstat.float_rounding_mode = float_round_to_odd; @@ -2857,6 +2858,7 @@ uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) { uint64_t result, sign, exp, frac; + helper_reset_fpstatus(env); float_status tstat = env->fp_status; set_float_exception_flags(0, &tstat); @@ -2912,22 +2914,20 @@ uint64_t helper_XSCVSPDPN(uint64_t xb) #define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, sfi, rnan) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ - int all_flags = env->fp_status.float_exception_flags, flags; \ ppc_vsr_t t = { }; \ - int i; \ + int i, flags; \ + \ + helper_reset_fpstatus(env); \ \ for (i = 0; i < nels; i++) { \ - env->fp_status.float_exception_flags = 0; \ t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \ flags = env->fp_status.float_exception_flags; \ if (unlikely(flags & float_flag_invalid)) { \ t.tfld = float_invalid_cvt(env, flags, t.tfld, rnan, 0, GETPC());\ } \ - all_flags |= flags; \ } \ \ *xt = t; \ - env->fp_status.float_exception_flags = all_flags; \ do_float_check_status(env, sfi, GETPC()); \ } @@ -2979,12 +2979,12 @@ VSX_CVT_FP_TO_INT128(XSCVQPSQZ, int128, 0x8000000000000000ULL); #define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, sfi, rnan) \ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ { \ - int all_flags = env->fp_status.float_exception_flags, flags; \ ppc_vsr_t t = { }; \ - int i; \ + int i, flags; \ + \ + helper_reset_fpstatus(env); \ \ for (i = 0; i < nels; i++) { \ - env->fp_status.float_exception_flags = 0; \ t.VsrW(2 * i) = stp##_to_##ttp##_round_to_zero(xb->VsrD(i), \ &env->fp_status); \ flags = env->fp_status.float_exception_flags; \ @@ -2993,11 +2993,9 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ rnan, 0, GETPC()); \ } \ t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ - all_flags |= flags; \ } \ \ *xt = t; \ - env->fp_status.float_exception_flags = all_flags; \ do_float_check_status(env, sfi, GETPC()); \ } @@ -3022,6 +3020,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ ppc_vsr_t t = { }; \ int flags; \ \ + helper_reset_fpstatus(env); \ + \ t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \ flags = get_float_exception_flags(&env->fp_status); \ if (flags & float_flag_invalid) { \ @@ -3034,7 +3034,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \ 0x8000000000000000ULL) - VSX_CVT_FP_TO_INT_VECTOR(xscvqpswz, float128, int32, f128, VsrD(0), \ 0xffffffff80000000ULL) VSX_CVT_FP_TO_INT_VECTOR(xscvqpudz, float128, uint64, f128, VsrD(0), 0x0ULL) @@ -3057,6 +3056,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ ppc_vsr_t t = { }; \ int i; \ \ + helper_reset_fpstatus(env); \ + \ for (i = 0; i < nels; i++) { \ t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ if (r2sp) { \ @@ -3126,6 +3127,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ { \ ppc_vsr_t t = *xt; \ \ + helper_reset_fpstatus(env); \ t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ helper_compute_fprf_##ttp(env, t.tfld); \ \ @@ -3159,6 +3161,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ int i; \ FloatRoundMode curr_rounding_mode; \ \ + helper_reset_fpstatus(env); \ + \ if (rmode != FLOAT_ROUND_CURRENT) { \ curr_rounding_mode = get_float_rounding_mode(&env->fp_status); \ set_float_rounding_mode(rmode, &env->fp_status); \ diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 159b352f6e..57eee07256 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -4,6 +4,10 @@ DEF_HELPER_FLAGS_4(tw, TCG_CALL_NO_WG, void, env, tl, tl, i32) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32) #endif +DEF_HELPER_4(HASHST, void, env, tl, tl, tl) +DEF_HELPER_4(HASHCHK, void, env, tl, tl, tl) +DEF_HELPER_4(HASHSTP, void, env, tl, tl, tl) +DEF_HELPER_4(HASHCHKP, void, env, tl, tl, tl) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(store_msr, void, env, tl) DEF_HELPER_1(rfi, void, env) @@ -116,8 +120,8 @@ DEF_HELPER_4(fmadds, i64, env, i64, i64, i64) DEF_HELPER_4(fmsubs, i64, env, i64, i64, i64) DEF_HELPER_4(fnmadds, i64, env, i64, i64, i64) DEF_HELPER_4(fnmsubs, i64, env, i64, i64, i64) -DEF_HELPER_2(fsqrt, f64, env, f64) -DEF_HELPER_2(fsqrts, f64, env, f64) +DEF_HELPER_2(FSQRT, f64, env, f64) +DEF_HELPER_2(FSQRTS, f64, env, f64) DEF_HELPER_2(fre, i64, env, i64) DEF_HELPER_2(fres, i64, env, i64) DEF_HELPER_2(frsqrte, i64, env, i64) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index eb41efc100..a5249ee32c 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -20,6 +20,9 @@ &A frt fra frb frc rc:bool @A ...... frt:5 fra:5 frb:5 frc:5 ..... rc:1 &A +&A_tb frt frb rc:bool +@A_tb ...... frt:5 ..... frb:5 ..... ..... rc:1 &A_tb + &D rt ra si:int64_t @D ...... rt:5 ra:5 si:s16 &D @@ -172,6 +175,9 @@ @X_TSX ...... ..... ra:5 rb:5 .......... . &X rt=%x_rt_tsx @X_TSXP ...... ..... ra:5 rb:5 .......... . &X rt=%rt_tsxp +%x_dw 0:1 21:5 !function=dw_compose_ea +@X_DW ...... ..... ra:5 rb:5 .......... . &X rt=%x_dw + &X_frtp_vrb frtp vrb @X_frtp_vrb ...... ....0 ..... vrb:5 .......... . &X_frtp_vrb frtp=%x_frtp @@ -323,6 +329,13 @@ CNTTZDM 011111 ..... ..... ..... 1000111011 - @X PDEPD 011111 ..... ..... ..... 0010011100 - @X PEXTD 011111 ..... ..... ..... 0010111100 - @X +# Fixed-Point Hash Instructions + +HASHST 011111 ..... ..... ..... 1011010010 . @X_DW +HASHCHK 011111 ..... ..... ..... 1011110010 . @X_DW +HASHSTP 011111 ..... ..... ..... 1010010010 . @X_DW +HASHCHKP 011111 ..... ..... ..... 1010110010 . @X_DW + ## BCD Assist ADDG6S 011111 ..... ..... ..... - 001001010 - @X @@ -353,6 +366,11 @@ STFDU 110111 ..... ...... ............... @D STFDX 011111 ..... ...... .... 1011010111 - @X STFDUX 011111 ..... ...... .... 1011110111 - @X +### Floating-Point Arithmetic Instructions + +FSQRT 111111 ..... ----- ..... ----- 10110 . @A_tb +FSQRTS 111011 ..... ----- ..... ----- 10110 . @A_tb + ### Floating-Point Select Instruction FSEL 111111 ..... ..... ..... ..... 10111 . @A diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index d905f07d02..696096100b 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -37,9 +37,9 @@ static inline void helper_update_ov_legacy(CPUPPCState *env, int ov) { if (unlikely(ov)) { - env->so = env->ov = 1; + env->so = env->ov = env->ov32 = 1; } else { - env->ov = 0; + env->ov = env->ov32 = 0; } } diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 467f3046c8..337a362205 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -165,6 +165,9 @@ EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0) /* darn */ EXTRACT_HELPER(L, 16, 2); #endif +/* wait */ +EXTRACT_HELPER(WC, 21, 2); +EXTRACT_HELPER(PL, 16, 2); /*** Jump target decoding ***/ /* Immediate address */ diff --git a/target/ppc/machine.c b/target/ppc/machine.c index a7d9036c09..be6eb3d968 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -234,7 +234,7 @@ static bool pvr_match(PowerPCCPU *cpu, uint32_t pvr) if (pvr == pcc->pvr) { return true; } - return pcc->pvr_match(pcc, pvr); + return pcc->pvr_match(pcc, pvr, true); } static int cpu_post_load(void *opaque, int version_id) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 5a18ee577f..e810842925 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -4071,12 +4071,91 @@ static void gen_sync(DisasContext *ctx) /* wait */ static void gen_wait(DisasContext *ctx) { - TCGv_i32 t0 = tcg_const_i32(1); - tcg_gen_st_i32(t0, cpu_env, - -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted)); - tcg_temp_free_i32(t0); - /* Stop translation, as the CPU is supposed to sleep from now */ - gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); + uint32_t wc; + + if (ctx->insns_flags & PPC_WAIT) { + /* v2.03-v2.07 define an older incompatible 'wait' encoding. */ + + if (ctx->insns_flags2 & PPC2_PM_ISA206) { + /* v2.06 introduced the WC field. WC > 0 may be treated as no-op. */ + wc = WC(ctx->opcode); + } else { + wc = 0; + } + + } else if (ctx->insns_flags2 & PPC2_ISA300) { + /* v3.0 defines a new 'wait' encoding. */ + wc = WC(ctx->opcode); + if (ctx->insns_flags2 & PPC2_ISA310) { + uint32_t pl = PL(ctx->opcode); + + /* WC 1,2 may be treated as no-op. WC 3 is reserved. */ + if (wc == 3) { + gen_invalid(ctx); + return; + } + + /* PL 1-3 are reserved. If WC=2 then the insn is treated as noop. */ + if (pl > 0 && wc != 2) { + gen_invalid(ctx); + return; + } + + } else { /* ISA300 */ + /* WC 1-3 are reserved */ + if (wc > 0) { + gen_invalid(ctx); + return; + } + } + + } else { + warn_report("wait instruction decoded with wrong ISA flags."); + gen_invalid(ctx); + return; + } + + /* + * wait without WC field or with WC=0 waits for an exception / interrupt + * to occur. + */ + if (wc == 0) { + TCGv_i32 t0 = tcg_const_i32(1); + tcg_gen_st_i32(t0, cpu_env, + -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted)); + tcg_temp_free_i32(t0); + /* Stop translation, as the CPU is supposed to sleep from now */ + gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next); + } + + /* + * Other wait types must not just wait until an exception occurs because + * ignoring their other wake-up conditions could cause a hang. + * + * For v2.06 and 2.07, wc=1,2,3 are architected but may be implemented as + * no-ops. + * + * wc=1 and wc=3 explicitly allow the instruction to be treated as a no-op. + * + * wc=2 waits for an implementation-specific condition, such could be + * always true, so it can be implemented as a no-op. + * + * For v3.1, wc=1,2 are architected but may be implemented as no-ops. + * + * wc=1 (waitrsv) waits for an exception or a reservation to be lost. + * Reservation-loss may have implementation-specific conditions, so it + * can be implemented as a no-op. + * + * wc=2 waits for an exception or an amount of time to pass. This + * amount is implementation-specific so it can be implemented as a + * no-op. + * + * ISA v3.1 allows for execution to resume "in the rare case of + * an implementation-dependent event", so in any case software must + * not depend on the architected resumption condition to become + * true, so no-op implementations should be architecturally correct + * (if suboptimal). + */ } #if defined(TARGET_PPC64) @@ -6364,6 +6443,14 @@ static inline void get_fpr(TCGv_i64 dst, int regno) static inline void set_fpr(int regno, TCGv_i64 src) { tcg_gen_st_i64(src, cpu_env, fpr_offset(regno)); + /* + * Before PowerISA v3.1 the result of doubleword 1 of the VSR + * corresponding to the target FPR was undefined. However, + * most (if not all) real hardware were setting the result to 0. + * Starting at ISA v3.1, the result for doubleword 1 is now defined + * to be 0. + */ + tcg_gen_st_i64(tcg_constant_i64(0), cpu_env, vsr64_offset(regno, false)); } static inline void get_avr64(TCGv_i64 dst, int regno, bool high) @@ -6394,6 +6481,11 @@ static int times_16(DisasContext *ctx, int x) return x * 16; } +static int64_t dw_compose_ea(DisasContext *ctx, int x) +{ + return deposit64(0xfffffffffffffe00, 3, 6, x); +} + /* * Helpers for trans_* functions to check for specific insns flags. * Use token pasting to ensure that we use the proper flag with the @@ -6691,8 +6783,9 @@ GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B), GEN_HANDLER_E(stqcx_, 0x1F, 0x16, 0x05, 0, PPC_NONE, PPC2_LSQ_ISA207), #endif GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC), -GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT), -GEN_HANDLER_E(wait, 0x1F, 0x1E, 0x00, 0x039FF801, PPC_NONE, PPC2_ISA300), +/* ISA v3.0 changed the extended opcode from 62 to 30 */ +GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x039FF801, PPC_WAIT), +GEN_HANDLER_E(wait, 0x1F, 0x1E, 0x00, 0x039CF801, PPC_NONE, PPC2_ISA300), GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW), GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW), GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW), @@ -7639,11 +7732,12 @@ static const TranslatorOps ppc_tr_ops = { .disas_log = ppc_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&ppc_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &ppc_tr_ops, &ctx.base); } void restore_state_to_opc(CPUPPCState *env, TranslationBlock *tb, diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index db14d3bebc..1ba56cbed5 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -540,3 +540,37 @@ static bool trans_CBCDTD(DisasContext *ctx, arg_X_sa *a) gen_helper_CBCDTD(cpu_gpr[a->ra], cpu_gpr[a->rs]); return true; } + +static bool do_hash(DisasContext *ctx, arg_X *a, bool priv, + void (*helper)(TCGv_ptr, TCGv, TCGv, TCGv)) +{ + TCGv ea; + + if (!(ctx->insns_flags2 & PPC2_ISA310)) { + /* if version is before v3.1, this operation is a nop */ + return true; + } + + if (priv) { + /* if instruction is privileged but the context is in user space */ + REQUIRE_SV(ctx); + } + + if (unlikely(a->ra == 0)) { + /* if RA=0, the instruction form is invalid */ + gen_invalid(ctx); + return true; + } + + ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->rt)); + helper(cpu_env, ea, cpu_gpr[a->ra], cpu_gpr[a->rb]); + + tcg_temp_free(ea); + + return true; +} + +TRANS(HASHST, do_hash, false, gen_helper_HASHST) +TRANS(HASHCHK, do_hash, false, gen_helper_HASHCHK) +TRANS(HASHSTP, do_hash, true, gen_helper_HASHSTP) +TRANS(HASHCHKP, do_hash, true, gen_helper_HASHCHKP) diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc index 0e893eafa7..8d5cf0f982 100644 --- a/target/ppc/translate/fp-impl.c.inc +++ b/target/ppc/translate/fp-impl.c.inc @@ -254,50 +254,34 @@ static bool trans_FSEL(DisasContext *ctx, arg_A *a) GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); /* Optional: */ -/* fsqrt */ -static void gen_fsqrt(DisasContext *ctx) +static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a, + void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64)) { - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1; + + REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSQRT); + REQUIRE_FPU(ctx); + t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); + gen_reset_fpstatus(); - get_fpr(t0, rB(ctx->opcode)); - gen_helper_fsqrt(t1, cpu_env, t0); - set_fpr(rD(ctx->opcode), t1); + get_fpr(t0, a->frb); + helper(t1, cpu_env, t0); + set_fpr(a->frt, t1); gen_compute_fprf_float64(t1); - if (unlikely(Rc(ctx->opcode) != 0)) { + if (unlikely(a->rc != 0)) { gen_set_cr1_from_fpscr(ctx); } + tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); + + return true; } -static void gen_fsqrts(DisasContext *ctx) -{ - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - gen_reset_fpstatus(); - get_fpr(t0, rB(ctx->opcode)); - gen_helper_fsqrts(t1, cpu_env, t0); - set_fpr(rD(ctx->opcode), t1); - gen_compute_fprf_float64(t1); - if (unlikely(Rc(ctx->opcode) != 0)) { - gen_set_cr1_from_fpscr(ctx); - } - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); -} +TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT); +TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS); /*** Floating-Point multiply-and-add ***/ /* fmadd - fmadds */ diff --git a/target/ppc/translate/fp-ops.c.inc b/target/ppc/translate/fp-ops.c.inc index 1b65f5ab73..d4c6c4bed1 100644 --- a/target/ppc/translate/fp-ops.c.inc +++ b/target/ppc/translate/fp-ops.c.inc @@ -62,8 +62,6 @@ GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205), GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES), -GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), -GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT), GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT), GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT), diff --git a/target/riscv/arch_dump.c b/target/riscv/arch_dump.c index 709f621d82..736a232956 100644 --- a/target/riscv/arch_dump.c +++ b/target/riscv/arch_dump.c @@ -64,12 +64,11 @@ static void riscv64_note_init(struct riscv64_note *note, DumpState *s, } int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { struct riscv64_note note; RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - DumpState *s = opaque; int ret, i = 0; const char name[] = "CORE"; @@ -134,12 +133,11 @@ static void riscv32_note_init(struct riscv32_note *note, DumpState *s, } int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { struct riscv32_note note; RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - DumpState *s = opaque; int ret, i; const char name[] = "CORE"; diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 1bb3973806..e6d9c706bb 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -22,7 +22,9 @@ #include "qemu/ctype.h" #include "qemu/log.h" #include "cpu.h" +#include "pmu.h" #include "internals.h" +#include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -43,9 +45,88 @@ static const char riscv_single_letter_exts[] = "IEMAFDQCPVH"; struct isa_ext_data { const char *name; - bool enabled; + bool multi_letter; + int min_version; + int ext_enable_offset; }; +#define ISA_EXT_DATA_ENTRY(_name, _m_letter, _min_ver, _prop) \ +{#_name, _m_letter, _min_ver, offsetof(struct RISCVCPUConfig, _prop)} + +/** + * Here are the ordering rules of extension naming defined by RISC-V + * specification : + * 1. All extensions should be separated from other multi-letter extensions + * by an underscore. + * 2. The first letter following the 'Z' conventionally indicates the most + * closely related alphabetical extension category, IMAFDQLCBKJTPVH. + * If multiple 'Z' extensions are named, they should be ordered first + * by category, then alphabetically within a category. + * 3. Standard supervisor-level extensions (starts with 'S') should be + * listed after standard unprivileged extensions. If multiple + * supervisor-level extensions are listed, they should be ordered + * alphabetically. + * 4. Non-standard extensions (starts with 'X') must be listed after all + * standard extensions. They must be separated from other multi-letter + * extensions by an underscore. + */ +static const struct isa_ext_data isa_edata_arr[] = { + ISA_EXT_DATA_ENTRY(h, false, PRIV_VERSION_1_12_0, ext_h), + ISA_EXT_DATA_ENTRY(v, false, PRIV_VERSION_1_12_0, ext_v), + ISA_EXT_DATA_ENTRY(zicsr, true, PRIV_VERSION_1_10_0, ext_icsr), + ISA_EXT_DATA_ENTRY(zifencei, true, PRIV_VERSION_1_10_0, ext_ifencei), + ISA_EXT_DATA_ENTRY(zihintpause, true, PRIV_VERSION_1_10_0, ext_zihintpause), + ISA_EXT_DATA_ENTRY(zfh, true, PRIV_VERSION_1_12_0, ext_zfh), + ISA_EXT_DATA_ENTRY(zfhmin, true, PRIV_VERSION_1_12_0, ext_zfhmin), + ISA_EXT_DATA_ENTRY(zfinx, true, PRIV_VERSION_1_12_0, ext_zfinx), + ISA_EXT_DATA_ENTRY(zdinx, true, PRIV_VERSION_1_12_0, ext_zdinx), + ISA_EXT_DATA_ENTRY(zba, true, PRIV_VERSION_1_12_0, ext_zba), + ISA_EXT_DATA_ENTRY(zbb, true, PRIV_VERSION_1_12_0, ext_zbb), + ISA_EXT_DATA_ENTRY(zbc, true, PRIV_VERSION_1_12_0, ext_zbc), + ISA_EXT_DATA_ENTRY(zbkb, true, PRIV_VERSION_1_12_0, ext_zbkb), + ISA_EXT_DATA_ENTRY(zbkc, true, PRIV_VERSION_1_12_0, ext_zbkc), + ISA_EXT_DATA_ENTRY(zbkx, true, PRIV_VERSION_1_12_0, ext_zbkx), + ISA_EXT_DATA_ENTRY(zbs, true, PRIV_VERSION_1_12_0, ext_zbs), + ISA_EXT_DATA_ENTRY(zk, true, PRIV_VERSION_1_12_0, ext_zk), + ISA_EXT_DATA_ENTRY(zkn, true, PRIV_VERSION_1_12_0, ext_zkn), + ISA_EXT_DATA_ENTRY(zknd, true, PRIV_VERSION_1_12_0, ext_zknd), + ISA_EXT_DATA_ENTRY(zkne, true, PRIV_VERSION_1_12_0, ext_zkne), + ISA_EXT_DATA_ENTRY(zknh, true, PRIV_VERSION_1_12_0, ext_zknh), + ISA_EXT_DATA_ENTRY(zkr, true, PRIV_VERSION_1_12_0, ext_zkr), + ISA_EXT_DATA_ENTRY(zks, true, PRIV_VERSION_1_12_0, ext_zks), + ISA_EXT_DATA_ENTRY(zksed, true, PRIV_VERSION_1_12_0, ext_zksed), + ISA_EXT_DATA_ENTRY(zksh, true, PRIV_VERSION_1_12_0, ext_zksh), + ISA_EXT_DATA_ENTRY(zkt, true, PRIV_VERSION_1_12_0, ext_zkt), + ISA_EXT_DATA_ENTRY(zve32f, true, PRIV_VERSION_1_12_0, ext_zve32f), + ISA_EXT_DATA_ENTRY(zve64f, true, PRIV_VERSION_1_12_0, ext_zve64f), + ISA_EXT_DATA_ENTRY(zhinx, true, PRIV_VERSION_1_12_0, ext_zhinx), + ISA_EXT_DATA_ENTRY(zhinxmin, true, PRIV_VERSION_1_12_0, ext_zhinxmin), + ISA_EXT_DATA_ENTRY(smaia, true, PRIV_VERSION_1_12_0, ext_smaia), + ISA_EXT_DATA_ENTRY(ssaia, true, PRIV_VERSION_1_12_0, ext_ssaia), + ISA_EXT_DATA_ENTRY(sscofpmf, true, PRIV_VERSION_1_12_0, ext_sscofpmf), + ISA_EXT_DATA_ENTRY(sstc, true, PRIV_VERSION_1_12_0, ext_sstc), + ISA_EXT_DATA_ENTRY(svinval, true, PRIV_VERSION_1_12_0, ext_svinval), + ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot), + ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt), + ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), +}; + +static bool isa_ext_is_enabled(RISCVCPU *cpu, + const struct isa_ext_data *edata) +{ + bool *ext_enabled = (void *)&cpu->cfg + edata->ext_enable_offset; + + return *ext_enabled; +} + +static void isa_ext_update_enabled(RISCVCPU *cpu, + const struct isa_ext_data *edata, bool en) +{ + bool *ext_enabled = (void *)&cpu->cfg + edata->ext_enable_offset; + + *ext_enabled = en; +} + const char * const riscv_int_regnames[] = { "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1", "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3", @@ -147,13 +228,6 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } -static void set_resetvec(CPURISCVState *env, target_ulong resetvec) -{ -#ifndef CONFIG_USER_ONLY - env->resetvec = resetvec; -#endif -} - static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -255,7 +329,6 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); - set_resetvec(env, DEFAULT_RSTVEC); cpu->cfg.mmu = false; } #endif @@ -389,6 +462,18 @@ static void riscv_cpu_set_pc(CPUState *cs, vaddr value) } } +static vaddr riscv_cpu_get_pc(CPUState *cs) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + + /* Match cpu_get_tb_cpu_state. */ + if (env->xl == MXL_RV32) { + return env->pc & UINT32_MAX; + } + return env->pc; +} + static void riscv_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -397,9 +482,9 @@ static void riscv_cpu_synchronize_from_tb(CPUState *cs, RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL); if (xl == MXL_RV32) { - env->pc = (int32_t)tb->pc; + env->pc = (int32_t)tb_pc(tb); } else { - env->pc = tb->pc; + env->pc = tb_pc(tb); } } @@ -530,7 +615,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) CPURISCVState *env = &cpu->env; RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); CPUClass *cc = CPU_CLASS(mcc); - int priv_version = -1; + int i, priv_version = -1; Error *local_err = NULL; cpu_exec_realizefn(cs, &local_err); @@ -558,6 +643,23 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) set_priv_version(env, priv_version); } + /* Force disable extensions if priv spec version does not match */ + for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { + if (isa_ext_is_enabled(cpu, &isa_edata_arr[i]) && + (env->priv_ver < isa_edata_arr[i].min_version)) { + isa_ext_update_enabled(cpu, &isa_edata_arr[i], false); +#ifndef CONFIG_USER_ONLY + warn_report("disabling %s extension for hart 0x%lx because " + "privilege spec version does not match", + isa_edata_arr[i].name, (unsigned long)env->mhartid); +#else + warn_report("disabling %s extension because " + "privilege spec version does not match", + isa_edata_arr[i].name); +#endif + } + } + if (cpu->cfg.mmu) { riscv_set_feature(env, RISCV_FEATURE_MMU); } @@ -574,15 +676,16 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } } - if (cpu->cfg.aia) { - riscv_set_feature(env, RISCV_FEATURE_AIA); - } - if (cpu->cfg.debug) { riscv_set_feature(env, RISCV_FEATURE_DEBUG); } - set_resetvec(env, cpu->cfg.resetvec); + +#ifndef CONFIG_USER_ONLY + if (cpu->cfg.ext_sstc) { + riscv_timer_init(cpu); + } +#endif /* CONFIG_USER_ONLY */ /* Validate that MISA_MXL is set properly. */ switch (env->misa_mxl_max) { @@ -619,11 +722,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) cpu->cfg.ext_ifencei = true; } - if (cpu->cfg.ext_m && cpu->cfg.ext_zmmul) { - warn_report("Zmmul will override M"); - cpu->cfg.ext_m = false; - } - if (cpu->cfg.ext_i && cpu->cfg.ext_e) { error_setg(errp, "I and E extensions are incompatible"); @@ -636,6 +734,23 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) return; } + if (cpu->cfg.ext_s && !cpu->cfg.ext_u) { + error_setg(errp, + "Setting S extension without U extension is illegal"); + return; + } + + if (cpu->cfg.ext_h && !cpu->cfg.ext_i) { + error_setg(errp, + "H depends on an I base integer ISA with 32 x registers"); + return; + } + + if (cpu->cfg.ext_h && !cpu->cfg.ext_s) { + error_setg(errp, "H extension implicitly requires S-mode"); + return; + } + if (cpu->cfg.ext_f && !cpu->cfg.ext_icsr) { error_setg(errp, "F extension requires Zicsr"); return; @@ -779,6 +894,15 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) set_misa(env, env->misa_mxl, ext); } +#ifndef CONFIG_USER_ONLY + if (cpu->cfg.pmu_num) { + if (!riscv_pmu_init(cpu, cpu->cfg.pmu_num) && cpu->cfg.ext_sscofpmf) { + cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + riscv_pmu_timer_cb, cpu); + } + } +#endif + riscv_cpu_register_gdb_regs_for_features(cs); qemu_init_vcpu(cs); @@ -883,14 +1007,17 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("v", RISCVCPU, cfg.ext_v, false), DEFINE_PROP_BOOL("h", RISCVCPU, cfg.ext_h, true), DEFINE_PROP_UINT8("pmu-num", RISCVCPU, cfg.pmu_num, 16), + DEFINE_PROP_BOOL("sscofpmf", RISCVCPU, cfg.ext_sscofpmf, false), DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true), DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), + DEFINE_PROP_BOOL("Zihintpause", RISCVCPU, cfg.ext_zihintpause, true), DEFINE_PROP_BOOL("Zfh", RISCVCPU, cfg.ext_zfh, false), DEFINE_PROP_BOOL("Zfhmin", RISCVCPU, cfg.ext_zfhmin, false), DEFINE_PROP_BOOL("Zve32f", RISCVCPU, cfg.ext_zve32f, false), DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), + DEFINE_PROP_BOOL("sstc", RISCVCPU, cfg.ext_sstc, true), DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), @@ -924,15 +1051,17 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("zhinx", RISCVCPU, cfg.ext_zhinx, false), DEFINE_PROP_BOOL("zhinxmin", RISCVCPU, cfg.ext_zhinxmin, false), + DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false), + /* Vendor-specific custom extensions */ DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), /* These are experimental so mark with 'x-' */ DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false), - DEFINE_PROP_BOOL("x-zmmul", RISCVCPU, cfg.ext_zmmul, false), /* ePMP 0.9.3 */ DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false), - DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false), + DEFINE_PROP_BOOL("x-smaia", RISCVCPU, cfg.ext_smaia, false), + DEFINE_PROP_BOOL("x-ssaia", RISCVCPU, cfg.ext_ssaia, false), DEFINE_PROP_END_OF_LIST(), }; @@ -953,11 +1082,14 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_UINT64("marchid", RISCVCPU, cfg.marchid, RISCV_CPU_MARCHID), DEFINE_PROP_UINT64("mimpid", RISCVCPU, cfg.mimpid, RISCV_CPU_MIMPID), - DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC), +#ifndef CONFIG_USER_ONLY + DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), +#endif DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false), DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false), + DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false), DEFINE_PROP_END_OF_LIST(), }; @@ -1034,6 +1166,7 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->has_work = riscv_cpu_has_work; cc->dump_state = riscv_cpu_dump_state; cc->set_pc = riscv_cpu_set_pc; + cc->get_pc = riscv_cpu_get_pc; cc->gdb_read_register = riscv_cpu_gdb_read_register; cc->gdb_write_register = riscv_cpu_gdb_write_register; cc->gdb_num_core_regs = 33; @@ -1049,67 +1182,15 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) device_class_set_props(dc, riscv_cpu_properties); } -#define ISA_EDATA_ENTRY(name, prop) {#name, cpu->cfg.prop} - static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len) { char *old = *isa_str; char *new = *isa_str; int i; - /** - * Here are the ordering rules of extension naming defined by RISC-V - * specification : - * 1. All extensions should be separated from other multi-letter extensions - * by an underscore. - * 2. The first letter following the 'Z' conventionally indicates the most - * closely related alphabetical extension category, IMAFDQLCBKJTPVH. - * If multiple 'Z' extensions are named, they should be ordered first - * by category, then alphabetically within a category. - * 3. Standard supervisor-level extensions (starts with 'S') should be - * listed after standard unprivileged extensions. If multiple - * supervisor-level extensions are listed, they should be ordered - * alphabetically. - * 4. Non-standard extensions (starts with 'X') must be listed after all - * standard extensions. They must be separated from other multi-letter - * extensions by an underscore. - */ - struct isa_ext_data isa_edata_arr[] = { - ISA_EDATA_ENTRY(zicsr, ext_icsr), - ISA_EDATA_ENTRY(zifencei, ext_ifencei), - ISA_EDATA_ENTRY(zmmul, ext_zmmul), - ISA_EDATA_ENTRY(zfh, ext_zfh), - ISA_EDATA_ENTRY(zfhmin, ext_zfhmin), - ISA_EDATA_ENTRY(zfinx, ext_zfinx), - ISA_EDATA_ENTRY(zdinx, ext_zdinx), - ISA_EDATA_ENTRY(zba, ext_zba), - ISA_EDATA_ENTRY(zbb, ext_zbb), - ISA_EDATA_ENTRY(zbc, ext_zbc), - ISA_EDATA_ENTRY(zbkb, ext_zbkb), - ISA_EDATA_ENTRY(zbkc, ext_zbkc), - ISA_EDATA_ENTRY(zbkx, ext_zbkx), - ISA_EDATA_ENTRY(zbs, ext_zbs), - ISA_EDATA_ENTRY(zk, ext_zk), - ISA_EDATA_ENTRY(zkn, ext_zkn), - ISA_EDATA_ENTRY(zknd, ext_zknd), - ISA_EDATA_ENTRY(zkne, ext_zkne), - ISA_EDATA_ENTRY(zknh, ext_zknh), - ISA_EDATA_ENTRY(zkr, ext_zkr), - ISA_EDATA_ENTRY(zks, ext_zks), - ISA_EDATA_ENTRY(zksed, ext_zksed), - ISA_EDATA_ENTRY(zksh, ext_zksh), - ISA_EDATA_ENTRY(zkt, ext_zkt), - ISA_EDATA_ENTRY(zve32f, ext_zve32f), - ISA_EDATA_ENTRY(zve64f, ext_zve64f), - ISA_EDATA_ENTRY(zhinx, ext_zhinx), - ISA_EDATA_ENTRY(zhinxmin, ext_zhinxmin), - ISA_EDATA_ENTRY(svinval, ext_svinval), - ISA_EDATA_ENTRY(svnapot, ext_svnapot), - ISA_EDATA_ENTRY(svpbmt, ext_svpbmt), - }; - for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) { - if (isa_edata_arr[i].enabled) { + if (isa_edata_arr[i].multi_letter && + isa_ext_is_enabled(cpu, &isa_edata_arr[i])) { new = g_strconcat(old, "_", isa_edata_arr[i].name, NULL); g_free(old); old = new; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 5c7acc055a..3a9e25053f 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -85,7 +85,6 @@ enum { RISCV_FEATURE_PMP, RISCV_FEATURE_EPMP, RISCV_FEATURE_MISA, - RISCV_FEATURE_AIA, RISCV_FEATURE_DEBUG }; @@ -137,6 +136,8 @@ typedef struct PMUCTRState { /* Snapshort value of a counter in RV32 */ target_ulong mhpmcounterh_prev; bool started; + /* Value beyond UINT32_MAX/UINT64_MAX before overflow interrupt trigger */ + target_ulong irq_overflow_left; } PMUCTRState; struct CPUArchState { @@ -189,7 +190,7 @@ struct CPUArchState { /* This contains QEMU specific information about the virt state. */ target_ulong virt; target_ulong geilen; - target_ulong resetvec; + uint64_t resetvec; target_ulong mhartid; /* @@ -285,6 +286,11 @@ struct CPUArchState { /* Signals whether the current exception occurred with two-stage address translation active. */ bool two_stage_lookup; + /* + * Signals whether the current exception occurred while doing two-stage + * address translation for the VS-stage page table walk. + */ + bool two_stage_indirect_lookup; target_ulong scounteren; target_ulong mcounteren; @@ -297,13 +303,20 @@ struct CPUArchState { /* PMU event selector configured values. First three are unused*/ target_ulong mhpmevent_val[RV_MAX_MHPMEVENTS]; + /* PMU event selector configured values for RV32*/ + target_ulong mhpmeventh_val[RV_MAX_MHPMEVENTS]; + target_ulong sscratch; target_ulong mscratch; /* temporary htif regs */ uint64_t mfromhost; uint64_t mtohost; - uint64_t timecmp; + + /* Sstc CSRs */ + uint64_t stimecmp; + + uint64_t vstimecmp; /* physical memory protection */ pmp_table_t pmp_state; @@ -311,7 +324,11 @@ struct CPUArchState { /* trigger module */ target_ulong trigger_cur; - type2_trigger_t type2_trig[TRIGGER_TYPE2_NUM]; + target_ulong tdata1[RV_MAX_TRIGGERS]; + target_ulong tdata2[RV_MAX_TRIGGERS]; + target_ulong tdata3[RV_MAX_TRIGGERS]; + struct CPUBreakpoint *cpu_breakpoint[RV_MAX_TRIGGERS]; + struct CPUWatchpoint *cpu_watchpoint[RV_MAX_TRIGGERS]; /* machine specific rdtime callback */ uint64_t (*rdtime_fn)(void *); @@ -358,7 +375,9 @@ struct CPUArchState { float_status fp_status; /* Fields from here on are preserved across CPU reset. */ - QEMUTimer *timer; /* Internal timer */ + QEMUTimer *stimer; /* Internal timer for S-mode interrupt */ + QEMUTimer *vstimer; /* Internal timer for VS-mode interrupt */ + bool vstime_irq; hwaddr kernel_addr; hwaddr fdt_addr; @@ -421,6 +440,8 @@ struct RISCVCPUConfig { bool ext_zkt; bool ext_ifencei; bool ext_icsr; + bool ext_zihintpause; + bool ext_sstc; bool ext_svinval; bool ext_svnapot; bool ext_svpbmt; @@ -433,7 +454,11 @@ struct RISCVCPUConfig { bool ext_zve32f; bool ext_zve64f; bool ext_zmmul; + bool ext_smaia; + bool ext_ssaia; + bool ext_sscofpmf; bool rvv_ta_all_1s; + bool rvv_ma_all_1s; uint32_t mvendorid; uint64_t marchid; @@ -452,9 +477,7 @@ struct RISCVCPUConfig { bool mmu; bool pmp; bool epmp; - bool aia; bool debug; - uint64_t resetvec; bool short_isa_string; }; @@ -479,6 +502,12 @@ struct ArchCPU { /* Configuration Settings */ RISCVCPUConfig cfg; + + QEMUTimer *pmu_timer; + /* A bitmask of Available programmable counters */ + uint32_t pmu_avail_ctrs; + /* Mapping of events to counters */ + GHashTable *pmu_event_ctr_map; }; static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext) @@ -505,9 +534,9 @@ extern const char * const riscv_fpr_regnames[]; const char *riscv_cpu_get_trap_name(target_ulong cause, bool async); void riscv_cpu_do_interrupt(CPUState *cpu); int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero); @@ -591,6 +620,7 @@ FIELD(TB_FLAGS, XL, 20, 2) FIELD(TB_FLAGS, PM_MASK_ENABLED, 22, 1) FIELD(TB_FLAGS, PM_BASE_ENABLED, 23, 1) FIELD(TB_FLAGS, VTA, 24, 1) +FIELD(TB_FLAGS, VMA, 25, 1) #ifdef TARGET_RISCV32 #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32) @@ -738,6 +768,19 @@ enum { CSR_TABLE_SIZE = 0x1000 }; +/** + * The event id are encoded based on the encoding specified in the + * SBI specification v0.3 + */ + +enum riscv_pmu_event_idx { + RISCV_PMU_EVENT_HW_CPU_CYCLES = 0x01, + RISCV_PMU_EVENT_HW_INSTRUCTIONS = 0x02, + RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS = 0x10019, + RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS = 0x1001B, + RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS = 0x10021, +}; + /* CSR function table */ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 6be5a9e9f0..d8f5f0abed 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -190,8 +190,6 @@ /* Supervisor Trap Setup */ #define CSR_SSTATUS 0x100 -#define CSR_SEDELEG 0x102 -#define CSR_SIDELEG 0x103 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 #define CSR_SCOUNTEREN 0x106 @@ -206,6 +204,10 @@ #define CSR_STVAL 0x143 #define CSR_SIP 0x144 +/* Sstc supervisor CSRs */ +#define CSR_STIMECMP 0x14D +#define CSR_STIMECMPH 0x15D + /* Supervisor Protection and Translation */ #define CSR_SPTBR 0x180 #define CSR_SATP 0x180 @@ -253,6 +255,10 @@ #define CSR_VSIP 0x244 #define CSR_VSATP 0x280 +/* Sstc virtual CSRs */ +#define CSR_VSTIMECMP 0x24D +#define CSR_VSTIMECMPH 0x25D + #define CSR_MTINST 0x34a #define CSR_MTVAL2 0x34b @@ -313,6 +319,7 @@ #define CSR_TDATA1 0x7a1 #define CSR_TDATA2 0x7a2 #define CSR_TDATA3 0x7a3 +#define CSR_TINFO 0x7a4 /* Debug Mode Registers */ #define CSR_DCSR 0x7b0 @@ -382,6 +389,37 @@ #define CSR_MHPMEVENT29 0x33d #define CSR_MHPMEVENT30 0x33e #define CSR_MHPMEVENT31 0x33f + +#define CSR_MHPMEVENT3H 0x723 +#define CSR_MHPMEVENT4H 0x724 +#define CSR_MHPMEVENT5H 0x725 +#define CSR_MHPMEVENT6H 0x726 +#define CSR_MHPMEVENT7H 0x727 +#define CSR_MHPMEVENT8H 0x728 +#define CSR_MHPMEVENT9H 0x729 +#define CSR_MHPMEVENT10H 0x72a +#define CSR_MHPMEVENT11H 0x72b +#define CSR_MHPMEVENT12H 0x72c +#define CSR_MHPMEVENT13H 0x72d +#define CSR_MHPMEVENT14H 0x72e +#define CSR_MHPMEVENT15H 0x72f +#define CSR_MHPMEVENT16H 0x730 +#define CSR_MHPMEVENT17H 0x731 +#define CSR_MHPMEVENT18H 0x732 +#define CSR_MHPMEVENT19H 0x733 +#define CSR_MHPMEVENT20H 0x734 +#define CSR_MHPMEVENT21H 0x735 +#define CSR_MHPMEVENT22H 0x736 +#define CSR_MHPMEVENT23H 0x737 +#define CSR_MHPMEVENT24H 0x738 +#define CSR_MHPMEVENT25H 0x739 +#define CSR_MHPMEVENT26H 0x73a +#define CSR_MHPMEVENT27H 0x73b +#define CSR_MHPMEVENT28H 0x73c +#define CSR_MHPMEVENT29H 0x73d +#define CSR_MHPMEVENT30H 0x73e +#define CSR_MHPMEVENT31H 0x73f + #define CSR_MHPMCOUNTER3H 0xb83 #define CSR_MHPMCOUNTER4H 0xb84 #define CSR_MHPMCOUNTER5H 0xb85 @@ -443,6 +481,7 @@ #define CSR_VSMTE 0x2c0 #define CSR_VSPMMASK 0x2c1 #define CSR_VSPMBASE 0x2c2 +#define CSR_SCOUNTOVF 0xda0 /* Crypto Extension */ #define CSR_SEED 0x015 @@ -620,6 +659,7 @@ typedef enum RISCVException { #define IRQ_VS_EXT 10 #define IRQ_M_EXT 11 #define IRQ_S_GEXT 12 +#define IRQ_PMU_OVF 13 #define IRQ_LOCAL_MAX 16 #define IRQ_LOCAL_GUEST_MAX (TARGET_LONG_BITS - 1) @@ -637,11 +677,13 @@ typedef enum RISCVException { #define MIP_VSEIP (1 << IRQ_VS_EXT) #define MIP_MEIP (1 << IRQ_M_EXT) #define MIP_SGEIP (1 << IRQ_S_GEXT) +#define MIP_LCOFIP (1 << IRQ_PMU_OVF) /* sip masks */ #define SIP_SSIP MIP_SSIP #define SIP_STIP MIP_STIP #define SIP_SEIP MIP_SEIP +#define SIP_LCOFIP MIP_LCOFIP /* MIE masks */ #define MIE_SEIE (1 << IRQ_S_EXT) @@ -795,4 +837,24 @@ typedef enum RISCVException { #define SEED_OPST_WAIT (0b01 << 30) #define SEED_OPST_ES16 (0b10 << 30) #define SEED_OPST_DEAD (0b11 << 30) +/* PMU related bits */ +#define MIE_LCOFIE (1 << IRQ_PMU_OVF) + +#define MHPMEVENT_BIT_OF BIT_ULL(63) +#define MHPMEVENTH_BIT_OF BIT(31) +#define MHPMEVENT_BIT_MINH BIT_ULL(62) +#define MHPMEVENTH_BIT_MINH BIT(30) +#define MHPMEVENT_BIT_SINH BIT_ULL(61) +#define MHPMEVENTH_BIT_SINH BIT(29) +#define MHPMEVENT_BIT_UINH BIT_ULL(60) +#define MHPMEVENTH_BIT_UINH BIT(28) +#define MHPMEVENT_BIT_VSINH BIT_ULL(59) +#define MHPMEVENTH_BIT_VSINH BIT(27) +#define MHPMEVENT_BIT_VUINH BIT_ULL(58) +#define MHPMEVENTH_BIT_VUINH BIT(26) + +#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000) +#define MHPMEVENT_IDX_MASK 0xFFFFF +#define MHPMEVENT_SSCOF_RESVD 16 + #endif diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 59b3680b1b..278d163803 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -21,10 +21,13 @@ #include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" +#include "pmu.h" #include "exec/exec-all.h" +#include "instmap.h" #include "tcg/tcg-op.h" #include "trace.h" #include "semihosting/common-semi.h" +#include "cpu_bits.h" int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) { @@ -67,6 +70,8 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax); flags = FIELD_DP32(flags, TB_FLAGS, VTA, FIELD_EX64(env->vtype, VTYPE, VTA)); + flags = FIELD_DP32(flags, TB_FLAGS, VMA, + FIELD_EX64(env->vtype, VTYPE, VMA)); } else { flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1); } @@ -304,6 +309,7 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env, int extirq, unsigned int extirq_def_prio, uint64_t pending, uint8_t *iprio) { + RISCVCPU *cpu = env_archcpu(env); int irq, best_irq = RISCV_EXCP_NONE; unsigned int prio, best_prio = UINT_MAX; @@ -312,7 +318,7 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env, } irq = ctz64(pending); - if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + if (!((extirq == IRQ_M_EXT) ? cpu->cfg.ext_smaia : cpu->cfg.ext_ssaia)) { return irq; } @@ -342,8 +348,9 @@ uint64_t riscv_cpu_all_pending(CPURISCVState *env) { uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN); uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; + uint64_t vstip = (env->vstime_irq) ? MIP_VSTIP : 0; - return (env->mip | vsgein) & env->mie; + return (env->mip | vsgein | vstip) & env->mie; } int riscv_cpu_mirq_pending(CPURISCVState *env) @@ -602,7 +609,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) { CPURISCVState *env = &cpu->env; CPUState *cs = CPU(cpu); - uint64_t gein, vsgein = 0, old = env->mip; + uint64_t gein, vsgein = 0, vstip = 0, old = env->mip; bool locked = false; if (riscv_cpu_virt_enabled(env)) { @@ -610,6 +617,10 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; } + /* No need to update mip for VSTIP */ + mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask; + vstip = env->vstime_irq ? MIP_VSTIP : 0; + if (!qemu_mutex_iothread_locked()) { locked = true; qemu_mutex_lock_iothread(); @@ -617,7 +628,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) env->mip = (env->mip & ~mask) | (value & mask); - if (env->mip | vsgein) { + if (env->mip | vsgein | vstip) { cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); @@ -1053,7 +1064,8 @@ restart: static void raise_mmu_exception(CPURISCVState *env, target_ulong address, MMUAccessType access_type, bool pmp_violation, - bool first_stage, bool two_stage) + bool first_stage, bool two_stage, + bool two_stage_indirect) { CPUState *cs = env_cpu(env); int page_fault_exceptions, vm; @@ -1103,6 +1115,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, } env->badaddr = address; env->two_stage_lookup = two_stage; + env->two_stage_indirect_lookup = two_stage_indirect; } hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) @@ -1148,6 +1161,7 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, env->badaddr = addr; env->two_stage_lookup = riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(mmu_idx); + env->two_stage_indirect_lookup = false; cpu_loop_exit_restore(cs, retaddr); } @@ -1173,9 +1187,32 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, env->badaddr = addr; env->two_stage_lookup = riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(mmu_idx); + env->two_stage_indirect_lookup = false; cpu_loop_exit_restore(cs, retaddr); } + +static void pmu_tlb_fill_incr_ctr(RISCVCPU *cpu, MMUAccessType access_type) +{ + enum riscv_pmu_event_idx pmu_event_type; + + switch (access_type) { + case MMU_INST_FETCH: + pmu_event_type = RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS; + break; + case MMU_DATA_LOAD: + pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS; + break; + case MMU_DATA_STORE: + pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS; + break; + default: + return; + } + + riscv_pmu_incr_ctr(cpu, pmu_event_type); +} + bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) @@ -1188,6 +1225,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, bool pmp_violation = false; bool first_stage_error = true; bool two_stage_lookup = false; + bool two_stage_indirect_error = false; int ret = TRANSLATE_FAIL; int mode = mmu_idx; /* default TLB page size */ @@ -1225,6 +1263,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, */ if (ret == TRANSLATE_G_STAGE_FAIL) { first_stage_error = false; + two_stage_indirect_error = true; access_type = MMU_DATA_LOAD; } @@ -1272,6 +1311,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } } } else { + pmu_tlb_fill_incr_ctr(cpu, access_type); /* Single stage lookup */ ret = get_physical_address(env, &pa, &prot, address, NULL, access_type, mmu_idx, true, false, false); @@ -1308,12 +1348,218 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, raise_mmu_exception(env, address, access_type, pmp_violation, first_stage_error, riscv_cpu_virt_enabled(env) || - riscv_cpu_two_stage_lookup(mmu_idx)); + riscv_cpu_two_stage_lookup(mmu_idx), + two_stage_indirect_error); cpu_loop_exit_restore(cs, retaddr); } return true; } + +static target_ulong riscv_transformed_insn(CPURISCVState *env, + target_ulong insn, + target_ulong taddr) +{ + target_ulong xinsn = 0; + target_ulong access_rs1 = 0, access_imm = 0, access_size = 0; + + /* + * Only Quadrant 0 and Quadrant 2 of RVC instruction space need to + * be uncompressed. The Quadrant 1 of RVC instruction space need + * not be transformed because these instructions won't generate + * any load/store trap. + */ + + if ((insn & 0x3) != 0x3) { + /* Transform 16bit instruction into 32bit instruction */ + switch (GET_C_OP(insn)) { + case OPC_RISC_C_OP_QUAD0: /* Quadrant 0 */ + switch (GET_C_FUNC(insn)) { + case OPC_RISC_C_FUNC_FLD_LQ: + if (riscv_cpu_xlen(env) != 128) { /* C.FLD (RV32/64) */ + xinsn = OPC_RISC_FLD; + xinsn = SET_RD(xinsn, GET_C_RS2S(insn)); + access_rs1 = GET_C_RS1S(insn); + access_imm = GET_C_LD_IMM(insn); + access_size = 8; + } + break; + case OPC_RISC_C_FUNC_LW: /* C.LW */ + xinsn = OPC_RISC_LW; + xinsn = SET_RD(xinsn, GET_C_RS2S(insn)); + access_rs1 = GET_C_RS1S(insn); + access_imm = GET_C_LW_IMM(insn); + access_size = 4; + break; + case OPC_RISC_C_FUNC_FLW_LD: + if (riscv_cpu_xlen(env) == 32) { /* C.FLW (RV32) */ + xinsn = OPC_RISC_FLW; + xinsn = SET_RD(xinsn, GET_C_RS2S(insn)); + access_rs1 = GET_C_RS1S(insn); + access_imm = GET_C_LW_IMM(insn); + access_size = 4; + } else { /* C.LD (RV64/RV128) */ + xinsn = OPC_RISC_LD; + xinsn = SET_RD(xinsn, GET_C_RS2S(insn)); + access_rs1 = GET_C_RS1S(insn); + access_imm = GET_C_LD_IMM(insn); + access_size = 8; + } + break; + case OPC_RISC_C_FUNC_FSD_SQ: + if (riscv_cpu_xlen(env) != 128) { /* C.FSD (RV32/64) */ + xinsn = OPC_RISC_FSD; + xinsn = SET_RS2(xinsn, GET_C_RS2S(insn)); + access_rs1 = GET_C_RS1S(insn); + access_imm = GET_C_SD_IMM(insn); + access_size = 8; + } + break; + case OPC_RISC_C_FUNC_SW: /* C.SW */ + xinsn = OPC_RISC_SW; + xinsn = SET_RS2(xinsn, GET_C_RS2S(insn)); + access_rs1 = GET_C_RS1S(insn); + access_imm = GET_C_SW_IMM(insn); + access_size = 4; + break; + case OPC_RISC_C_FUNC_FSW_SD: + if (riscv_cpu_xlen(env) == 32) { /* C.FSW (RV32) */ + xinsn = OPC_RISC_FSW; + xinsn = SET_RS2(xinsn, GET_C_RS2S(insn)); + access_rs1 = GET_C_RS1S(insn); + access_imm = GET_C_SW_IMM(insn); + access_size = 4; + } else { /* C.SD (RV64/RV128) */ + xinsn = OPC_RISC_SD; + xinsn = SET_RS2(xinsn, GET_C_RS2S(insn)); + access_rs1 = GET_C_RS1S(insn); + access_imm = GET_C_SD_IMM(insn); + access_size = 8; + } + break; + default: + break; + } + break; + case OPC_RISC_C_OP_QUAD2: /* Quadrant 2 */ + switch (GET_C_FUNC(insn)) { + case OPC_RISC_C_FUNC_FLDSP_LQSP: + if (riscv_cpu_xlen(env) != 128) { /* C.FLDSP (RV32/64) */ + xinsn = OPC_RISC_FLD; + xinsn = SET_RD(xinsn, GET_C_RD(insn)); + access_rs1 = 2; + access_imm = GET_C_LDSP_IMM(insn); + access_size = 8; + } + break; + case OPC_RISC_C_FUNC_LWSP: /* C.LWSP */ + xinsn = OPC_RISC_LW; + xinsn = SET_RD(xinsn, GET_C_RD(insn)); + access_rs1 = 2; + access_imm = GET_C_LWSP_IMM(insn); + access_size = 4; + break; + case OPC_RISC_C_FUNC_FLWSP_LDSP: + if (riscv_cpu_xlen(env) == 32) { /* C.FLWSP (RV32) */ + xinsn = OPC_RISC_FLW; + xinsn = SET_RD(xinsn, GET_C_RD(insn)); + access_rs1 = 2; + access_imm = GET_C_LWSP_IMM(insn); + access_size = 4; + } else { /* C.LDSP (RV64/RV128) */ + xinsn = OPC_RISC_LD; + xinsn = SET_RD(xinsn, GET_C_RD(insn)); + access_rs1 = 2; + access_imm = GET_C_LDSP_IMM(insn); + access_size = 8; + } + break; + case OPC_RISC_C_FUNC_FSDSP_SQSP: + if (riscv_cpu_xlen(env) != 128) { /* C.FSDSP (RV32/64) */ + xinsn = OPC_RISC_FSD; + xinsn = SET_RS2(xinsn, GET_C_RS2(insn)); + access_rs1 = 2; + access_imm = GET_C_SDSP_IMM(insn); + access_size = 8; + } + break; + case OPC_RISC_C_FUNC_SWSP: /* C.SWSP */ + xinsn = OPC_RISC_SW; + xinsn = SET_RS2(xinsn, GET_C_RS2(insn)); + access_rs1 = 2; + access_imm = GET_C_SWSP_IMM(insn); + access_size = 4; + break; + case 7: + if (riscv_cpu_xlen(env) == 32) { /* C.FSWSP (RV32) */ + xinsn = OPC_RISC_FSW; + xinsn = SET_RS2(xinsn, GET_C_RS2(insn)); + access_rs1 = 2; + access_imm = GET_C_SWSP_IMM(insn); + access_size = 4; + } else { /* C.SDSP (RV64/RV128) */ + xinsn = OPC_RISC_SD; + xinsn = SET_RS2(xinsn, GET_C_RS2(insn)); + access_rs1 = 2; + access_imm = GET_C_SDSP_IMM(insn); + access_size = 8; + } + break; + default: + break; + } + break; + default: + break; + } + + /* + * Clear Bit1 of transformed instruction to indicate that + * original insruction was a 16bit instruction + */ + xinsn &= ~((target_ulong)0x2); + } else { + /* Transform 32bit (or wider) instructions */ + switch (MASK_OP_MAJOR(insn)) { + case OPC_RISC_ATOMIC: + xinsn = insn; + access_rs1 = GET_RS1(insn); + access_size = 1 << GET_FUNCT3(insn); + break; + case OPC_RISC_LOAD: + case OPC_RISC_FP_LOAD: + xinsn = SET_I_IMM(insn, 0); + access_rs1 = GET_RS1(insn); + access_imm = GET_IMM(insn); + access_size = 1 << GET_FUNCT3(insn); + break; + case OPC_RISC_STORE: + case OPC_RISC_FP_STORE: + xinsn = SET_S_IMM(insn, 0); + access_rs1 = GET_RS1(insn); + access_imm = GET_STORE_IMM(insn); + access_size = 1 << GET_FUNCT3(insn); + break; + case OPC_RISC_SYSTEM: + if (MASK_OP_SYSTEM(insn) == OPC_RISC_HLVHSV) { + xinsn = insn; + access_rs1 = GET_RS1(insn); + access_size = 1 << ((GET_FUNCT7(insn) >> 1) & 0x3); + access_size = 1 << access_size; + } + break; + default: + break; + } + } + + if (access_size) { + xinsn = SET_RS1(xinsn, (taddr - (env->gpr[access_rs1] + access_imm)) & + (access_size - 1)); + } + + return xinsn; +} #endif /* !CONFIG_USER_ONLY */ /* @@ -1338,35 +1584,56 @@ void riscv_cpu_do_interrupt(CPUState *cs) target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; uint64_t deleg = async ? env->mideleg : env->medeleg; target_ulong tval = 0; + target_ulong tinst = 0; target_ulong htval = 0; target_ulong mtval2 = 0; if (cause == RISCV_EXCP_SEMIHOST) { - if (env->priv >= PRV_S) { - do_common_semihosting(cs); - env->pc += 4; - return; - } - cause = RISCV_EXCP_BREAKPOINT; + do_common_semihosting(cs); + env->pc += 4; + return; } if (!async) { /* set tval to badaddr for traps with address information */ switch (cause) { - case RISCV_EXCP_INST_GUEST_PAGE_FAULT: case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT: case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT: - case RISCV_EXCP_INST_ADDR_MIS: - case RISCV_EXCP_INST_ACCESS_FAULT: case RISCV_EXCP_LOAD_ADDR_MIS: case RISCV_EXCP_STORE_AMO_ADDR_MIS: case RISCV_EXCP_LOAD_ACCESS_FAULT: case RISCV_EXCP_STORE_AMO_ACCESS_FAULT: - case RISCV_EXCP_INST_PAGE_FAULT: case RISCV_EXCP_LOAD_PAGE_FAULT: case RISCV_EXCP_STORE_PAGE_FAULT: write_gva = env->two_stage_lookup; tval = env->badaddr; + if (env->two_stage_indirect_lookup) { + /* + * special pseudoinstruction for G-stage fault taken while + * doing VS-stage page table walk. + */ + tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000; + } else { + /* + * The "Addr. Offset" field in transformed instruction is + * non-zero only for misaligned access. + */ + tinst = riscv_transformed_insn(env, env->bins, tval); + } + break; + case RISCV_EXCP_INST_GUEST_PAGE_FAULT: + case RISCV_EXCP_INST_ADDR_MIS: + case RISCV_EXCP_INST_ACCESS_FAULT: + case RISCV_EXCP_INST_PAGE_FAULT: + write_gva = env->two_stage_lookup; + tval = env->badaddr; + if (env->two_stage_indirect_lookup) { + /* + * special pseudoinstruction for G-stage fault taken while + * doing VS-stage page table walk. + */ + tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000; + } break; case RISCV_EXCP_ILLEGAL_INST: case RISCV_EXCP_VIRT_INSTRUCTION_FAULT: @@ -1446,6 +1713,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->sepc = env->pc; env->stval = tval; env->htval = htval; + env->htinst = tinst; env->pc = (env->stvec >> 2 << 2) + ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); riscv_cpu_set_mode(env, PRV_S); @@ -1476,6 +1744,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->mepc = env->pc; env->mtval = tval; env->mtval2 = mtval2; + env->mtinst = tinst; env->pc = (env->mtvec >> 2 << 2) + ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); riscv_cpu_set_mode(env, PRV_M); @@ -1488,6 +1757,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) */ env->two_stage_lookup = false; + env->two_stage_indirect_lookup = false; #endif cs->exception_index = RISCV_EXCP_NONE; /* mark handled to qemu */ } diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 235f2a011e..5c9a7ee287 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -22,6 +22,7 @@ #include "qemu/timer.h" #include "cpu.h" #include "pmu.h" +#include "time_helper.h" #include "qemu/main-loop.h" #include "exec/exec-all.h" #include "sysemu/cpu-timers.h" @@ -74,7 +75,8 @@ static RISCVException ctr(CPURISCVState *env, int csrno) CPUState *cs = env_cpu(env); RISCVCPU *cpu = RISCV_CPU(cs); int ctr_index; - int base_csrno = CSR_HPMCOUNTER3; + target_ulong ctr_mask; + int base_csrno = CSR_CYCLE; bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false; if (rv32 && csrno >= CSR_CYCLEH) { @@ -82,121 +84,36 @@ static RISCVException ctr(CPURISCVState *env, int csrno) base_csrno += 0x80; } ctr_index = csrno - base_csrno; + ctr_mask = BIT(ctr_index); - if (!cpu->cfg.pmu_num || ctr_index >= (cpu->cfg.pmu_num)) { + if ((csrno >= CSR_CYCLE && csrno <= CSR_INSTRET) || + (csrno >= CSR_CYCLEH && csrno <= CSR_INSTRETH)) { + goto skip_ext_pmu_check; + } + + if (!(cpu->pmu_avail_ctrs & ctr_mask)) { /* No counter is enabled in PMU or the counter is out of range */ return RISCV_EXCP_ILLEGAL_INST; } - if (env->priv == PRV_S) { - switch (csrno) { - case CSR_CYCLE: - if (!get_field(env->mcounteren, COUNTEREN_CY)) { - return RISCV_EXCP_ILLEGAL_INST; - } - break; - case CSR_TIME: - if (!get_field(env->mcounteren, COUNTEREN_TM)) { - return RISCV_EXCP_ILLEGAL_INST; - } - break; - case CSR_INSTRET: - if (!get_field(env->mcounteren, COUNTEREN_IR)) { - return RISCV_EXCP_ILLEGAL_INST; - } - break; - case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31: - ctr_index = csrno - CSR_CYCLE; - if (!get_field(env->mcounteren, 1 << ctr_index)) { - return RISCV_EXCP_ILLEGAL_INST; - } - break; - } - if (rv32) { - switch (csrno) { - case CSR_CYCLEH: - if (!get_field(env->mcounteren, COUNTEREN_CY)) { - return RISCV_EXCP_ILLEGAL_INST; - } - break; - case CSR_TIMEH: - if (!get_field(env->mcounteren, COUNTEREN_TM)) { - return RISCV_EXCP_ILLEGAL_INST; - } - break; - case CSR_INSTRETH: - if (!get_field(env->mcounteren, COUNTEREN_IR)) { - return RISCV_EXCP_ILLEGAL_INST; - } - break; - case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H: - ctr_index = csrno - CSR_CYCLEH; - if (!get_field(env->mcounteren, 1 << ctr_index)) { - return RISCV_EXCP_ILLEGAL_INST; - } - break; - } - } +skip_ext_pmu_check: + + if (env->priv < PRV_M && !get_field(env->mcounteren, ctr_mask)) { + return RISCV_EXCP_ILLEGAL_INST; } if (riscv_cpu_virt_enabled(env)) { - switch (csrno) { - case CSR_CYCLE: - if (!get_field(env->hcounteren, COUNTEREN_CY) && - get_field(env->mcounteren, COUNTEREN_CY)) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - case CSR_TIME: - if (!get_field(env->hcounteren, COUNTEREN_TM) && - get_field(env->mcounteren, COUNTEREN_TM)) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - case CSR_INSTRET: - if (!get_field(env->hcounteren, COUNTEREN_IR) && - get_field(env->mcounteren, COUNTEREN_IR)) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31: - ctr_index = csrno - CSR_CYCLE; - if (!get_field(env->hcounteren, 1 << ctr_index) && - get_field(env->mcounteren, 1 << ctr_index)) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - } - if (rv32) { - switch (csrno) { - case CSR_CYCLEH: - if (!get_field(env->hcounteren, COUNTEREN_CY) && - get_field(env->mcounteren, COUNTEREN_CY)) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - case CSR_TIMEH: - if (!get_field(env->hcounteren, COUNTEREN_TM) && - get_field(env->mcounteren, COUNTEREN_TM)) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - case CSR_INSTRETH: - if (!get_field(env->hcounteren, COUNTEREN_IR) && - get_field(env->mcounteren, COUNTEREN_IR)) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H: - ctr_index = csrno - CSR_CYCLEH; - if (!get_field(env->hcounteren, 1 << ctr_index) && - get_field(env->mcounteren, 1 << ctr_index)) { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } - break; - } + if (!get_field(env->hcounteren, ctr_mask) || + (env->priv == PRV_U && !get_field(env->scounteren, ctr_mask))) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } } + + if (riscv_has_ext(env, RVS) && env->priv == PRV_U && + !get_field(env->scounteren, ctr_mask)) { + return RISCV_EXCP_ILLEGAL_INST; + } + #endif return RISCV_EXCP_NONE; } @@ -240,6 +157,18 @@ static RISCVException mctr32(CPURISCVState *env, int csrno) return mctr(env, csrno); } +static RISCVException sscofpmf(CPURISCVState *env, int csrno) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (!cpu->cfg.ext_sscofpmf) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return RISCV_EXCP_NONE; +} + static RISCVException any(CPURISCVState *env, int csrno) { return RISCV_EXCP_NONE; @@ -257,7 +186,9 @@ static RISCVException any32(CPURISCVState *env, int csrno) static int aia_any(CPURISCVState *env, int csrno) { - if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + RISCVCPU *cpu = env_archcpu(env); + + if (!cpu->cfg.ext_smaia) { return RISCV_EXCP_ILLEGAL_INST; } @@ -266,7 +197,9 @@ static int aia_any(CPURISCVState *env, int csrno) static int aia_any32(CPURISCVState *env, int csrno) { - if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + RISCVCPU *cpu = env_archcpu(env); + + if (!cpu->cfg.ext_smaia) { return RISCV_EXCP_ILLEGAL_INST; } @@ -293,7 +226,9 @@ static int smode32(CPURISCVState *env, int csrno) static int aia_smode(CPURISCVState *env, int csrno) { - if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + RISCVCPU *cpu = env_archcpu(env); + + if (!cpu->cfg.ext_ssaia) { return RISCV_EXCP_ILLEGAL_INST; } @@ -302,7 +237,9 @@ static int aia_smode(CPURISCVState *env, int csrno) static int aia_smode32(CPURISCVState *env, int csrno) { - if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + RISCVCPU *cpu = env_archcpu(env); + + if (!cpu->cfg.ext_ssaia) { return RISCV_EXCP_ILLEGAL_INST; } @@ -311,15 +248,8 @@ static int aia_smode32(CPURISCVState *env, int csrno) static RISCVException hmode(CPURISCVState *env, int csrno) { - if (riscv_has_ext(env, RVS) && - riscv_has_ext(env, RVH)) { - /* Hypervisor extension is supported */ - if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) || - env->priv == PRV_M) { - return RISCV_EXCP_NONE; - } else { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } + if (riscv_has_ext(env, RVH)) { + return RISCV_EXCP_NONE; } return RISCV_EXCP_ILLEGAL_INST; @@ -328,17 +258,31 @@ static RISCVException hmode(CPURISCVState *env, int csrno) static RISCVException hmode32(CPURISCVState *env, int csrno) { if (riscv_cpu_mxl(env) != MXL_RV32) { - if (!riscv_cpu_virt_enabled(env)) { - return RISCV_EXCP_ILLEGAL_INST; - } else { - return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; - } + return RISCV_EXCP_ILLEGAL_INST; } return hmode(env, csrno); } +static RISCVException umode(CPURISCVState *env, int csrno) +{ + if (riscv_has_ext(env, RVU)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; +} + +static RISCVException umode32(CPURISCVState *env, int csrno) +{ + if (riscv_cpu_mxl(env) != MXL_RV32) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return umode(env, csrno); +} + /* Checks if PointerMasking registers could be accessed */ static RISCVException pointer_masking(CPURISCVState *env, int csrno) { @@ -351,7 +295,9 @@ static RISCVException pointer_masking(CPURISCVState *env, int csrno) static int aia_hmode(CPURISCVState *env, int csrno) { - if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + RISCVCPU *cpu = env_archcpu(env); + + if (!cpu->cfg.ext_ssaia) { return RISCV_EXCP_ILLEGAL_INST; } @@ -360,7 +306,9 @@ static int aia_hmode(CPURISCVState *env, int csrno) static int aia_hmode32(CPURISCVState *env, int csrno) { - if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + RISCVCPU *cpu = env_archcpu(env); + + if (!cpu->cfg.ext_ssaia) { return RISCV_EXCP_ILLEGAL_INST; } @@ -663,9 +611,39 @@ static int read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) static int write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val) { int evt_index = csrno - CSR_MCOUNTINHIBIT; + uint64_t mhpmevt_val = val; env->mhpmevent_val[evt_index] = val; + if (riscv_cpu_mxl(env) == MXL_RV32) { + mhpmevt_val = mhpmevt_val | + ((uint64_t)env->mhpmeventh_val[evt_index] << 32); + } + riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); + + return RISCV_EXCP_NONE; +} + +static int read_mhpmeventh(CPURISCVState *env, int csrno, target_ulong *val) +{ + int evt_index = csrno - CSR_MHPMEVENT3H + 3; + + *val = env->mhpmeventh_val[evt_index]; + + return RISCV_EXCP_NONE; +} + +static int write_mhpmeventh(CPURISCVState *env, int csrno, target_ulong val) +{ + int evt_index = csrno - CSR_MHPMEVENT3H + 3; + uint64_t mhpmevth_val = val; + uint64_t mhpmevt_val = env->mhpmevent_val[evt_index]; + + mhpmevt_val = mhpmevt_val | (mhpmevth_val << 32); + env->mhpmeventh_val[evt_index] = val; + + riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); + return RISCV_EXCP_NONE; } @@ -673,12 +651,20 @@ static int write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val) { int ctr_idx = csrno - CSR_MCYCLE; PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; + uint64_t mhpmctr_val = val; counter->mhpmcounter_val = val; if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { counter->mhpmcounter_prev = get_ticks(false); - } else { + if (ctr_idx > 2) { + if (riscv_cpu_mxl(env) == MXL_RV32) { + mhpmctr_val = mhpmctr_val | + ((uint64_t)counter->mhpmcounterh_val << 32); + } + riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx); + } + } else { /* Other counters can keep incrementing from the given value */ counter->mhpmcounter_prev = val; } @@ -690,11 +676,17 @@ static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val) { int ctr_idx = csrno - CSR_MCYCLEH; PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; + uint64_t mhpmctr_val = counter->mhpmcounter_val; + uint64_t mhpmctrh_val = val; counter->mhpmcounterh_val = val; + mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32); if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { counter->mhpmcounterh_prev = get_ticks(true); + if (ctr_idx > 2) { + riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx); + } } else { counter->mhpmcounterh_prev = val; } @@ -770,6 +762,32 @@ static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) return riscv_pmu_read_ctr(env, val, true, ctr_index); } +static int read_scountovf(CPURISCVState *env, int csrno, target_ulong *val) +{ + int mhpmevt_start = CSR_MHPMEVENT3 - CSR_MCOUNTINHIBIT; + int i; + *val = 0; + target_ulong *mhpm_evt_val; + uint64_t of_bit_mask; + + if (riscv_cpu_mxl(env) == MXL_RV32) { + mhpm_evt_val = env->mhpmeventh_val; + of_bit_mask = MHPMEVENTH_BIT_OF; + } else { + mhpm_evt_val = env->mhpmevent_val; + of_bit_mask = MHPMEVENT_BIT_OF; + } + + for (i = mhpmevt_start; i < RV_MAX_MHPMEVENTS; i++) { + if ((get_field(env->mcounteren, BIT(i))) && + (mhpm_evt_val[i] & of_bit_mask)) { + *val |= BIT(i); + } + } + + return RISCV_EXCP_NONE; +} + static RISCVException read_time(CPURISCVState *env, int csrno, target_ulong *val) { @@ -796,10 +814,161 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException sstc(CPURISCVState *env, int csrno) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + bool hmode_check = false; + + if (!cpu->cfg.ext_sstc || !env->rdtime_fn) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (env->priv == PRV_M) { + return RISCV_EXCP_NONE; + } + + /* + * No need of separate function for rv32 as menvcfg stores both menvcfg + * menvcfgh for RV32. + */ + if (!(get_field(env->mcounteren, COUNTEREN_TM) && + get_field(env->menvcfg, MENVCFG_STCE))) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (riscv_cpu_virt_enabled(env)) { + if (!(get_field(env->hcounteren, COUNTEREN_TM) & + get_field(env->henvcfg, HENVCFG_STCE))) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + } + + if ((csrno == CSR_VSTIMECMP) || (csrno == CSR_VSTIMECMPH)) { + hmode_check = true; + } + + return hmode_check ? hmode(env, csrno) : smode(env, csrno); +} + +static RISCVException sstc_32(CPURISCVState *env, int csrno) +{ + if (riscv_cpu_mxl(env) != MXL_RV32) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return sstc(env, csrno); +} + +static RISCVException read_vstimecmp(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->vstimecmp; + + return RISCV_EXCP_NONE; +} + +static RISCVException read_vstimecmph(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->vstimecmp >> 32; + + return RISCV_EXCP_NONE; +} + +static RISCVException write_vstimecmp(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + if (riscv_cpu_mxl(env) == MXL_RV32) { + env->vstimecmp = deposit64(env->vstimecmp, 0, 32, (uint64_t)val); + } else { + env->vstimecmp = val; + } + + riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + + return RISCV_EXCP_NONE; +} + +static RISCVException write_vstimecmph(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + env->vstimecmp = deposit64(env->vstimecmp, 32, 32, (uint64_t)val); + riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + + return RISCV_EXCP_NONE; +} + +static RISCVException read_stimecmp(CPURISCVState *env, int csrno, + target_ulong *val) +{ + if (riscv_cpu_virt_enabled(env)) { + *val = env->vstimecmp; + } else { + *val = env->stimecmp; + } + + return RISCV_EXCP_NONE; +} + +static RISCVException read_stimecmph(CPURISCVState *env, int csrno, + target_ulong *val) +{ + if (riscv_cpu_virt_enabled(env)) { + *val = env->vstimecmp >> 32; + } else { + *val = env->stimecmp >> 32; + } + + return RISCV_EXCP_NONE; +} + +static RISCVException write_stimecmp(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + if (riscv_cpu_virt_enabled(env)) { + return write_vstimecmp(env, csrno, val); + } + + if (riscv_cpu_mxl(env) == MXL_RV32) { + env->stimecmp = deposit64(env->stimecmp, 0, 32, (uint64_t)val); + } else { + env->stimecmp = val; + } + + riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP); + + return RISCV_EXCP_NONE; +} + +static RISCVException write_stimecmph(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + if (riscv_cpu_virt_enabled(env)) { + return write_vstimecmph(env, csrno, val); + } + + env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val); + riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP); + + return RISCV_EXCP_NONE; +} + /* Machine constants */ #define M_MODE_INTERRUPTS ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP)) -#define S_MODE_INTERRUPTS ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP)) +#define S_MODE_INTERRUPTS ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP | \ + MIP_LCOFIP)) #define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) #define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS)) @@ -840,7 +1009,8 @@ static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS & 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_VS; -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; +static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP | + SIP_LCOFIP; static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; static const target_ulong vsip_writable_mask = MIP_VSSIP; @@ -1487,10 +1657,6 @@ static RISCVException write_mtvec(CPURISCVState *env, int csrno, static RISCVException read_mcountinhibit(CPURISCVState *env, int csrno, target_ulong *val) { - if (env->priv_ver < PRIV_VERSION_1_11_0) { - return RISCV_EXCP_ILLEGAL_INST; - } - *val = env->mcountinhibit; return RISCV_EXCP_NONE; } @@ -1501,10 +1667,6 @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, int cidx; PMUCTRState *counter; - if (env->priv_ver < PRIV_VERSION_1_11_0) { - return RISCV_EXCP_ILLEGAL_INST; - } - env->mcountinhibit = val; /* Check if any other counter is also monitoring cycles/instructions */ @@ -1712,6 +1874,12 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno, new_val |= env->external_seip * MIP_SEIP; } + if (cpu->cfg.ext_sstc && (env->priv == PRV_M) && + get_field(env->menvcfg, MENVCFG_STCE)) { + /* sstc extension forbids STIP & VSTIP to be writeable in mip */ + mask = mask & ~(MIP_STIP | MIP_VSTIP); + } + if (mask) { old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask)); } else { @@ -1721,6 +1889,7 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno, if (csrno != CSR_HVIP) { gin = get_field(env->hstatus, HSTATUS_VGEIN); old_mip |= (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VSEIP : 0; + old_mip |= env->vstime_irq ? MIP_VSTIP : 0; } if (ret_val) { @@ -2901,7 +3070,7 @@ static RISCVException read_tdata(CPURISCVState *env, int csrno, target_ulong *val) { /* return 0 in tdata1 to end the trigger enumeration */ - if (env->trigger_cur >= TRIGGER_NUM && csrno == CSR_TDATA1) { + if (env->trigger_cur >= RV_MAX_TRIGGERS && csrno == CSR_TDATA1) { *val = 0; return RISCV_EXCP_NONE; } @@ -2925,6 +3094,13 @@ static RISCVException write_tdata(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException read_tinfo(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = tinfo_csr_read(env); + return RISCV_EXCP_NONE; +} + /* * Functions to access Pointer Masking feature registers * We have to check if current priv lvl could modify @@ -3263,16 +3439,38 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env, /* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */ int read_only = get_field(csrno, 0xC00) == 3; int csr_min_priv = csr_ops[csrno].min_priv_ver; + + /* ensure the CSR extension is enabled. */ + if (!cpu->cfg.ext_icsr) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (env->priv_ver < csr_min_priv) { + return RISCV_EXCP_ILLEGAL_INST; + } + + /* check predicate */ + if (!csr_ops[csrno].predicate) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (write_mask && read_only) { + return RISCV_EXCP_ILLEGAL_INST; + } + + RISCVException ret = csr_ops[csrno].predicate(env, csrno); + if (ret != RISCV_EXCP_NONE) { + return ret; + } + #if !defined(CONFIG_USER_ONLY) int csr_priv, effective_priv = env->priv; - if (riscv_has_ext(env, RVH) && env->priv == PRV_S) { + if (riscv_has_ext(env, RVH) && env->priv == PRV_S && + !riscv_cpu_virt_enabled(env)) { /* - * We are in either HS or VS mode. - * Add 1 to the effective privledge level to allow us to access the - * Hypervisor CSRs. The `hmode` predicate will determine if access - * should be allowed(HS) or if a virtual instruction exception should be - * raised(VS). + * We are in HS mode. Add 1 to the effective privledge level to + * allow us to access the Hypervisor CSRs. */ effective_priv++; } @@ -3285,25 +3483,7 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env, return RISCV_EXCP_ILLEGAL_INST; } #endif - if (write_mask && read_only) { - return RISCV_EXCP_ILLEGAL_INST; - } - - /* ensure the CSR extension is enabled. */ - if (!cpu->cfg.ext_icsr) { - return RISCV_EXCP_ILLEGAL_INST; - } - - /* check predicate */ - if (!csr_ops[csrno].predicate) { - return RISCV_EXCP_ILLEGAL_INST; - } - - if (env->priv_ver < csr_min_priv) { - return RISCV_EXCP_ILLEGAL_INST; - } - - return csr_ops[csrno].predicate(env, csrno); + return RISCV_EXCP_NONE; } static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, @@ -3461,20 +3641,20 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_FRM] = { "frm", fs, read_frm, write_frm }, [CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr }, /* Vector CSRs */ - [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VL] = { "vl", vs, read_vl, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VTYPE] = { "vtype", vs, read_vtype, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VLENB] = { "vlenb", vs, read_vlenb, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VL] = { "vl", vs, read_vl, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VTYPE] = { "vtype", vs, read_vtype, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VLENB] = { "vlenb", vs, read_vlenb, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* User Timers and Counters */ [CSR_CYCLE] = { "cycle", ctr, read_hpmcounter }, [CSR_INSTRET] = { "instret", ctr, read_hpmcounter }, @@ -3493,10 +3673,14 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { #if !defined(CONFIG_USER_ONLY) /* Machine Timers and Counters */ - [CSR_MCYCLE] = { "mcycle", any, read_hpmcounter, write_mhpmcounter}, - [CSR_MINSTRET] = { "minstret", any, read_hpmcounter, write_mhpmcounter}, - [CSR_MCYCLEH] = { "mcycleh", any32, read_hpmcounterh, write_mhpmcounterh}, - [CSR_MINSTRETH] = { "minstreth", any32, read_hpmcounterh, write_mhpmcounterh}, + [CSR_MCYCLE] = { "mcycle", any, read_hpmcounter, + write_mhpmcounter }, + [CSR_MINSTRET] = { "minstret", any, read_hpmcounter, + write_mhpmcounter }, + [CSR_MCYCLEH] = { "mcycleh", any32, read_hpmcounterh, + write_mhpmcounterh }, + [CSR_MINSTRETH] = { "minstreth", any32, read_hpmcounterh, + write_mhpmcounterh }, /* Machine Information Registers */ [CSR_MVENDORID] = { "mvendorid", any, read_mvendorid }, @@ -3505,23 +3689,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MHARTID] = { "mhartid", any, read_mhartid }, [CSR_MCONFIGPTR] = { "mconfigptr", any, read_zero, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Machine Trap Setup */ - [CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus, NULL, - read_mstatus_i128 }, - [CSR_MISA] = { "misa", any, read_misa, write_misa, NULL, - read_misa_i128 }, - [CSR_MIDELEG] = { "mideleg", any, NULL, NULL, rmw_mideleg }, - [CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg }, - [CSR_MIE] = { "mie", any, NULL, NULL, rmw_mie }, - [CSR_MTVEC] = { "mtvec", any, read_mtvec, write_mtvec }, - [CSR_MCOUNTEREN] = { "mcounteren", any, read_mcounteren, write_mcounteren }, + [CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus, + NULL, read_mstatus_i128 }, + [CSR_MISA] = { "misa", any, read_misa, write_misa, + NULL, read_misa_i128 }, + [CSR_MIDELEG] = { "mideleg", any, NULL, NULL, rmw_mideleg }, + [CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg }, + [CSR_MIE] = { "mie", any, NULL, NULL, rmw_mie }, + [CSR_MTVEC] = { "mtvec", any, read_mtvec, write_mtvec }, + [CSR_MCOUNTEREN] = { "mcounteren", umode, read_mcounteren, + write_mcounteren }, - [CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush }, + [CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, + write_mstatush }, /* Machine Trap Handling */ - [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch, NULL, - read_mscratch_i128, write_mscratch_i128 }, + [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch, + NULL, read_mscratch_i128, write_mscratch_i128 }, [CSR_MEPC] = { "mepc", any, read_mepc, write_mepc }, [CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause }, [CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval }, @@ -3532,12 +3718,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MIREG] = { "mireg", aia_any, NULL, NULL, rmw_xireg }, /* Machine-Level Interrupts (AIA) */ - [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei }, - [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, + [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei }, + [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, /* Virtual Interrupts for Supervisor Level (AIA) */ - [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, - [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, + [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, + [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, /* Machine-Level High-Half CSRs (AIA) */ [CSR_MIDELEGH] = { "midelegh", aia_any32, NULL, NULL, rmw_midelegh }, @@ -3547,34 +3733,45 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, /* Execution environment configuration */ - [CSR_MENVCFG] = { "menvcfg", any, read_menvcfg, write_menvcfg, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MENVCFGH] = { "menvcfgh", any32, read_menvcfgh, write_menvcfgh, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MENVCFG] = { "menvcfg", umode, read_menvcfg, write_menvcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MENVCFGH] = { "menvcfgh", umode32, read_menvcfgh, write_menvcfgh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_SENVCFG] = { "senvcfg", smode, read_senvcfg, write_senvcfg, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_HENVCFG] = { "henvcfg", hmode, read_henvcfg, write_henvcfg, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_HENVCFGH] = { "henvcfgh", hmode32, read_henvcfgh, write_henvcfgh, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Supervisor Trap Setup */ - [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus, NULL, - read_sstatus_i128 }, - [CSR_SIE] = { "sie", smode, NULL, NULL, rmw_sie }, - [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec }, - [CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren, write_scounteren }, + [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus, + NULL, read_sstatus_i128 }, + [CSR_SIE] = { "sie", smode, NULL, NULL, rmw_sie }, + [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec }, + [CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren, + write_scounteren }, /* Supervisor Trap Handling */ - [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch, NULL, - read_sscratch_i128, write_sscratch_i128 }, + [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch, + NULL, read_sscratch_i128, write_sscratch_i128 }, [CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc }, [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause }, - [CSR_STVAL] = { "stval", smode, read_stval, write_stval }, + [CSR_STVAL] = { "stval", smode, read_stval, write_stval }, [CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip }, + [CSR_STIMECMP] = { "stimecmp", sstc, read_stimecmp, write_stimecmp, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_STIMECMPH] = { "stimecmph", sstc_32, read_stimecmph, write_stimecmph, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSTIMECMP] = { "vstimecmp", sstc, read_vstimecmp, + write_vstimecmp, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSTIMECMPH] = { "vstimecmph", sstc_32, read_vstimecmph, + write_vstimecmph, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Supervisor Protection and Translation */ - [CSR_SATP] = { "satp", smode, read_satp, write_satp }, + [CSR_SATP] = { "satp", smode, read_satp, write_satp }, /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */ [CSR_SISELECT] = { "siselect", aia_smode, NULL, NULL, rmw_xiselect }, @@ -3588,87 +3785,100 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh }, [CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph }, - [CSR_HSTATUS] = { "hstatus", hmode, read_hstatus, write_hstatus, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HEDELEG] = { "hedeleg", hmode, read_hedeleg, write_hedeleg, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HSTATUS] = { "hstatus", hmode, read_hstatus, write_hstatus, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HEDELEG] = { "hedeleg", hmode, read_hedeleg, write_hedeleg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_HIDELEG] = { "hideleg", hmode, NULL, NULL, rmw_hideleg, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HVIP] = { "hvip", hmode, NULL, NULL, rmw_hvip, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HIE] = { "hie", hmode, NULL, NULL, rmw_hie, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, write_hcounteren, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HVIP] = { "hvip", hmode, NULL, NULL, rmw_hvip, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HIE] = { "hie", hmode, NULL, NULL, rmw_hie, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, + write_hcounteren, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst, + .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_HGEIP] = { "hgeip", hmode, read_hgeip, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, write_htimedelta, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, write_htimedeltah, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, + write_htimedelta, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, + write_htimedeltah, + .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSSTATUS] = { "vsstatus", hmode, read_vsstatus, write_vsstatus, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSIP] = { "vsip", hmode, NULL, NULL, rmw_vsip, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSIE] = { "vsie", hmode, NULL, NULL, rmw_vsie , - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSTVEC] = { "vstvec", hmode, read_vstvec, write_vstvec, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSSCRATCH] = { "vsscratch", hmode, read_vsscratch, write_vsscratch, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSEPC] = { "vsepc", hmode, read_vsepc, write_vsepc, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSCAUSE] = { "vscause", hmode, read_vscause, write_vscause, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSTVAL] = { "vstval", hmode, read_vstval, write_vstval, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_VSATP] = { "vsatp", hmode, read_vsatp, write_vsatp, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSSTATUS] = { "vsstatus", hmode, read_vsstatus, + write_vsstatus, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSIP] = { "vsip", hmode, NULL, NULL, rmw_vsip, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSIE] = { "vsie", hmode, NULL, NULL, rmw_vsie , + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSTVEC] = { "vstvec", hmode, read_vstvec, write_vstvec, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSSCRATCH] = { "vsscratch", hmode, read_vsscratch, + write_vsscratch, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSEPC] = { "vsepc", hmode, read_vsepc, write_vsepc, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSCAUSE] = { "vscause", hmode, read_vscause, write_vscause, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSTVAL] = { "vstval", hmode, read_vstval, write_vstval, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSATP] = { "vsatp", hmode, read_vsatp, write_vsatp, + .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MTVAL2] = { "mtval2", hmode, read_mtval2, write_mtval2, - .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst, - .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MTVAL2] = { "mtval2", hmode, read_mtval2, write_mtval2, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */ [CSR_HVIEN] = { "hvien", aia_hmode, read_zero, write_ignore }, - [CSR_HVICTL] = { "hvictl", aia_hmode, read_hvictl, write_hvictl }, - [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1, write_hviprio1 }, - [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2, write_hviprio2 }, + [CSR_HVICTL] = { "hvictl", aia_hmode, read_hvictl, + write_hvictl }, + [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1, + write_hviprio1 }, + [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2, + write_hviprio2 }, /* * VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */ - [CSR_VSISELECT] = { "vsiselect", aia_hmode, NULL, NULL, rmw_xiselect }, - [CSR_VSIREG] = { "vsireg", aia_hmode, NULL, NULL, rmw_xireg }, + [CSR_VSISELECT] = { "vsiselect", aia_hmode, NULL, NULL, + rmw_xiselect }, + [CSR_VSIREG] = { "vsireg", aia_hmode, NULL, NULL, rmw_xireg }, /* VS-Level Interrupts (H-extension with AIA) */ [CSR_VSTOPEI] = { "vstopei", aia_hmode, NULL, NULL, rmw_xtopei }, [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ - [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL, rmw_hidelegh }, - [CSR_HVIENH] = { "hvienh", aia_hmode32, read_zero, write_ignore }, + [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL, + rmw_hidelegh }, + [CSR_HVIENH] = { "hvienh", aia_hmode32, read_zero, + write_ignore }, [CSR_HVIPH] = { "hviph", aia_hmode32, NULL, NULL, rmw_hviph }, - [CSR_HVIPRIO1H] = { "hviprio1h", aia_hmode32, read_hviprio1h, write_hviprio1h }, - [CSR_HVIPRIO2H] = { "hviprio2h", aia_hmode32, read_hviprio2h, write_hviprio2h }, + [CSR_HVIPRIO1H] = { "hviprio1h", aia_hmode32, read_hviprio1h, + write_hviprio1h }, + [CSR_HVIPRIO2H] = { "hviprio2h", aia_hmode32, read_hviprio2h, + write_hviprio2h }, [CSR_VSIEH] = { "vsieh", aia_hmode32, NULL, NULL, rmw_vsieh }, [CSR_VSIPH] = { "vsiph", aia_hmode32, NULL, NULL, rmw_vsiph }, /* Physical Memory Protection */ [CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg, - .min_priv_ver = PRIV_VERSION_1_11_0 }, + .min_priv_ver = PRIV_VERSION_1_11_0 }, [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg }, @@ -3695,19 +3905,26 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_TDATA1] = { "tdata1", debug, read_tdata, write_tdata }, [CSR_TDATA2] = { "tdata2", debug, read_tdata, write_tdata }, [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata }, + [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore }, /* User Pointer Masking */ - [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte }, - [CSR_UPMMASK] = { "upmmask", pointer_masking, read_upmmask, write_upmmask }, - [CSR_UPMBASE] = { "upmbase", pointer_masking, read_upmbase, write_upmbase }, + [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte }, + [CSR_UPMMASK] = { "upmmask", pointer_masking, read_upmmask, + write_upmmask }, + [CSR_UPMBASE] = { "upmbase", pointer_masking, read_upmbase, + write_upmbase }, /* Machine Pointer Masking */ - [CSR_MMTE] = { "mmte", pointer_masking, read_mmte, write_mmte }, - [CSR_MPMMASK] = { "mpmmask", pointer_masking, read_mpmmask, write_mpmmask }, - [CSR_MPMBASE] = { "mpmbase", pointer_masking, read_mpmbase, write_mpmbase }, + [CSR_MMTE] = { "mmte", pointer_masking, read_mmte, write_mmte }, + [CSR_MPMMASK] = { "mpmmask", pointer_masking, read_mpmmask, + write_mpmmask }, + [CSR_MPMBASE] = { "mpmbase", pointer_masking, read_mpmbase, + write_mpmbase }, /* Supervisor Pointer Masking */ - [CSR_SMTE] = { "smte", pointer_masking, read_smte, write_smte }, - [CSR_SPMMASK] = { "spmmask", pointer_masking, read_spmmask, write_spmmask }, - [CSR_SPMBASE] = { "spmbase", pointer_masking, read_spmbase, write_spmbase }, + [CSR_SMTE] = { "smte", pointer_masking, read_smte, write_smte }, + [CSR_SPMMASK] = { "spmmask", pointer_masking, read_spmmask, + write_spmmask }, + [CSR_SPMBASE] = { "spmbase", pointer_masking, read_spmbase, + write_spmbase }, /* Performance Counters */ [CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_hpmcounter }, @@ -3741,125 +3958,214 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_HPMCOUNTER31] = { "hpmcounter31", ctr, read_hpmcounter }, [CSR_MHPMCOUNTER3] = { "mhpmcounter3", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER4] = { "mhpmcounter4", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER5] = { "mhpmcounter5", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER6] = { "mhpmcounter6", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER7] = { "mhpmcounter7", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER8] = { "mhpmcounter8", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER9] = { "mhpmcounter9", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER10] = { "mhpmcounter10", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER11] = { "mhpmcounter11", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER12] = { "mhpmcounter12", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER13] = { "mhpmcounter13", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER14] = { "mhpmcounter14", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER15] = { "mhpmcounter15", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER16] = { "mhpmcounter16", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER17] = { "mhpmcounter17", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER18] = { "mhpmcounter18", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER19] = { "mhpmcounter19", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER20] = { "mhpmcounter20", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER21] = { "mhpmcounter21", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER22] = { "mhpmcounter22", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER23] = { "mhpmcounter23", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER24] = { "mhpmcounter24", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER25] = { "mhpmcounter25", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER26] = { "mhpmcounter26", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER27] = { "mhpmcounter27", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER28] = { "mhpmcounter28", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER29] = { "mhpmcounter29", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER30] = { "mhpmcounter30", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MHPMCOUNTER31] = { "mhpmcounter31", mctr, read_hpmcounter, - write_mhpmcounter }, + write_mhpmcounter }, [CSR_MCOUNTINHIBIT] = { "mcountinhibit", any, read_mcountinhibit, - write_mcountinhibit, .min_priv_ver = PRIV_VERSION_1_11_0 }, + write_mcountinhibit, + .min_priv_ver = PRIV_VERSION_1_11_0 }, [CSR_MHPMEVENT3] = { "mhpmevent3", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT4] = { "mhpmevent4", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT5] = { "mhpmevent5", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT6] = { "mhpmevent6", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT7] = { "mhpmevent7", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT8] = { "mhpmevent8", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT9] = { "mhpmevent9", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT10] = { "mhpmevent10", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT11] = { "mhpmevent11", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT12] = { "mhpmevent12", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT13] = { "mhpmevent13", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT14] = { "mhpmevent14", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT15] = { "mhpmevent15", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT16] = { "mhpmevent16", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT17] = { "mhpmevent17", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT18] = { "mhpmevent18", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT19] = { "mhpmevent19", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT20] = { "mhpmevent20", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT21] = { "mhpmevent21", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT22] = { "mhpmevent22", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT23] = { "mhpmevent23", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT24] = { "mhpmevent24", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT25] = { "mhpmevent25", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT26] = { "mhpmevent26", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT27] = { "mhpmevent27", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT28] = { "mhpmevent28", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT29] = { "mhpmevent29", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT30] = { "mhpmevent30", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_mhpmevent, - write_mhpmevent }, + write_mhpmevent }, + + [CSR_MHPMEVENT3H] = { "mhpmevent3h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT4H] = { "mhpmevent4h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT5H] = { "mhpmevent5h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT6H] = { "mhpmevent6h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT7H] = { "mhpmevent7h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT8H] = { "mhpmevent8h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT9H] = { "mhpmevent9h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT10H] = { "mhpmevent10h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT11H] = { "mhpmevent11h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT12H] = { "mhpmevent12h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT13H] = { "mhpmevent13h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT14H] = { "mhpmevent14h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT15H] = { "mhpmevent15h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT16H] = { "mhpmevent16h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT17H] = { "mhpmevent17h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT18H] = { "mhpmevent18h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT19H] = { "mhpmevent19h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT20H] = { "mhpmevent20h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT21H] = { "mhpmevent21h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT22H] = { "mhpmevent22h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT23H] = { "mhpmevent23h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT24H] = { "mhpmevent24h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT25H] = { "mhpmevent25h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT26H] = { "mhpmevent26h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT27H] = { "mhpmevent27h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT28H] = { "mhpmevent28h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT29H] = { "mhpmevent29h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT30H] = { "mhpmevent30h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT31H] = { "mhpmevent31h", sscofpmf, read_mhpmeventh, + write_mhpmeventh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_HPMCOUNTER3H] = { "hpmcounter3h", ctr32, read_hpmcounterh }, [CSR_HPMCOUNTER4H] = { "hpmcounter4h", ctr32, read_hpmcounterh }, @@ -3892,62 +4198,65 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_HPMCOUNTER31H] = { "hpmcounter31h", ctr32, read_hpmcounterh }, [CSR_MHPMCOUNTER3H] = { "mhpmcounter3h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER4H] = { "mhpmcounter4h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER5H] = { "mhpmcounter5h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER6H] = { "mhpmcounter6h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER7H] = { "mhpmcounter7h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER8H] = { "mhpmcounter8h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER9H] = { "mhpmcounter9h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER10H] = { "mhpmcounter10h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER11H] = { "mhpmcounter11h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER12H] = { "mhpmcounter12h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER13H] = { "mhpmcounter13h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER14H] = { "mhpmcounter14h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER15H] = { "mhpmcounter15h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER16H] = { "mhpmcounter16h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER17H] = { "mhpmcounter17h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER18H] = { "mhpmcounter18h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER19H] = { "mhpmcounter19h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER20H] = { "mhpmcounter20h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER21H] = { "mhpmcounter21h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER22H] = { "mhpmcounter22h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER23H] = { "mhpmcounter23h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER24H] = { "mhpmcounter24h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER25H] = { "mhpmcounter25h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER26H] = { "mhpmcounter26h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER27H] = { "mhpmcounter27h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER28H] = { "mhpmcounter28h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER29H] = { "mhpmcounter29h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER30H] = { "mhpmcounter30h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, [CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", mctr32, read_hpmcounterh, - write_mhpmcounterh }, + write_mhpmcounterh }, + [CSR_SCOUNTOVF] = { "scountovf", sscofpmf, read_scountovf, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + #endif /* !CONFIG_USER_ONLY */ }; diff --git a/target/riscv/debug.c b/target/riscv/debug.c index fc6e13222f..26ea764407 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -37,11 +37,9 @@ * - tdata1 * - tdata2 * - tdata3 + * - tinfo * - * We don't support writable 'type' field in the tdata1 register, so there is - * no need to implement the "tinfo" CSR. - * - * The following triggers are implemented: + * The following triggers are initialized by default: * * Index | Type | tdata mapping | Description * ------+------+------------------------+------------ @@ -52,8 +50,15 @@ /* tdata availability of a trigger */ typedef bool tdata_avail[TDATA_NUM]; -static tdata_avail tdata_mapping[TRIGGER_NUM] = { - [TRIGGER_TYPE2_IDX_0 ... TRIGGER_TYPE2_IDX_1] = { true, true, false }, +static tdata_avail tdata_mapping[TRIGGER_TYPE_NUM] = { + [TRIGGER_TYPE_NO_EXIST] = { false, false, false }, + [TRIGGER_TYPE_AD_MATCH] = { true, true, true }, + [TRIGGER_TYPE_INST_CNT] = { true, false, true }, + [TRIGGER_TYPE_INT] = { true, true, true }, + [TRIGGER_TYPE_EXCP] = { true, true, true }, + [TRIGGER_TYPE_AD_MATCH6] = { true, true, true }, + [TRIGGER_TYPE_EXT_SRC] = { true, false, false }, + [TRIGGER_TYPE_UNAVAIL] = { true, true, true } }; /* only breakpoint size 1/2/4/8 supported */ @@ -67,18 +72,76 @@ static int access_size[SIZE_NUM] = { [6 ... 15] = -1, }; -static inline target_ulong trigger_type(CPURISCVState *env, - trigger_type_t type) +static inline target_ulong extract_trigger_type(CPURISCVState *env, + target_ulong tdata1) +{ + switch (riscv_cpu_mxl(env)) { + case MXL_RV32: + return extract32(tdata1, 28, 4); + case MXL_RV64: + case MXL_RV128: + return extract64(tdata1, 60, 4); + default: + g_assert_not_reached(); + } +} + +static inline target_ulong get_trigger_type(CPURISCVState *env, + target_ulong trigger_index) +{ + return extract_trigger_type(env, env->tdata1[trigger_index]); +} + +static trigger_action_t get_trigger_action(CPURISCVState *env, + target_ulong trigger_index) +{ + target_ulong tdata1 = env->tdata1[trigger_index]; + int trigger_type = get_trigger_type(env, trigger_index); + trigger_action_t action = DBG_ACTION_NONE; + + switch (trigger_type) { + case TRIGGER_TYPE_AD_MATCH: + action = (tdata1 & TYPE2_ACTION) >> 12; + break; + case TRIGGER_TYPE_AD_MATCH6: + action = (tdata1 & TYPE6_ACTION) >> 12; + break; + case TRIGGER_TYPE_INST_CNT: + case TRIGGER_TYPE_INT: + case TRIGGER_TYPE_EXCP: + case TRIGGER_TYPE_EXT_SRC: + qemu_log_mask(LOG_UNIMP, "trigger type: %d is not supported\n", + trigger_type); + break; + case TRIGGER_TYPE_NO_EXIST: + case TRIGGER_TYPE_UNAVAIL: + qemu_log_mask(LOG_GUEST_ERROR, "trigger type: %d does not exit\n", + trigger_type); + break; + default: + g_assert_not_reached(); + } + + return action; +} + +static inline target_ulong build_tdata1(CPURISCVState *env, + trigger_type_t type, + bool dmode, target_ulong data) { target_ulong tdata1; switch (riscv_cpu_mxl(env)) { case MXL_RV32: - tdata1 = RV32_TYPE(type); + tdata1 = RV32_TYPE(type) | + (dmode ? RV32_DMODE : 0) | + (data & RV32_DATA_MASK); break; case MXL_RV64: case MXL_RV128: - tdata1 = RV64_TYPE(type); + tdata1 = RV64_TYPE(type) | + (dmode ? RV64_DMODE : 0) | + (data & RV64_DATA_MASK); break; default: g_assert_not_reached(); @@ -89,15 +152,13 @@ static inline target_ulong trigger_type(CPURISCVState *env, bool tdata_available(CPURISCVState *env, int tdata_index) { + int trigger_type = get_trigger_type(env, env->trigger_cur); + if (unlikely(tdata_index >= TDATA_NUM)) { return false; } - if (unlikely(env->trigger_cur >= TRIGGER_NUM)) { - return false; - } - - return tdata_mapping[env->trigger_cur][tdata_index]; + return tdata_mapping[trigger_type][tdata_index]; } target_ulong tselect_csr_read(CPURISCVState *env) @@ -107,8 +168,9 @@ target_ulong tselect_csr_read(CPURISCVState *env) void tselect_csr_write(CPURISCVState *env, target_ulong val) { - /* all target_ulong bits of tselect are implemented */ - env->trigger_cur = val; + if (val < RV_MAX_TRIGGERS) { + env->trigger_cur = val; + } } static target_ulong tdata1_validate(CPURISCVState *env, target_ulong val, @@ -137,6 +199,7 @@ static target_ulong tdata1_validate(CPURISCVState *env, target_ulong val, qemu_log_mask(LOG_GUEST_ERROR, "ignoring type write to tdata1 register\n"); } + if (dmode != 0) { qemu_log_mask(LOG_UNIMP, "debug mode is not supported\n"); } @@ -152,6 +215,32 @@ static inline void warn_always_zero_bit(target_ulong val, target_ulong mask, } } +static void do_trigger_action(CPURISCVState *env, target_ulong trigger_index) +{ + trigger_action_t action = get_trigger_action(env, trigger_index); + + switch (action) { + case DBG_ACTION_NONE: + break; + case DBG_ACTION_BP: + riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); + break; + case DBG_ACTION_DBG_MODE: + case DBG_ACTION_TRACE0: + case DBG_ACTION_TRACE1: + case DBG_ACTION_TRACE2: + case DBG_ACTION_TRACE3: + case DBG_ACTION_EXT_DBG0: + case DBG_ACTION_EXT_DBG1: + qemu_log_mask(LOG_UNIMP, "action: %d is not supported\n", action); + break; + default: + g_assert_not_reached(); + } +} + +/* type 2 trigger */ + static uint32_t type2_breakpoint_size(CPURISCVState *env, target_ulong ctrl) { uint32_t size, sizelo, sizehi = 0; @@ -211,8 +300,8 @@ static target_ulong type2_mcontrol_validate(CPURISCVState *env, static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index) { - target_ulong ctrl = env->type2_trig[index].mcontrol; - target_ulong addr = env->type2_trig[index].maddress; + target_ulong ctrl = env->tdata1[index]; + target_ulong addr = env->tdata2[index]; bool enabled = type2_breakpoint_enabled(ctrl); CPUState *cs = env_cpu(env); int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; @@ -223,7 +312,7 @@ static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index) } if (ctrl & TYPE2_EXEC) { - cpu_breakpoint_insert(cs, addr, flags, &env->type2_trig[index].bp); + cpu_breakpoint_insert(cs, addr, flags, &env->cpu_breakpoint[index]); } if (ctrl & TYPE2_LOAD) { @@ -237,10 +326,10 @@ static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index) size = type2_breakpoint_size(env, ctrl); if (size != 0) { cpu_watchpoint_insert(cs, addr, size, flags, - &env->type2_trig[index].wp); + &env->cpu_watchpoint[index]); } else { cpu_watchpoint_insert(cs, addr, 8, flags, - &env->type2_trig[index].wp); + &env->cpu_watchpoint[index]); } } } @@ -249,59 +338,42 @@ static void type2_breakpoint_remove(CPURISCVState *env, target_ulong index) { CPUState *cs = env_cpu(env); - if (env->type2_trig[index].bp) { - cpu_breakpoint_remove_by_ref(cs, env->type2_trig[index].bp); - env->type2_trig[index].bp = NULL; + if (env->cpu_breakpoint[index]) { + cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]); + env->cpu_breakpoint[index] = NULL; } - if (env->type2_trig[index].wp) { - cpu_watchpoint_remove_by_ref(cs, env->type2_trig[index].wp); - env->type2_trig[index].wp = NULL; + if (env->cpu_watchpoint[index]) { + cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); + env->cpu_watchpoint[index] = NULL; } } -static target_ulong type2_reg_read(CPURISCVState *env, - target_ulong trigger_index, int tdata_index) -{ - uint32_t index = trigger_index - TRIGGER_TYPE2_IDX_0; - target_ulong tdata; - - switch (tdata_index) { - case TDATA1: - tdata = env->type2_trig[index].mcontrol; - break; - case TDATA2: - tdata = env->type2_trig[index].maddress; - break; - default: - g_assert_not_reached(); - } - - return tdata; -} - -static void type2_reg_write(CPURISCVState *env, target_ulong trigger_index, +static void type2_reg_write(CPURISCVState *env, target_ulong index, int tdata_index, target_ulong val) { - uint32_t index = trigger_index - TRIGGER_TYPE2_IDX_0; target_ulong new_val; switch (tdata_index) { case TDATA1: new_val = type2_mcontrol_validate(env, val); - if (new_val != env->type2_trig[index].mcontrol) { - env->type2_trig[index].mcontrol = new_val; + if (new_val != env->tdata1[index]) { + env->tdata1[index] = new_val; type2_breakpoint_remove(env, index); type2_breakpoint_insert(env, index); } break; case TDATA2: - if (val != env->type2_trig[index].maddress) { - env->type2_trig[index].maddress = val; + if (val != env->tdata2[index]) { + env->tdata2[index] = val; type2_breakpoint_remove(env, index); type2_breakpoint_insert(env, index); } break; + case TDATA3: + qemu_log_mask(LOG_UNIMP, + "tdata3 is not supported for type 2 trigger\n"); + break; default: g_assert_not_reached(); } @@ -309,35 +381,176 @@ static void type2_reg_write(CPURISCVState *env, target_ulong trigger_index, return; } -typedef target_ulong (*tdata_read_func)(CPURISCVState *env, - target_ulong trigger_index, - int tdata_index); +/* type 6 trigger */ -static tdata_read_func trigger_read_funcs[TRIGGER_NUM] = { - [TRIGGER_TYPE2_IDX_0 ... TRIGGER_TYPE2_IDX_1] = type2_reg_read, -}; +static inline bool type6_breakpoint_enabled(target_ulong ctrl) +{ + bool mode = !!(ctrl & (TYPE6_VU | TYPE6_VS | TYPE6_U | TYPE6_S | TYPE6_M)); + bool rwx = !!(ctrl & (TYPE6_LOAD | TYPE6_STORE | TYPE6_EXEC)); -typedef void (*tdata_write_func)(CPURISCVState *env, - target_ulong trigger_index, - int tdata_index, - target_ulong val); + return mode && rwx; +} -static tdata_write_func trigger_write_funcs[TRIGGER_NUM] = { - [TRIGGER_TYPE2_IDX_0 ... TRIGGER_TYPE2_IDX_1] = type2_reg_write, -}; +static target_ulong type6_mcontrol6_validate(CPURISCVState *env, + target_ulong ctrl) +{ + target_ulong val; + uint32_t size; + + /* validate the generic part first */ + val = tdata1_validate(env, ctrl, TRIGGER_TYPE_AD_MATCH6); + + /* validate unimplemented (always zero) bits */ + warn_always_zero_bit(ctrl, TYPE6_MATCH, "match"); + warn_always_zero_bit(ctrl, TYPE6_CHAIN, "chain"); + warn_always_zero_bit(ctrl, TYPE6_ACTION, "action"); + warn_always_zero_bit(ctrl, TYPE6_TIMING, "timing"); + warn_always_zero_bit(ctrl, TYPE6_SELECT, "select"); + warn_always_zero_bit(ctrl, TYPE6_HIT, "hit"); + + /* validate size encoding */ + size = extract32(ctrl, 16, 4); + if (access_size[size] == -1) { + qemu_log_mask(LOG_UNIMP, "access size %d is not supported, using SIZE_ANY\n", + size); + } else { + val |= (ctrl & TYPE6_SIZE); + } + + /* keep the mode and attribute bits */ + val |= (ctrl & (TYPE6_VU | TYPE6_VS | TYPE6_U | TYPE6_S | TYPE6_M | + TYPE6_LOAD | TYPE6_STORE | TYPE6_EXEC)); + + return val; +} + +static void type6_breakpoint_insert(CPURISCVState *env, target_ulong index) +{ + target_ulong ctrl = env->tdata1[index]; + target_ulong addr = env->tdata2[index]; + bool enabled = type6_breakpoint_enabled(ctrl); + CPUState *cs = env_cpu(env); + int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; + uint32_t size; + + if (!enabled) { + return; + } + + if (ctrl & TYPE6_EXEC) { + cpu_breakpoint_insert(cs, addr, flags, &env->cpu_breakpoint[index]); + } + + if (ctrl & TYPE6_LOAD) { + flags |= BP_MEM_READ; + } + + if (ctrl & TYPE6_STORE) { + flags |= BP_MEM_WRITE; + } + + if (flags & BP_MEM_ACCESS) { + size = extract32(ctrl, 16, 4); + if (size != 0) { + cpu_watchpoint_insert(cs, addr, size, flags, + &env->cpu_watchpoint[index]); + } else { + cpu_watchpoint_insert(cs, addr, 8, flags, + &env->cpu_watchpoint[index]); + } + } +} + +static void type6_breakpoint_remove(CPURISCVState *env, target_ulong index) +{ + type2_breakpoint_remove(env, index); +} + +static void type6_reg_write(CPURISCVState *env, target_ulong index, + int tdata_index, target_ulong val) +{ + target_ulong new_val; + + switch (tdata_index) { + case TDATA1: + new_val = type6_mcontrol6_validate(env, val); + if (new_val != env->tdata1[index]) { + env->tdata1[index] = new_val; + type6_breakpoint_remove(env, index); + type6_breakpoint_insert(env, index); + } + break; + case TDATA2: + if (val != env->tdata2[index]) { + env->tdata2[index] = val; + type6_breakpoint_remove(env, index); + type6_breakpoint_insert(env, index); + } + break; + case TDATA3: + qemu_log_mask(LOG_UNIMP, + "tdata3 is not supported for type 6 trigger\n"); + break; + default: + g_assert_not_reached(); + } + + return; +} target_ulong tdata_csr_read(CPURISCVState *env, int tdata_index) { - tdata_read_func read_func = trigger_read_funcs[env->trigger_cur]; - - return read_func(env, env->trigger_cur, tdata_index); + switch (tdata_index) { + case TDATA1: + return env->tdata1[env->trigger_cur]; + case TDATA2: + return env->tdata2[env->trigger_cur]; + case TDATA3: + return env->tdata3[env->trigger_cur]; + default: + g_assert_not_reached(); + } } void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val) { - tdata_write_func write_func = trigger_write_funcs[env->trigger_cur]; + int trigger_type; - return write_func(env, env->trigger_cur, tdata_index, val); + if (tdata_index == TDATA1) { + trigger_type = extract_trigger_type(env, val); + } else { + trigger_type = get_trigger_type(env, env->trigger_cur); + } + + switch (trigger_type) { + case TRIGGER_TYPE_AD_MATCH: + type2_reg_write(env, env->trigger_cur, tdata_index, val); + break; + case TRIGGER_TYPE_AD_MATCH6: + type6_reg_write(env, env->trigger_cur, tdata_index, val); + break; + case TRIGGER_TYPE_INST_CNT: + case TRIGGER_TYPE_INT: + case TRIGGER_TYPE_EXCP: + case TRIGGER_TYPE_EXT_SRC: + qemu_log_mask(LOG_UNIMP, "trigger type: %d is not supported\n", + trigger_type); + break; + case TRIGGER_TYPE_NO_EXIST: + case TRIGGER_TYPE_UNAVAIL: + qemu_log_mask(LOG_GUEST_ERROR, "trigger type: %d does not exit\n", + trigger_type); + break; + default: + g_assert_not_reached(); + } +} + +target_ulong tinfo_csr_read(CPURISCVState *env) +{ + /* assume all triggers support the same types of triggers */ + return BIT(TRIGGER_TYPE_AD_MATCH) | + BIT(TRIGGER_TYPE_AD_MATCH6); } void riscv_cpu_debug_excp_handler(CPUState *cs) @@ -348,11 +561,11 @@ void riscv_cpu_debug_excp_handler(CPUState *cs) if (cs->watchpoint_hit) { if (cs->watchpoint_hit->flags & BP_CPU) { cs->watchpoint_hit = NULL; - riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); + do_trigger_action(env, DBG_ACTION_BP); } } else { if (cpu_breakpoint_test(cs, env->pc, BP_CPU)) { - riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); + do_trigger_action(env, DBG_ACTION_BP); } } } @@ -364,18 +577,51 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs) CPUBreakpoint *bp; target_ulong ctrl; target_ulong pc; + int trigger_type; int i; QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - for (i = 0; i < TRIGGER_TYPE2_NUM; i++) { - ctrl = env->type2_trig[i].mcontrol; - pc = env->type2_trig[i].maddress; + for (i = 0; i < RV_MAX_TRIGGERS; i++) { + trigger_type = get_trigger_type(env, i); - if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) { - /* check U/S/M bit against current privilege level */ - if ((ctrl >> 3) & BIT(env->priv)) { - return true; + switch (trigger_type) { + case TRIGGER_TYPE_AD_MATCH: + /* type 2 trigger cannot be fired in VU/VS mode */ + if (riscv_cpu_virt_enabled(env)) { + return false; } + + ctrl = env->tdata1[i]; + pc = env->tdata2[i]; + + if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) { + /* check U/S/M bit against current privilege level */ + if ((ctrl >> 3) & BIT(env->priv)) { + return true; + } + } + break; + case TRIGGER_TYPE_AD_MATCH6: + ctrl = env->tdata1[i]; + pc = env->tdata2[i]; + + if ((ctrl & TYPE6_EXEC) && (bp->pc == pc)) { + if (riscv_cpu_virt_enabled(env)) { + /* check VU/VS bit against current privilege level */ + if ((ctrl >> 23) & BIT(env->priv)) { + return true; + } + } else { + /* check U/S/M bit against current privilege level */ + if ((ctrl >> 3) & BIT(env->priv)) { + return true; + } + } + } + break; + default: + /* other trigger types are not supported or irrelevant */ + break; } } } @@ -389,26 +635,67 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) CPURISCVState *env = &cpu->env; target_ulong ctrl; target_ulong addr; + int trigger_type; int flags; int i; - for (i = 0; i < TRIGGER_TYPE2_NUM; i++) { - ctrl = env->type2_trig[i].mcontrol; - addr = env->type2_trig[i].maddress; - flags = 0; + for (i = 0; i < RV_MAX_TRIGGERS; i++) { + trigger_type = get_trigger_type(env, i); - if (ctrl & TYPE2_LOAD) { - flags |= BP_MEM_READ; - } - if (ctrl & TYPE2_STORE) { - flags |= BP_MEM_WRITE; - } - - if ((wp->flags & flags) && (wp->vaddr == addr)) { - /* check U/S/M bit against current privilege level */ - if ((ctrl >> 3) & BIT(env->priv)) { - return true; + switch (trigger_type) { + case TRIGGER_TYPE_AD_MATCH: + /* type 2 trigger cannot be fired in VU/VS mode */ + if (riscv_cpu_virt_enabled(env)) { + return false; } + + ctrl = env->tdata1[i]; + addr = env->tdata2[i]; + flags = 0; + + if (ctrl & TYPE2_LOAD) { + flags |= BP_MEM_READ; + } + if (ctrl & TYPE2_STORE) { + flags |= BP_MEM_WRITE; + } + + if ((wp->flags & flags) && (wp->vaddr == addr)) { + /* check U/S/M bit against current privilege level */ + if ((ctrl >> 3) & BIT(env->priv)) { + return true; + } + } + break; + case TRIGGER_TYPE_AD_MATCH6: + ctrl = env->tdata1[i]; + addr = env->tdata2[i]; + flags = 0; + + if (ctrl & TYPE6_LOAD) { + flags |= BP_MEM_READ; + } + if (ctrl & TYPE6_STORE) { + flags |= BP_MEM_WRITE; + } + + if ((wp->flags & flags) && (wp->vaddr == addr)) { + if (riscv_cpu_virt_enabled(env)) { + /* check VU/VS bit against current privilege level */ + if ((ctrl >> 23) & BIT(env->priv)) { + return true; + } + } else { + /* check U/S/M bit against current privilege level */ + if ((ctrl >> 3) & BIT(env->priv)) { + return true; + } + } + } + break; + default: + /* other trigger types are not supported */ + break; } } @@ -417,11 +704,11 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) void riscv_trigger_init(CPURISCVState *env) { - target_ulong type2 = trigger_type(env, TRIGGER_TYPE_AD_MATCH); + target_ulong tdata1 = build_tdata1(env, TRIGGER_TYPE_AD_MATCH, 0, 0); int i; - /* type 2 triggers */ - for (i = 0; i < TRIGGER_TYPE2_NUM; i++) { + /* init to type 2 triggers */ + for (i = 0; i < RV_MAX_TRIGGERS; i++) { /* * type = TRIGGER_TYPE_AD_MATCH * dmode = 0 (both debug and M-mode can write tdata) @@ -435,9 +722,10 @@ void riscv_trigger_init(CPURISCVState *env) * chain = 0 (unimplemented, always 0) * match = 0 (always 0, when any compare value equals tdata2) */ - env->type2_trig[i].mcontrol = type2; - env->type2_trig[i].maddress = 0; - env->type2_trig[i].bp = NULL; - env->type2_trig[i].wp = NULL; + env->tdata1[i] = tdata1; + env->tdata2[i] = 0; + env->tdata3[i] = 0; + env->cpu_breakpoint[i] = NULL; + env->cpu_watchpoint[i] = NULL; } } diff --git a/target/riscv/debug.h b/target/riscv/debug.h index 27b9cac6b4..a1226b4d29 100644 --- a/target/riscv/debug.h +++ b/target/riscv/debug.h @@ -22,13 +22,7 @@ #ifndef RISCV_DEBUG_H #define RISCV_DEBUG_H -/* trigger indexes implemented */ -enum { - TRIGGER_TYPE2_IDX_0 = 0, - TRIGGER_TYPE2_IDX_1, - TRIGGER_TYPE2_NUM, - TRIGGER_NUM = TRIGGER_TYPE2_NUM -}; +#define RV_MAX_TRIGGERS 2 /* register index of tdata CSRs */ enum { @@ -46,24 +40,33 @@ typedef enum { TRIGGER_TYPE_EXCP = 5, /* exception trigger */ TRIGGER_TYPE_AD_MATCH6 = 6, /* new address/data match trigger */ TRIGGER_TYPE_EXT_SRC = 7, /* external source trigger */ - TRIGGER_TYPE_UNAVAIL = 15 /* trigger exists, but unavailable */ + TRIGGER_TYPE_UNAVAIL = 15, /* trigger exists, but unavailable */ + TRIGGER_TYPE_NUM } trigger_type_t; -typedef struct { - target_ulong mcontrol; - target_ulong maddress; - struct CPUBreakpoint *bp; - struct CPUWatchpoint *wp; -} type2_trigger_t; +/* actions */ +typedef enum { + DBG_ACTION_NONE = -1, /* sentinel value */ + DBG_ACTION_BP = 0, + DBG_ACTION_DBG_MODE, + DBG_ACTION_TRACE0, + DBG_ACTION_TRACE1, + DBG_ACTION_TRACE2, + DBG_ACTION_TRACE3, + DBG_ACTION_EXT_DBG0 = 8, + DBG_ACTION_EXT_DBG1 +} trigger_action_t; -/* tdata field masks */ +/* tdata1 field masks */ #define RV32_TYPE(t) ((uint32_t)(t) << 28) #define RV32_TYPE_MASK (0xf << 28) #define RV32_DMODE BIT(27) +#define RV32_DATA_MASK 0x7ffffff #define RV64_TYPE(t) ((uint64_t)(t) << 60) #define RV64_TYPE_MASK (0xfULL << 60) #define RV64_DMODE BIT_ULL(59) +#define RV64_DATA_MASK 0x7ffffffffffffff /* mcontrol field masks */ @@ -82,6 +85,24 @@ typedef struct { #define TYPE2_HIT BIT(20) #define TYPE2_SIZEHI (0x3 << 21) /* RV64 only */ +/* mcontrol6 field masks */ + +#define TYPE6_LOAD BIT(0) +#define TYPE6_STORE BIT(1) +#define TYPE6_EXEC BIT(2) +#define TYPE6_U BIT(3) +#define TYPE6_S BIT(4) +#define TYPE6_M BIT(6) +#define TYPE6_MATCH (0xf << 7) +#define TYPE6_CHAIN BIT(11) +#define TYPE6_ACTION (0xf << 12) +#define TYPE6_SIZE (0xf << 16) +#define TYPE6_TIMING BIT(20) +#define TYPE6_SELECT BIT(21) +#define TYPE6_HIT BIT(22) +#define TYPE6_VU BIT(23) +#define TYPE6_VS BIT(24) + /* access size */ enum { SIZE_ANY = 0, @@ -105,6 +126,8 @@ void tselect_csr_write(CPURISCVState *env, target_ulong val); target_ulong tdata_csr_read(CPURISCVState *env, int tdata_index); void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val); +target_ulong tinfo_csr_read(CPURISCVState *env); + void riscv_cpu_debug_excp_handler(CPUState *cs); bool riscv_cpu_debug_check_breakpoint(CPUState *cs); bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp); diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 9ed049c29e..6e7bbdbd5e 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -114,20 +114,6 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n) if (env->misa_ext & RVF) { return gdb_get_reg32(buf, env->fpr[n]); } - /* there is hole between ft11 and fflags in fpu.xml */ - } else if (n < 36 && n > 32) { - target_ulong val = 0; - int result; - /* - * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP - * register 33, so we recalculate the map index. - * This also works for CSR_FRM and CSR_FCSR. - */ - result = riscv_csrrw_debug(env, n - 32, &val, - 0, 0); - if (result == RISCV_EXCP_NONE) { - return gdb_get_regl(buf, val); - } } return 0; } @@ -137,20 +123,6 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) if (n < 32) { env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */ return sizeof(uint64_t); - /* there is hole between ft11 and fflags in fpu.xml */ - } else if (n < 36 && n > 32) { - target_ulong val = ldtul_p(mem_buf); - int result; - /* - * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP - * register 33, so we recalculate the map index. - * This also works for CSR_FRM and CSR_FCSR. - */ - result = riscv_csrrw_debug(env, n - 32, NULL, - val, -1); - if (result == RISCV_EXCP_NONE) { - return sizeof(target_ulong); - } } return 0; } @@ -211,7 +183,7 @@ static int riscv_gdb_get_vector(CPURISCVState *env, GByteArray *buf, int n) target_ulong val = 0; int result = riscv_csrrw_debug(env, csrno, &val, 0, 0); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return gdb_get_regl(buf, val); } @@ -238,7 +210,7 @@ static int riscv_gdb_set_vector(CPURISCVState *env, uint8_t *mem_buf, int n) target_ulong val = ldtul_p(mem_buf); int result = riscv_csrrw_debug(env, csrno, NULL, val, -1); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return sizeof(target_ulong); } @@ -404,10 +376,10 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) CPURISCVState *env = &cpu->env; if (env->misa_ext & RVD) { gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, - 36, "riscv-64bit-fpu.xml", 0); + 32, "riscv-64bit-fpu.xml", 0); } else if (env->misa_ext & RVF) { gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, - 36, "riscv-32bit-fpu.xml", 0); + 32, "riscv-32bit-fpu.xml", 0); } if (env->misa_ext & RVV) { gdb_register_coprocessor(cs, riscv_gdb_get_vector, riscv_gdb_set_vector, diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 4ef3b2251d..a03014fe67 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -1009,9 +1009,12 @@ DEF_HELPER_6(vwredsum_vs_b, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfredsum_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredusum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredusum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredusum_vs_d, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredosum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredosum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfredosum_vs_d, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmax_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmax_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmax_vs_d, void, ptr, ptr, ptr, ptr, env, i32) @@ -1019,8 +1022,10 @@ DEF_HELPER_6(vfredmin_vs_h, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmin_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vfredmin_vs_d, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_6(vfwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredusum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredusum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredosum_vs_h, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_6(vfwredosum_vs_w, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmand_mm, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vmnand_mm, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode index 02c8f61b48..ccfe59f294 100644 --- a/target/riscv/insn16.decode +++ b/target/riscv/insn16.decode @@ -31,7 +31,8 @@ %imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1 %imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1 -%shimm_6bit 12:1 2:5 !function=ex_rvc_shifti +%shlimm_6bit 12:1 2:5 !function=ex_rvc_shiftli +%shrimm_6bit 12:1 2:5 !function=ex_rvc_shiftri %uimm_6bit_lq 2:4 12:1 6:1 !function=ex_shift_4 %uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3 %uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2 @@ -82,9 +83,9 @@ @c_addi16sp ... . ..... ..... .. &i imm=%imm_addi16sp rs1=2 rd=2 @c_shift ... . .. ... ..... .. \ - &shift rd=%rs1_3 rs1=%rs1_3 shamt=%shimm_6bit + &shift rd=%rs1_3 rs1=%rs1_3 shamt=%shrimm_6bit @c_shift2 ... . .. ... ..... .. \ - &shift rd=%rd rs1=%rd shamt=%shimm_6bit + &shift rd=%rd rs1=%rd shamt=%shlimm_6bit @c_andi ... . .. ... ..... .. &i imm=%imm_ci rs1=%rs1_3 rd=%rs1_3 diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 4033565393..d0253b8104 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -149,7 +149,12 @@ srl 0000000 ..... ..... 101 ..... 0110011 @r sra 0100000 ..... ..... 101 ..... 0110011 @r or 0000000 ..... ..... 110 ..... 0110011 @r and 0000000 ..... ..... 111 ..... 0110011 @r -fence ---- pred:4 succ:4 ----- 000 ----- 0001111 + +{ + pause 0000 0001 0000 00000 000 00000 0001111 + fence ---- pred:4 succ:4 ----- 000 ----- 0001111 +} + fence_i ---- ---- ---- ----- 001 ----- 0001111 csrrw ............ ..... 001 ..... 1110011 @csr csrrs ............ ..... 010 ..... 1110011 @csr @@ -659,11 +664,13 @@ vredmax_vs 000111 . ..... ..... 010 ..... 1010111 @r_vm vwredsumu_vs 110000 . ..... ..... 000 ..... 1010111 @r_vm vwredsum_vs 110001 . ..... ..... 000 ..... 1010111 @r_vm # Vector ordered and unordered reduction sum -vfredsum_vs 0000-1 . ..... ..... 001 ..... 1010111 @r_vm +vfredusum_vs 000001 . ..... ..... 001 ..... 1010111 @r_vm +vfredosum_vs 000011 . ..... ..... 001 ..... 1010111 @r_vm vfredmin_vs 000101 . ..... ..... 001 ..... 1010111 @r_vm vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm # Vector widening ordered and unordered float reduction sum -vfwredsum_vs 1100-1 . ..... ..... 001 ..... 1010111 @r_vm +vfwredusum_vs 110001 . ..... ..... 001 ..... 1010111 @r_vm +vfwredosum_vs 110011 . ..... ..... 001 ..... 1010111 @r_vm vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r vmandn_mm 011000 - ..... ..... 010 ..... 1010111 @r diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc index 46f96ad74d..3281408a87 100644 --- a/target/riscv/insn_trans/trans_privileged.c.inc +++ b/target/riscv/insn_trans/trans_privileged.c.inc @@ -52,7 +52,8 @@ static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a) * that no exception will be raised when fetching them. */ - if ((pre_addr & TARGET_PAGE_MASK) == (post_addr & TARGET_PAGE_MASK)) { + if (semihosting_enabled(ctx->mem_idx < PRV_S) && + (pre_addr & TARGET_PAGE_MASK) == (post_addr & TARGET_PAGE_MASK)) { pre = opcode_at(&ctx->base, pre_addr); ebreak = opcode_at(&ctx->base, ebreak_addr); post = opcode_at(&ctx->base, post_addr); diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index ca8e3d1ea1..c49dbec0eb 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -792,6 +792,22 @@ static bool trans_srad(DisasContext *ctx, arg_srad *a) return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl, NULL); } +static bool trans_pause(DisasContext *ctx, arg_pause *a) +{ + if (!ctx->cfg_ptr->ext_zihintpause) { + return false; + } + + /* + * PAUSE is a no-op in QEMU, + * end the TB and return to main loop + */ + gen_set_pc_imm(ctx, ctx->pc_succ_insn); + tcg_gen_exit_tb(NULL, 0); + ctx->base.is_jmp = DISAS_NORETURN; + + return true; +} static bool trans_fence(DisasContext *ctx, arg_fence *a) { diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 6c091824b6..4dea4413ae 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -712,6 +712,7 @@ static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); } @@ -777,6 +778,7 @@ static bool ld_us_mask_op(DisasContext *s, arg_vlm_v *a, uint8_t eew) data = FIELD_DP32(data, VDATA, NF, 1); /* Mask destination register are always tail-agnostic */ data = FIELD_DP32(data, VDATA, VTA, s->cfg_vta_all_1s); + data = FIELD_DP32(data, VDATA, VMA, s->vma); return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); } @@ -866,6 +868,7 @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); } @@ -996,6 +999,7 @@ static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); } @@ -1114,6 +1118,7 @@ static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); return ldff_trans(a->rd, a->rs1, data, fn, s); } @@ -1247,6 +1252,7 @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8, @@ -1295,6 +1301,7 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); + data = FIELD_DP32(data, VDATA, VMA, s->vma); desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); @@ -1462,6 +1469,7 @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); + data = FIELD_DP32(data, VDATA, VMA, s->vma); desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); @@ -1545,6 +1553,7 @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), @@ -1627,6 +1636,7 @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), @@ -1708,6 +1718,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ data = \ FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -1891,6 +1902,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -2349,6 +2361,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ data = \ FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -2434,6 +2447,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ data = FIELD_DP32(data, VDATA, VTA_ALL_1S, \ s->cfg_vta_all_1s); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ fns[s->sew - 1], s); \ } \ @@ -2473,6 +2487,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -2513,6 +2528,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ fns[s->sew - 1], s); \ } \ @@ -2550,6 +2566,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), cpu_env, \ @@ -2590,6 +2607,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ fns[s->sew - 1], s); \ } \ @@ -2674,6 +2692,7 @@ static bool do_opfv(DisasContext *s, arg_rmr *a, data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs2), cpu_env, s->cfg_ptr->vlen / 8, @@ -2778,6 +2797,7 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) TCGv_i32 desc; uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); static gen_helper_vmv_vx * const fns[3] = { gen_helper_vmv_v_x_h, gen_helper_vmv_v_x_w, @@ -2879,6 +2899,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), cpu_env, \ s->cfg_ptr->vlen / 8, \ @@ -2932,6 +2953,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), cpu_env, \ s->cfg_ptr->vlen / 8, \ @@ -3000,6 +3022,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), cpu_env, \ s->cfg_ptr->vlen / 8, \ @@ -3055,6 +3078,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VM, a->vm); \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = FIELD_DP32(data, VDATA, VTA, s->vta); \ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), cpu_env, \ s->cfg_ptr->vlen / 8, \ @@ -3112,7 +3136,8 @@ static bool freduction_check(DisasContext *s, arg_rmrr *a) require_zve64f(s); } -GEN_OPFVV_TRANS(vfredsum_vs, freduction_check) +GEN_OPFVV_TRANS(vfredusum_vs, freduction_check) +GEN_OPFVV_TRANS(vfredosum_vs, freduction_check) GEN_OPFVV_TRANS(vfredmax_vs, freduction_check) GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) @@ -3124,7 +3149,8 @@ static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) (s->sew != MO_8); } -GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, freduction_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwredusum_vs, freduction_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwredosum_vs, freduction_widen_check) /* *** Vector Mask Operations @@ -3251,6 +3277,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ data = \ FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ + data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ cpu_env, s->cfg_ptr->vlen / 8, \ @@ -3289,6 +3316,7 @@ static bool trans_viota_m(DisasContext *s, arg_viota_m *a) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); static gen_helper_gvec_3_ptr * const fns[4] = { gen_helper_viota_m_b, gen_helper_viota_m_h, gen_helper_viota_m_w, gen_helper_viota_m_d, @@ -3319,6 +3347,7 @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); static gen_helper_gvec_2_ptr * const fns[4] = { gen_helper_vid_v_b, gen_helper_vid_v_h, gen_helper_vid_v_w, gen_helper_vid_v_d, @@ -3864,6 +3893,7 @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); data = FIELD_DP32(data, VDATA, VTA, s->vta); + data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs2), cpu_env, diff --git a/target/riscv/instmap.h b/target/riscv/instmap.h index 40b6d2b64d..f877530576 100644 --- a/target/riscv/instmap.h +++ b/target/riscv/instmap.h @@ -184,6 +184,8 @@ enum { OPC_RISC_CSRRWI = OPC_RISC_SYSTEM | (0x5 << 12), OPC_RISC_CSRRSI = OPC_RISC_SYSTEM | (0x6 << 12), OPC_RISC_CSRRCI = OPC_RISC_SYSTEM | (0x7 << 12), + + OPC_RISC_HLVHSV = OPC_RISC_SYSTEM | (0x4 << 12), }; #define MASK_OP_FP_LOAD(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12))) @@ -310,12 +312,20 @@ enum { | (extract32(inst, 12, 8) << 12) \ | (sextract64(inst, 31, 1) << 20)) +#define GET_FUNCT3(inst) extract32(inst, 12, 3) +#define GET_FUNCT7(inst) extract32(inst, 25, 7) #define GET_RM(inst) extract32(inst, 12, 3) #define GET_RS3(inst) extract32(inst, 27, 5) #define GET_RS1(inst) extract32(inst, 15, 5) #define GET_RS2(inst) extract32(inst, 20, 5) #define GET_RD(inst) extract32(inst, 7, 5) #define GET_IMM(inst) sextract64(inst, 20, 12) +#define SET_RS1(inst, val) deposit32(inst, 15, 5, val) +#define SET_RS2(inst, val) deposit32(inst, 20, 5, val) +#define SET_RD(inst, val) deposit32(inst, 7, 5, val) +#define SET_I_IMM(inst, val) deposit32(inst, 20, 12, val) +#define SET_S_IMM(inst, val) \ + deposit32(deposit32(inst, 7, 5, val), 25, 7, (val) >> 5) /* RVC decoding macros */ #define GET_C_IMM(inst) (extract32(inst, 2, 5) \ @@ -346,6 +356,8 @@ enum { | (extract32(inst, 5, 1) << 6)) #define GET_C_LD_IMM(inst) ((extract16(inst, 10, 3) << 3) \ | (extract16(inst, 5, 2) << 6)) +#define GET_C_SW_IMM(inst) GET_C_LW_IMM(inst) +#define GET_C_SD_IMM(inst) GET_C_LD_IMM(inst) #define GET_C_J_IMM(inst) ((extract32(inst, 3, 3) << 1) \ | (extract32(inst, 11, 1) << 4) \ | (extract32(inst, 2, 1) << 5) \ @@ -366,4 +378,37 @@ enum { #define GET_C_RS1S(inst) (8 + extract16(inst, 7, 3)) #define GET_C_RS2S(inst) (8 + extract16(inst, 2, 3)) +#define GET_C_FUNC(inst) extract32(inst, 13, 3) +#define GET_C_OP(inst) extract32(inst, 0, 2) + +enum { + /* RVC Quadrants */ + OPC_RISC_C_OP_QUAD0 = 0x0, + OPC_RISC_C_OP_QUAD1 = 0x1, + OPC_RISC_C_OP_QUAD2 = 0x2 +}; + +enum { + /* RVC Quadrant 0 */ + OPC_RISC_C_FUNC_ADDI4SPN = 0x0, + OPC_RISC_C_FUNC_FLD_LQ = 0x1, + OPC_RISC_C_FUNC_LW = 0x2, + OPC_RISC_C_FUNC_FLW_LD = 0x3, + OPC_RISC_C_FUNC_FSD_SQ = 0x5, + OPC_RISC_C_FUNC_SW = 0x6, + OPC_RISC_C_FUNC_FSW_SD = 0x7 +}; + +enum { + /* RVC Quadrant 2 */ + OPC_RISC_C_FUNC_SLLI_SLLI64 = 0x0, + OPC_RISC_C_FUNC_FLDSP_LQSP = 0x1, + OPC_RISC_C_FUNC_LWSP = 0x2, + OPC_RISC_C_FUNC_FLWSP_LDSP = 0x3, + OPC_RISC_C_FUNC_JR_MV_EBREAK_JALR_ADD = 0x4, + OPC_RISC_C_FUNC_FSDSP_SQSP = 0x5, + OPC_RISC_C_FUNC_SWSP = 0x6, + OPC_RISC_C_FUNC_FSWSP_SDSP = 0x7 +}; + #endif diff --git a/target/riscv/internals.h b/target/riscv/internals.h index 193ce57a6d..5620fbffb6 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -26,8 +26,9 @@ FIELD(VDATA, VM, 0, 1) FIELD(VDATA, LMUL, 1, 3) FIELD(VDATA, VTA, 4, 1) FIELD(VDATA, VTA_ALL_1S, 5, 1) -FIELD(VDATA, NF, 6, 4) -FIELD(VDATA, WD, 6, 1) +FIELD(VDATA, VMA, 6, 1) +FIELD(VDATA, NF, 7, 4) +FIELD(VDATA, WD, 7, 1) /* float point classify helpers */ target_ulong fclass_h(uint64_t frs1); diff --git a/target/riscv/machine.c b/target/riscv/machine.c index dc182ca811..c2a94a82b3 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -92,6 +92,7 @@ static const VMStateDescription vmstate_hyper = { VMSTATE_UINTTL(env.hgeie, RISCVCPU), VMSTATE_UINTTL(env.hgeip, RISCVCPU), VMSTATE_UINT64(env.htimedelta, RISCVCPU), + VMSTATE_UINT64(env.vstimecmp, RISCVCPU), VMSTATE_UINTTL(env.hvictl, RISCVCPU), VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), @@ -228,26 +229,16 @@ static bool debug_needed(void *opaque) return riscv_feature(env, RISCV_FEATURE_DEBUG); } -static const VMStateDescription vmstate_debug_type2 = { - .name = "cpu/debug/type2", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINTTL(mcontrol, type2_trigger_t), - VMSTATE_UINTTL(maddress, type2_trigger_t), - VMSTATE_END_OF_LIST() - } -}; - static const VMStateDescription vmstate_debug = { .name = "cpu/debug", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = debug_needed, .fields = (VMStateField[]) { VMSTATE_UINTTL(env.trigger_cur, RISCVCPU), - VMSTATE_STRUCT_ARRAY(env.type2_trig, RISCVCPU, TRIGGER_TYPE2_NUM, - 0, vmstate_debug_type2, type2_trigger_t), + VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS), + VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS), + VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS), VMSTATE_END_OF_LIST() } }; @@ -307,8 +298,8 @@ static const VMStateDescription vmstate_pmu_ctr_state = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 3, - .minimum_version_id = 3, + .version_id = 5, + .minimum_version_id = 5, .post_load = riscv_cpu_post_load, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), @@ -330,7 +321,7 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINT32(env.features, RISCVCPU), VMSTATE_UINTTL(env.priv, RISCVCPU), VMSTATE_UINTTL(env.virt, RISCVCPU), - VMSTATE_UINTTL(env.resetvec, RISCVCPU), + VMSTATE_UINT64(env.resetvec, RISCVCPU), VMSTATE_UINTTL(env.mhartid, RISCVCPU), VMSTATE_UINT64(env.mstatus, RISCVCPU), VMSTATE_UINT64(env.mip, RISCVCPU), @@ -355,11 +346,12 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_STRUCT_ARRAY(env.pmu_ctrs, RISCVCPU, RV_MAX_MHPMCOUNTERS, 0, vmstate_pmu_ctr_state, PMUCTRState), VMSTATE_UINTTL_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS), + VMSTATE_UINTTL_ARRAY(env.mhpmeventh_val, RISCVCPU, RV_MAX_MHPMEVENTS), VMSTATE_UINTTL(env.sscratch, RISCVCPU), VMSTATE_UINTTL(env.mscratch, RISCVCPU), VMSTATE_UINT64(env.mfromhost, RISCVCPU), VMSTATE_UINT64(env.mtohost, RISCVCPU), - VMSTATE_UINT64(env.timecmp, RISCVCPU), + VMSTATE_UINT64(env.stimecmp, RISCVCPU), VMSTATE_END_OF_LIST() }, diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 2c1975e72c..ba25164d74 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -1,6 +1,4 @@ # FIXME extra_args should accept files() -dir = meson.current_source_dir() - gen = [ decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']), decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), @@ -31,7 +29,8 @@ riscv_softmmu_ss.add(files( 'debug.c', 'monitor.c', 'machine.c', - 'pmu.c' + 'pmu.c', + 'time_helper.c' )) target_arch += {'riscv': riscv_ss} diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index 000fe8da45..b8e56d2b7b 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -19,14 +19,435 @@ #include "qemu/osdep.h" #include "cpu.h" #include "pmu.h" +#include "sysemu/cpu-timers.h" +#include "sysemu/device_tree.h" + +#define RISCV_TIMEBASE_FREQ 1000000000 /* 1Ghz */ +#define MAKE_32BIT_MASK(shift, length) \ + (((uint32_t)(~0UL) >> (32 - (length))) << (shift)) + +/* + * To keep it simple, any event can be mapped to any programmable counters in + * QEMU. The generic cycle & instruction count events can also be monitored + * using programmable counters. In that case, mcycle & minstret must continue + * to provide the correct value as well. Heterogeneous PMU per hart is not + * supported yet. Thus, number of counters are same across all harts. + */ +void riscv_pmu_generate_fdt_node(void *fdt, int num_ctrs, char *pmu_name) +{ + uint32_t fdt_event_ctr_map[20] = {}; + uint32_t cmask; + + /* All the programmable counters can map to any event */ + cmask = MAKE_32BIT_MASK(3, num_ctrs); + + /* + * The event encoding is specified in the SBI specification + * Event idx is a 20bits wide number encoded as follows: + * event_idx[19:16] = type + * event_idx[15:0] = code + * The code field in cache events are encoded as follows: + * event_idx.code[15:3] = cache_id + * event_idx.code[2:1] = op_id + * event_idx.code[0:0] = result_id + */ + + /* SBI_PMU_HW_CPU_CYCLES: 0x01 : type(0x00) */ + fdt_event_ctr_map[0] = cpu_to_be32(0x00000001); + fdt_event_ctr_map[1] = cpu_to_be32(0x00000001); + fdt_event_ctr_map[2] = cpu_to_be32(cmask | 1 << 0); + + /* SBI_PMU_HW_INSTRUCTIONS: 0x02 : type(0x00) */ + fdt_event_ctr_map[3] = cpu_to_be32(0x00000002); + fdt_event_ctr_map[4] = cpu_to_be32(0x00000002); + fdt_event_ctr_map[5] = cpu_to_be32(cmask | 1 << 2); + + /* SBI_PMU_HW_CACHE_DTLB : 0x03 READ : 0x00 MISS : 0x00 type(0x01) */ + fdt_event_ctr_map[6] = cpu_to_be32(0x00010019); + fdt_event_ctr_map[7] = cpu_to_be32(0x00010019); + fdt_event_ctr_map[8] = cpu_to_be32(cmask); + + /* SBI_PMU_HW_CACHE_DTLB : 0x03 WRITE : 0x01 MISS : 0x00 type(0x01) */ + fdt_event_ctr_map[9] = cpu_to_be32(0x0001001B); + fdt_event_ctr_map[10] = cpu_to_be32(0x0001001B); + fdt_event_ctr_map[11] = cpu_to_be32(cmask); + + /* SBI_PMU_HW_CACHE_ITLB : 0x04 READ : 0x00 MISS : 0x00 type(0x01) */ + fdt_event_ctr_map[12] = cpu_to_be32(0x00010021); + fdt_event_ctr_map[13] = cpu_to_be32(0x00010021); + fdt_event_ctr_map[14] = cpu_to_be32(cmask); + + /* This a OpenSBI specific DT property documented in OpenSBI docs */ + qemu_fdt_setprop(fdt, pmu_name, "riscv,event-to-mhpmcounters", + fdt_event_ctr_map, sizeof(fdt_event_ctr_map)); +} + +static bool riscv_pmu_counter_valid(RISCVCPU *cpu, uint32_t ctr_idx) +{ + if (ctr_idx < 3 || ctr_idx >= RV_MAX_MHPMCOUNTERS || + !(cpu->pmu_avail_ctrs & BIT(ctr_idx))) { + return false; + } else { + return true; + } +} + +static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uint32_t ctr_idx) +{ + CPURISCVState *env = &cpu->env; + + if (riscv_pmu_counter_valid(cpu, ctr_idx) && + !get_field(env->mcountinhibit, BIT(ctr_idx))) { + return true; + } else { + return false; + } +} + +static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx) +{ + CPURISCVState *env = &cpu->env; + target_ulong max_val = UINT32_MAX; + PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; + bool virt_on = riscv_cpu_virt_enabled(env); + + /* Privilege mode filtering */ + if ((env->priv == PRV_M && + (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_MINH)) || + (env->priv == PRV_S && virt_on && + (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VSINH)) || + (env->priv == PRV_U && virt_on && + (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VUINH)) || + (env->priv == PRV_S && !virt_on && + (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_SINH)) || + (env->priv == PRV_U && !virt_on && + (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_UINH))) { + return 0; + } + + /* Handle the overflow scenario */ + if (counter->mhpmcounter_val == max_val) { + if (counter->mhpmcounterh_val == max_val) { + counter->mhpmcounter_val = 0; + counter->mhpmcounterh_val = 0; + /* Generate interrupt only if OF bit is clear */ + if (!(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_OF)) { + env->mhpmeventh_val[ctr_idx] |= MHPMEVENTH_BIT_OF; + riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1)); + } + } else { + counter->mhpmcounterh_val++; + } + } else { + counter->mhpmcounter_val++; + } + + return 0; +} + +static int riscv_pmu_incr_ctr_rv64(RISCVCPU *cpu, uint32_t ctr_idx) +{ + CPURISCVState *env = &cpu->env; + PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; + uint64_t max_val = UINT64_MAX; + bool virt_on = riscv_cpu_virt_enabled(env); + + /* Privilege mode filtering */ + if ((env->priv == PRV_M && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || + (env->priv == PRV_S && virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || + (env->priv == PRV_U && virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || + (env->priv == PRV_S && !virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || + (env->priv == PRV_U && !virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { + return 0; + } + + /* Handle the overflow scenario */ + if (counter->mhpmcounter_val == max_val) { + counter->mhpmcounter_val = 0; + /* Generate interrupt only if OF bit is clear */ + if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { + env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; + riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1)); + } + } else { + counter->mhpmcounter_val++; + } + return 0; +} + +int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) +{ + uint32_t ctr_idx; + int ret; + CPURISCVState *env = &cpu->env; + gpointer value; + + if (!cpu->cfg.pmu_num) { + return 0; + } + value = g_hash_table_lookup(cpu->pmu_event_ctr_map, + GUINT_TO_POINTER(event_idx)); + if (!value) { + return -1; + } + + ctr_idx = GPOINTER_TO_UINT(value); + if (!riscv_pmu_counter_enabled(cpu, ctr_idx) || + get_field(env->mcountinhibit, BIT(ctr_idx))) { + return -1; + } + + if (riscv_cpu_mxl(env) == MXL_RV32) { + ret = riscv_pmu_incr_ctr_rv32(cpu, ctr_idx); + } else { + ret = riscv_pmu_incr_ctr_rv64(cpu, ctr_idx); + } + + return ret; +} bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env, uint32_t target_ctr) { - return (target_ctr == 0) ? true : false; + RISCVCPU *cpu; + uint32_t event_idx; + uint32_t ctr_idx; + + /* Fixed instret counter */ + if (target_ctr == 2) { + return true; + } + + cpu = RISCV_CPU(env_cpu(env)); + if (!cpu->pmu_event_ctr_map) { + return false; + } + + event_idx = RISCV_PMU_EVENT_HW_INSTRUCTIONS; + ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map, + GUINT_TO_POINTER(event_idx))); + if (!ctr_idx) { + return false; + } + + return target_ctr == ctr_idx ? true : false; } bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr) { - return (target_ctr == 2) ? true : false; + RISCVCPU *cpu; + uint32_t event_idx; + uint32_t ctr_idx; + + /* Fixed mcycle counter */ + if (target_ctr == 0) { + return true; + } + + cpu = RISCV_CPU(env_cpu(env)); + if (!cpu->pmu_event_ctr_map) { + return false; + } + + event_idx = RISCV_PMU_EVENT_HW_CPU_CYCLES; + ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map, + GUINT_TO_POINTER(event_idx))); + + /* Counter zero is not used for event_ctr_map */ + if (!ctr_idx) { + return false; + } + + return (target_ctr == ctr_idx) ? true : false; +} + +static gboolean pmu_remove_event_map(gpointer key, gpointer value, + gpointer udata) +{ + return (GPOINTER_TO_UINT(value) == GPOINTER_TO_UINT(udata)) ? true : false; +} + +static int64_t pmu_icount_ticks_to_ns(int64_t value) +{ + int64_t ret = 0; + + if (icount_enabled()) { + ret = icount_to_ns(value); + } else { + ret = (NANOSECONDS_PER_SECOND / RISCV_TIMEBASE_FREQ) * value; + } + + return ret; +} + +int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value, + uint32_t ctr_idx) +{ + uint32_t event_idx; + RISCVCPU *cpu = RISCV_CPU(env_cpu(env)); + + if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->pmu_event_ctr_map) { + return -1; + } + + /* + * Expected mhpmevent value is zero for reset case. Remove the current + * mapping. + */ + if (!value) { + g_hash_table_foreach_remove(cpu->pmu_event_ctr_map, + pmu_remove_event_map, + GUINT_TO_POINTER(ctr_idx)); + return 0; + } + + event_idx = value & MHPMEVENT_IDX_MASK; + if (g_hash_table_lookup(cpu->pmu_event_ctr_map, + GUINT_TO_POINTER(event_idx))) { + return 0; + } + + switch (event_idx) { + case RISCV_PMU_EVENT_HW_CPU_CYCLES: + case RISCV_PMU_EVENT_HW_INSTRUCTIONS: + case RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS: + case RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS: + case RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS: + break; + default: + /* We don't support any raw events right now */ + return -1; + } + g_hash_table_insert(cpu->pmu_event_ctr_map, GUINT_TO_POINTER(event_idx), + GUINT_TO_POINTER(ctr_idx)); + + return 0; +} + +static void pmu_timer_trigger_irq(RISCVCPU *cpu, + enum riscv_pmu_event_idx evt_idx) +{ + uint32_t ctr_idx; + CPURISCVState *env = &cpu->env; + PMUCTRState *counter; + target_ulong *mhpmevent_val; + uint64_t of_bit_mask; + int64_t irq_trigger_at; + + if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES && + evt_idx != RISCV_PMU_EVENT_HW_INSTRUCTIONS) { + return; + } + + ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map, + GUINT_TO_POINTER(evt_idx))); + if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) { + return; + } + + if (riscv_cpu_mxl(env) == MXL_RV32) { + mhpmevent_val = &env->mhpmeventh_val[ctr_idx]; + of_bit_mask = MHPMEVENTH_BIT_OF; + } else { + mhpmevent_val = &env->mhpmevent_val[ctr_idx]; + of_bit_mask = MHPMEVENT_BIT_OF; + } + + counter = &env->pmu_ctrs[ctr_idx]; + if (counter->irq_overflow_left > 0) { + irq_trigger_at = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + counter->irq_overflow_left; + timer_mod_anticipate_ns(cpu->pmu_timer, irq_trigger_at); + counter->irq_overflow_left = 0; + return; + } + + if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) { + /* Generate interrupt only if OF bit is clear */ + if (!(*mhpmevent_val & of_bit_mask)) { + *mhpmevent_val |= of_bit_mask; + riscv_cpu_update_mip(cpu, MIP_LCOFIP, BOOL_TO_MASK(1)); + } + } +} + +/* Timer callback for instret and cycle counter overflow */ +void riscv_pmu_timer_cb(void *priv) +{ + RISCVCPU *cpu = priv; + + /* Timer event was triggered only for these events */ + pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_CPU_CYCLES); + pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_INSTRUCTIONS); +} + +int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx) +{ + uint64_t overflow_delta, overflow_at; + int64_t overflow_ns, overflow_left = 0; + RISCVCPU *cpu = RISCV_CPU(env_cpu(env)); + PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; + + if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf) { + return -1; + } + + if (value) { + overflow_delta = UINT64_MAX - value + 1; + } else { + overflow_delta = UINT64_MAX; + } + + /* + * QEMU supports only int64_t timers while RISC-V counters are uint64_t. + * Compute the leftover and save it so that it can be reprogrammed again + * when timer expires. + */ + if (overflow_delta > INT64_MAX) { + overflow_left = overflow_delta - INT64_MAX; + } + + if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + overflow_ns = pmu_icount_ticks_to_ns((int64_t)overflow_delta); + overflow_left = pmu_icount_ticks_to_ns(overflow_left) ; + } else { + return -1; + } + overflow_at = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + overflow_ns; + + if (overflow_at > INT64_MAX) { + overflow_left += overflow_at - INT64_MAX; + counter->irq_overflow_left = overflow_left; + overflow_at = INT64_MAX; + } + timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); + + return 0; +} + + +int riscv_pmu_init(RISCVCPU *cpu, int num_counters) +{ + if (num_counters > (RV_MAX_MHPMCOUNTERS - 3)) { + return -1; + } + + cpu->pmu_event_ctr_map = g_hash_table_new(g_direct_hash, g_direct_equal); + if (!cpu->pmu_event_ctr_map) { + /* PMU support can not be enabled */ + qemu_log_mask(LOG_UNIMP, "PMU events can't be supported\n"); + cpu->cfg.pmu_num = 0; + return -1; + } + + /* Create a bitmask of available programmable counters */ + cpu->pmu_avail_ctrs = MAKE_32BIT_MASK(3, num_counters); + + return 0; } diff --git a/target/riscv/pmu.h b/target/riscv/pmu.h index 58a5bc3a40..3004ce37b6 100644 --- a/target/riscv/pmu.h +++ b/target/riscv/pmu.h @@ -26,3 +26,11 @@ bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env, uint32_t target_ctr); bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr); +void riscv_pmu_timer_cb(void *priv); +int riscv_pmu_init(RISCVCPU *cpu, int num_counters); +int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value, + uint32_t ctr_idx); +int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx); +void riscv_pmu_generate_fdt_node(void *fdt, int num_counters, char *pmu_name); +int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, + uint32_t ctr_idx); diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c new file mode 100644 index 0000000000..8cce667dfd --- /dev/null +++ b/target/riscv/time_helper.c @@ -0,0 +1,114 @@ +/* + * RISC-V timer helper implementation. + * + * Copyright (c) 2022 Rivos Inc. + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu_bits.h" +#include "time_helper.h" +#include "hw/intc/riscv_aclint.h" + +static void riscv_vstimer_cb(void *opaque) +{ + RISCVCPU *cpu = opaque; + CPURISCVState *env = &cpu->env; + env->vstime_irq = 1; + riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1)); +} + +static void riscv_stimer_cb(void *opaque) +{ + RISCVCPU *cpu = opaque; + riscv_cpu_update_mip(cpu, MIP_STIP, BOOL_TO_MASK(1)); +} + +/* + * Called when timecmp is written to update the QEMU timer or immediately + * trigger timer interrupt if mtimecmp <= current timer value. + */ +void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer, + uint64_t timecmp, uint64_t delta, + uint32_t timer_irq) +{ + uint64_t diff, ns_diff, next; + CPURISCVState *env = &cpu->env; + RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg; + uint32_t timebase_freq = mtimer->timebase_freq; + uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta; + + if (timecmp <= rtc_r) { + /* + * If we're setting an stimecmp value in the "past", + * immediately raise the timer interrupt + */ + if (timer_irq == MIP_VSTIP) { + env->vstime_irq = 1; + } + riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1)); + return; + } + + if (timer_irq == MIP_VSTIP) { + env->vstime_irq = 0; + } + /* Clear the [V]STIP bit in mip */ + riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0)); + + /* otherwise, set up the future timer interrupt */ + diff = timecmp - rtc_r; + /* back to ns (note args switched in muldiv64) */ + ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq); + + /* + * check if ns_diff overflowed and check if the addition would potentially + * overflow + */ + if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) || + ns_diff > INT64_MAX) { + next = INT64_MAX; + } else { + /* + * as it is very unlikely qemu_clock_get_ns will return a value + * greater than INT64_MAX, no additional check is needed for an + * unsigned integer overflow. + */ + next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff; + /* + * if ns_diff is INT64_MAX next may still be outside the range + * of a signed integer. + */ + next = MIN(next, INT64_MAX); + } + + timer_mod(timer, next); +} + +void riscv_timer_init(RISCVCPU *cpu) +{ + CPURISCVState *env; + + if (!cpu) { + return; + } + + env = &cpu->env; + env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu); + env->stimecmp = 0; + + env->vstimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_cb, cpu); + env->vstimecmp = 0; +} diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h new file mode 100644 index 0000000000..7b3cdcc350 --- /dev/null +++ b/target/riscv/time_helper.h @@ -0,0 +1,30 @@ +/* + * RISC-V timer header file. + * + * Copyright (c) 2022 Rivos Inc. + * + * 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 . + */ + +#ifndef RISCV_TIME_HELPER_H +#define RISCV_TIME_HELPER_H + +#include "cpu.h" +#include "qemu/timer.h" + +void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer, + uint64_t timecmp, uint64_t delta, + uint32_t timer_irq); +void riscv_timer_init(RISCVCPU *cpu); + +#endif diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 63b04e8a94..db123da5ec 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -28,6 +28,7 @@ #include "exec/translator.h" #include "exec/log.h" +#include "semihosting/semihost.h" #include "instmap.h" #include "internals.h" @@ -95,6 +96,7 @@ typedef struct DisasContext { int8_t lmul; uint8_t sew; uint8_t vta; + uint8_t vma; bool cfg_vta_all_1s; target_ulong vstart; bool vl_eq_vlmax; @@ -544,7 +546,7 @@ static TCGv get_address(DisasContext *ctx, int rs1, int imm) tcg_gen_addi_tl(addr, src1, imm); if (ctx->pm_mask_enabled) { - tcg_gen_and_tl(addr, addr, pm_mask); + tcg_gen_andc_tl(addr, addr, pm_mask); } else if (get_xl(ctx) == MXL_RV32) { tcg_gen_ext32u_tl(addr, addr); } @@ -705,10 +707,26 @@ static int ex_rvc_register(DisasContext *ctx, int reg) return 8 + reg; } -static int ex_rvc_shifti(DisasContext *ctx, int imm) +static int ex_rvc_shiftli(DisasContext *ctx, int imm) { /* For RV128 a shamt of 0 means a shift by 64. */ - return imm ? imm : 64; + if (get_ol(ctx) == MXL_RV128) { + imm = imm ? imm : 64; + } + return imm; +} + +static int ex_rvc_shiftri(DisasContext *ctx, int imm) +{ + /* + * For RV128 a shamt of 0 means a shift by 64, furthermore, for right + * shifts, the shamt is sign-extended. + */ + if (get_ol(ctx) == MXL_RV128) { + imm = imm | (imm & 32) << 1; + imm = imm ? imm : 64; + } + return imm; } /* Include the auto-generated decoder for 32 bit insn */ @@ -1022,6 +1040,14 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) /* Include decoders for factored-out extensions */ #include "decode-XVentanaCondOps.c.inc" +/* The specification allows for longer insns, but not supported by qemu. */ +#define MAX_INSN_LEN 4 + +static inline int insn_len(uint16_t first_word) +{ + return (first_word & 3) == 3 ? 4 : 2; +} + static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) { /* @@ -1037,7 +1063,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) }; /* Check for compressed insn */ - if (extract16(opcode, 0, 2) != 3) { + if (insn_len(opcode) == 2) { if (!has_ext(ctx, RVC)) { gen_exception_illegal(ctx); } else { @@ -1097,6 +1123,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW); ctx->lmul = sextract32(FIELD_EX32(tb_flags, TB_FLAGS, LMUL), 0, 3); ctx->vta = FIELD_EX32(tb_flags, TB_FLAGS, VTA) && cpu->cfg.rvv_ta_all_1s; + ctx->vma = FIELD_EX32(tb_flags, TB_FLAGS, VMA) && cpu->cfg.rvv_ma_all_1s; ctx->cfg_vta_all_1s = cpu->cfg.rvv_ta_all_1s; ctx->vstart = env->vstart; ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); @@ -1146,12 +1173,21 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) } ctx->nftemp = 0; + /* Only the first insn within a TB is allowed to cross a page boundary. */ if (ctx->base.is_jmp == DISAS_NEXT) { - target_ulong page_start; - - page_start = ctx->base.pc_first & TARGET_PAGE_MASK; - if (ctx->base.pc_next - page_start >= TARGET_PAGE_SIZE) { + if (!is_same_page(&ctx->base, ctx->base.pc_next)) { ctx->base.is_jmp = DISAS_TOO_MANY; + } else { + unsigned page_ofs = ctx->base.pc_next & ~TARGET_PAGE_MASK; + + if (page_ofs > TARGET_PAGE_SIZE - MAX_INSN_LEN) { + uint16_t next_insn = cpu_lduw_code(env, ctx->base.pc_next); + int len = insn_len(next_insn); + + if (!is_same_page(&ctx->base, ctx->base.pc_next + len)) { + ctx->base.is_jmp = DISAS_TOO_MANY; + } + } } } } @@ -1196,11 +1232,12 @@ static const TranslatorOps riscv_tr_ops = { .disas_log = riscv_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&riscv_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &riscv_tr_ops, &ctx.base); } void riscv_translate_init(void) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index a96fc49c71..b94f809eb3 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -127,6 +127,11 @@ static inline uint32_t vext_vta(uint32_t desc) return FIELD_EX32(simd_data(desc), VDATA, VTA); } +static inline uint32_t vext_vma(uint32_t desc) +{ + return FIELD_EX32(simd_data(desc), VDATA, VMA); +} + static inline uint32_t vext_vta_all_1s(uint32_t desc) { return FIELD_EX32(simd_data(desc), VDATA, VTA_ALL_1S); @@ -278,14 +283,18 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, uint32_t esz = 1 << log2_esz; uint32_t total_elems = vext_get_total_elems(env, desc, esz); uint32_t vta = vext_vta(desc); + uint32_t vma = vext_vma(desc); for (i = env->vstart; i < env->vl; i++, env->vstart++) { - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } - k = 0; while (k < nf) { + if (!vm && !vext_elem_mask(v0, i)) { + /* set masked-off elements to 1s */ + vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz, + (i + k * max_elems + 1) * esz); + k++; + continue; + } target_ulong addr = base + stride * i + (k << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; @@ -477,15 +486,19 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, uint32_t esz = 1 << log2_esz; uint32_t total_elems = vext_get_total_elems(env, desc, esz); uint32_t vta = vext_vta(desc); + uint32_t vma = vext_vma(desc); /* load bytes from guest memory */ for (i = env->vstart; i < env->vl; i++, env->vstart++) { - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } - k = 0; while (k < nf) { + if (!vm && !vext_elem_mask(v0, i)) { + /* set masked-off elements to 1s */ + vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz, + (i + k * max_elems + 1) * esz); + k++; + continue; + } abi_ptr addr = get_index_addr(base, i, vs2) + (k << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; @@ -574,6 +587,7 @@ vext_ldff(void *vd, void *v0, target_ulong base, uint32_t esz = 1 << log2_esz; uint32_t total_elems = vext_get_total_elems(env, desc, esz); uint32_t vta = vext_vta(desc); + uint32_t vma = vext_vma(desc); target_ulong addr, offset, remain; /* probe every access*/ @@ -619,10 +633,14 @@ ProbeSuccess: } for (i = env->vstart; i < env->vl; i++) { k = 0; - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } while (k < nf) { + if (!vm && !vext_elem_mask(v0, i)) { + /* set masked-off elements to 1s */ + vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz, + (i + k * max_elems + 1) * esz); + k++; + continue; + } target_ulong addr = base + ((i * nf + k) << log2_esz); ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; @@ -812,10 +830,13 @@ static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2, uint32_t vl = env->vl; uint32_t total_elems = vext_get_total_elems(env, desc, esz); uint32_t vta = vext_vta(desc); + uint32_t vma = vext_vma(desc); uint32_t i; for (i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { + /* set masked-off elements to 1s */ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); continue; } fn(vd, vs1, vs2, i); @@ -878,10 +899,13 @@ static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2, uint32_t vl = env->vl; uint32_t total_elems = vext_get_total_elems(env, desc, esz); uint32_t vta = vext_vta(desc); + uint32_t vma = vext_vma(desc); uint32_t i; for (i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { + /* set masked-off elements to 1s */ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); continue; } fn(vd, s1, vs2, i); @@ -1274,10 +1298,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t esz = sizeof(TS1); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ TS1 s1 = *((TS1 *)vs1 + HS1(i)); \ @@ -1315,10 +1342,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ uint32_t total_elems = \ vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, \ + (i + 1) * esz); \ continue; \ } \ TS2 s2 = *((TS2 *)vs2 + HS2(i)); \ @@ -1373,12 +1404,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vl = env->vl; \ uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + if (vma) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ continue; \ } \ vext_set_elem_mask(vd, i, DO_OP(s2, s1)); \ @@ -1431,11 +1467,16 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vl = env->vl; \ uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + if (vma) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ continue; \ } \ vext_set_elem_mask(vd, i, \ @@ -2088,10 +2129,12 @@ static inline void vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2, CPURISCVState *env, uint32_t vl, uint32_t vm, int vxrm, - opivv2_rm_fn *fn) + opivv2_rm_fn *fn, uint32_t vma, uint32_t esz) { for (uint32_t i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { + /* set masked-off elements to 1s */ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); continue; } fn(vd, vs1, vs2, i, env, vxrm); @@ -2109,23 +2152,24 @@ vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2, uint32_t vl = env->vl; uint32_t total_elems = vext_get_total_elems(env, desc, esz); uint32_t vta = vext_vta(desc); + uint32_t vma = vext_vma(desc); switch (env->vxrm) { case 0: /* rnu */ vext_vv_rm_1(vd, v0, vs1, vs2, - env, vl, vm, 0, fn); + env, vl, vm, 0, fn, vma, esz); break; case 1: /* rne */ vext_vv_rm_1(vd, v0, vs1, vs2, - env, vl, vm, 1, fn); + env, vl, vm, 1, fn, vma, esz); break; case 2: /* rdn */ vext_vv_rm_1(vd, v0, vs1, vs2, - env, vl, vm, 2, fn); + env, vl, vm, 2, fn, vma, esz); break; default: /* rod */ vext_vv_rm_1(vd, v0, vs1, vs2, - env, vl, vm, 3, fn); + env, vl, vm, 3, fn, vma, esz); break; } /* set tail elements to 1s */ @@ -2209,10 +2253,12 @@ static inline void vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2, CPURISCVState *env, uint32_t vl, uint32_t vm, int vxrm, - opivx2_rm_fn *fn) + opivx2_rm_fn *fn, uint32_t vma, uint32_t esz) { for (uint32_t i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { + /* set masked-off elements to 1s */ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); continue; } fn(vd, s1, vs2, i, env, vxrm); @@ -2230,23 +2276,24 @@ vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2, uint32_t vl = env->vl; uint32_t total_elems = vext_get_total_elems(env, desc, esz); uint32_t vta = vext_vta(desc); + uint32_t vma = vext_vma(desc); switch (env->vxrm) { case 0: /* rnu */ vext_vx_rm_1(vd, v0, s1, vs2, - env, vl, vm, 0, fn); + env, vl, vm, 0, fn, vma, esz); break; case 1: /* rne */ vext_vx_rm_1(vd, v0, s1, vs2, - env, vl, vm, 1, fn); + env, vl, vm, 1, fn, vma, esz); break; case 2: /* rdn */ vext_vx_rm_1(vd, v0, s1, vs2, - env, vl, vm, 2, fn); + env, vl, vm, 2, fn, vma, esz); break; default: /* rod */ vext_vx_rm_1(vd, v0, s1, vs2, - env, vl, vm, 3, fn); + env, vl, vm, 3, fn, vma, esz); break; } /* set tail elements to 1s */ @@ -3004,10 +3051,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t total_elems = \ vext_get_total_elems(env, desc, ESZ); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * ESZ, \ + (i + 1) * ESZ); \ continue; \ } \ do_##NAME(vd, vs1, vs2, i, env); \ @@ -3043,10 +3094,14 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \ uint32_t total_elems = \ vext_get_total_elems(env, desc, ESZ); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * ESZ, \ + (i + 1) * ESZ); \ continue; \ } \ do_##NAME(vd, s1, vs2, i, env); \ @@ -3618,6 +3673,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ uint32_t total_elems = \ vext_get_total_elems(env, desc, ESZ); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ if (vl == 0) { \ @@ -3625,6 +3681,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ } \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * ESZ, \ + (i + 1) * ESZ); \ continue; \ } \ do_##NAME(vd, vs2, i, env); \ @@ -4135,12 +4194,17 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vl = env->vl; \ uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + if (vma) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ continue; \ } \ vext_set_elem_mask(vd, i, \ @@ -4168,11 +4232,16 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ uint32_t vl = env->vl; \ uint32_t total_elems = env_archcpu(env)->cfg.vlen; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + if (vma) { \ + vext_set_elem_mask(vd, i, 1); \ + } \ continue; \ } \ vext_set_elem_mask(vd, i, \ @@ -4295,10 +4364,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ uint32_t total_elems = \ vext_get_total_elems(env, desc, ESZ); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * ESZ, \ + (i + 1) * ESZ); \ continue; \ } \ do_##NAME(vd, vs2, i); \ @@ -4641,9 +4714,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ } /* Unordered sum */ -GEN_VEXT_FRED(vfredsum_vs_h, uint16_t, uint16_t, H2, H2, float16_add) -GEN_VEXT_FRED(vfredsum_vs_w, uint32_t, uint32_t, H4, H4, float32_add) -GEN_VEXT_FRED(vfredsum_vs_d, uint64_t, uint64_t, H8, H8, float64_add) +GEN_VEXT_FRED(vfredusum_vs_h, uint16_t, uint16_t, H2, H2, float16_add) +GEN_VEXT_FRED(vfredusum_vs_w, uint32_t, uint32_t, H4, H4, float32_add) +GEN_VEXT_FRED(vfredusum_vs_d, uint64_t, uint64_t, H8, H8, float64_add) + +/* Ordered sum */ +GEN_VEXT_FRED(vfredosum_vs_h, uint16_t, uint16_t, H2, H2, float16_add) +GEN_VEXT_FRED(vfredosum_vs_w, uint32_t, uint32_t, H4, H4, float32_add) +GEN_VEXT_FRED(vfredosum_vs_d, uint64_t, uint64_t, H8, H8, float64_add) /* Maximum value */ GEN_VEXT_FRED(vfredmax_vs_h, uint16_t, uint16_t, H2, H2, float16_maximum_number) @@ -4655,57 +4733,23 @@ GEN_VEXT_FRED(vfredmin_vs_h, uint16_t, uint16_t, H2, H2, float16_minimum_number) GEN_VEXT_FRED(vfredmin_vs_w, uint32_t, uint32_t, H4, H4, float32_minimum_number) GEN_VEXT_FRED(vfredmin_vs_d, uint64_t, uint64_t, H8, H8, float64_minimum_number) +/* Vector Widening Floating-Point Add Instructions */ +static uint32_t fwadd16(uint32_t a, uint16_t b, float_status *s) +{ + return float32_add(a, float16_to_float32(b, true, s), s); +} + +static uint64_t fwadd32(uint64_t a, uint32_t b, float_status *s) +{ + return float64_add(a, float32_to_float64(b, s), s); +} + /* Vector Widening Floating-Point Reduction Instructions */ -/* Unordered reduce 2*SEW = 2*SEW + sum(promote(SEW)) */ -void HELPER(vfwredsum_vs_h)(void *vd, void *v0, void *vs1, - void *vs2, CPURISCVState *env, uint32_t desc) -{ - uint32_t vm = vext_vm(desc); - uint32_t vl = env->vl; - uint32_t esz = sizeof(uint32_t); - uint32_t vlenb = simd_maxsz(desc); - uint32_t vta = vext_vta(desc); - uint32_t i; - uint32_t s1 = *((uint32_t *)vs1 + H4(0)); - - for (i = env->vstart; i < vl; i++) { - uint16_t s2 = *((uint16_t *)vs2 + H2(i)); - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } - s1 = float32_add(s1, float16_to_float32(s2, true, &env->fp_status), - &env->fp_status); - } - *((uint32_t *)vd + H4(0)) = s1; - env->vstart = 0; - /* set tail elements to 1s */ - vext_set_elems_1s(vd, vta, esz, vlenb); -} - -void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1, - void *vs2, CPURISCVState *env, uint32_t desc) -{ - uint32_t vm = vext_vm(desc); - uint32_t vl = env->vl; - uint32_t esz = sizeof(uint64_t); - uint32_t vlenb = simd_maxsz(desc); - uint32_t vta = vext_vta(desc); - uint32_t i; - uint64_t s1 = *((uint64_t *)vs1); - - for (i = env->vstart; i < vl; i++) { - uint32_t s2 = *((uint32_t *)vs2 + H4(i)); - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } - s1 = float64_add(s1, float32_to_float64(s2, &env->fp_status), - &env->fp_status); - } - *((uint64_t *)vd) = s1; - env->vstart = 0; - /* set tail elements to 1s */ - vext_set_elems_1s(vd, vta, esz, vlenb); -} +/* Ordered/unordered reduce 2*SEW = 2*SEW + sum(promote(SEW)) */ +GEN_VEXT_FRED(vfwredusum_vs_h, uint32_t, uint16_t, H4, H2, fwadd16) +GEN_VEXT_FRED(vfwredusum_vs_w, uint64_t, uint32_t, H8, H4, fwadd32) +GEN_VEXT_FRED(vfwredosum_vs_h, uint32_t, uint16_t, H4, H2, fwadd16) +GEN_VEXT_FRED(vfwredosum_vs_w, uint64_t, uint32_t, H8, H4, fwadd32) /* *** Vector Mask Operations @@ -4806,11 +4850,16 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env, uint32_t vl = env->vl; uint32_t total_elems = env_archcpu(env)->cfg.vlen; uint32_t vta_all_1s = vext_vta_all_1s(desc); + uint32_t vma = vext_vma(desc); int i; bool first_mask_bit = false; for (i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { + /* set masked-off elements to 1s */ + if (vma) { + vext_set_elem_mask(vd, i, 1); + } continue; } /* write a zero to all following active elements */ @@ -4871,11 +4920,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \ uint32_t esz = sizeof(ETYPE); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t sum = 0; \ int i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ *((ETYPE *)vd + H(i)) = sum; \ @@ -4902,10 +4954,13 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \ uint32_t esz = sizeof(ETYPE); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ int i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ *((ETYPE *)vd + H(i)) = i; \ @@ -4934,11 +4989,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t esz = sizeof(ETYPE); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ target_ulong offset = s1, i_min, i; \ \ i_min = MAX(env->vstart, offset); \ for (i = i_min; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - offset)); \ @@ -4963,13 +5021,17 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t esz = sizeof(ETYPE); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ target_ulong i_max, i; \ \ i_max = MAX(MIN(s1 < vlmax ? vlmax - s1 : 0, vl), env->vstart); \ for (i = env->vstart; i < i_max; ++i) { \ - if (vm || vext_elem_mask(v0, i)) { \ - *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i + s1)); \ + if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ + continue; \ } \ + *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i + s1)); \ } \ \ for (i = i_max; i < vl; ++i) { \ @@ -4999,10 +5061,13 @@ static void vslide1up_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ uint32_t esz = sizeof(ETYPE); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ if (i == 0) { \ @@ -5044,10 +5109,13 @@ static void vslide1down_##BITWIDTH(void *vd, void *v0, target_ulong s1, \ uint32_t esz = sizeof(ETYPE); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ if (i == vl - 1) { \ @@ -5115,11 +5183,14 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t esz = sizeof(TS2); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint64_t index; \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ index = *((TS1 *)vs1 + HS1(i)); \ @@ -5155,11 +5226,14 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t esz = sizeof(ETYPE); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint64_t index = s1; \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ if (index >= vlmax) { \ @@ -5234,10 +5308,13 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ uint32_t esz = sizeof(ETYPE); \ uint32_t total_elems = vext_get_total_elems(env, desc, esz); \ uint32_t vta = vext_vta(desc); \ + uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ + /* set masked-off elements to 1s */ \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ continue; \ } \ *((ETYPE *)vd + HD(i)) = *((DTYPE *)vs2 + HS1(i)); \ diff --git a/target/rx/cpu.c b/target/rx/cpu.c index fb30080ac4..2f28099723 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -32,12 +32,19 @@ static void rx_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.pc = value; } +static vaddr rx_cpu_get_pc(CPUState *cs) +{ + RXCPU *cpu = RX_CPU(cs); + + return cpu->env.pc; +} + static void rx_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { RXCPU *cpu = RX_CPU(cs); - cpu->env.pc = tb->pc; + cpu->env.pc = tb_pc(tb); } static bool rx_cpu_has_work(CPUState *cs) @@ -208,6 +215,7 @@ static void rx_cpu_class_init(ObjectClass *klass, void *data) cc->has_work = rx_cpu_has_work; cc->dump_state = rx_cpu_dump_state; cc->set_pc = rx_cpu_set_pc; + cc->get_pc = rx_cpu_get_pc; #ifndef CONFIG_USER_ONLY cc->sysemu_ops = &rx_sysemu_ops; diff --git a/target/rx/translate.c b/target/rx/translate.c index 62aee66937..ea5653bc95 100644 --- a/target/rx/translate.c +++ b/target/rx/translate.c @@ -2363,11 +2363,12 @@ static const TranslatorOps rx_tr_ops = { .disas_log = rx_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc; - translator_loop(&rx_tr_ops, &dc.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &rx_tr_ops, &dc.base); } void restore_state_to_opc(CPURXState *env, TranslationBlock *tb, diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c index 08daf93ae1..f60a14920d 100644 --- a/target/s390x/arch_dump.c +++ b/target/s390x/arch_dump.c @@ -204,7 +204,7 @@ static const NoteFuncDesc note_linux[] = { static int s390x_write_elf64_notes(const char *note_name, WriteCoreDumpFunction f, S390CPU *cpu, int id, - void *opaque, + DumpState *s, const NoteFuncDesc *funcs) { Note note; @@ -222,7 +222,7 @@ static int s390x_write_elf64_notes(const char *note_name, (*nf->note_contents_func)(¬e, cpu, id); note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; - ret = f(¬e, note_size, opaque); + ret = f(¬e, note_size, s); if (ret < 0) { return -1; @@ -235,16 +235,16 @@ static int s390x_write_elf64_notes(const char *note_name, int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque) + int cpuid, DumpState *s) { S390CPU *cpu = S390_CPU(cs); int r; - r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, opaque, note_core); + r = s390x_write_elf64_notes("CORE", f, cpu, cpuid, s, note_core); if (r) { return r; } - return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, opaque, note_linux); + return s390x_write_elf64_notes("LINUX", f, cpu, cpuid, s, note_linux); } int cpu_get_dump_info(ArchDumpInfo *info, diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index c31bb2351f..df00040e95 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -88,6 +88,13 @@ static void s390_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.psw.addr = value; } +static vaddr s390_cpu_get_pc(CPUState *cs) +{ + S390CPU *cpu = S390_CPU(cs); + + return cpu->env.psw.addr; +} + static bool s390_cpu_has_work(CPUState *cs) { S390CPU *cpu = S390_CPU(cs); @@ -297,6 +304,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = s390_cpu_has_work; cc->dump_state = s390_cpu_dump_state; cc->set_pc = s390_cpu_set_pc; + cc->get_pc = s390_cpu_get_pc; cc->gdb_read_register = s390_cpu_gdb_read_register; cc->gdb_write_register = s390_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/s390x/cpu_features_def.h.inc b/target/s390x/cpu_features_def.h.inc index 3603e5fb12..e3cfe63735 100644 --- a/target/s390x/cpu_features_def.h.inc +++ b/target/s390x/cpu_features_def.h.inc @@ -114,6 +114,7 @@ DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH2, "vxpdeh2", STFL, 192, "Vector-Packed-Decima DEF_FEAT(BEAR_ENH, "beareh", STFL, 193, "BEAR-enhancement facility") DEF_FEAT(RDP, "rdp", STFL, 194, "Reset-DAT-protection facility") DEF_FEAT(PAI, "pai", STFL, 196, "Processor-Activity-Instrumentation facility") +DEF_FEAT(PAIE, "paie", STFL, 197, "Processor-Activity-Instrumentation extension-1") /* Features exposed via SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */ DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility") diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 1a562d2801..c3a4f80633 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -334,18 +334,31 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, static void s390_print_cpu_model_list_entry(gpointer data, gpointer user_data) { const S390CPUClass *scc = S390_CPU_CLASS((ObjectClass *)data); + CPUClass *cc = CPU_CLASS(scc); char *name = g_strdup(object_class_get_name((ObjectClass *)data)); - const char *details = ""; + g_autoptr(GString) details = g_string_new(""); if (scc->is_static) { - details = "(static, migration-safe)"; - } else if (scc->is_migration_safe) { - details = "(migration-safe)"; + g_string_append(details, "static, "); + } + if (scc->is_migration_safe) { + g_string_append(details, "migration-safe, "); + } + if (cc->deprecation_note) { + g_string_append(details, "deprecated, "); + } + if (details->len) { + /* cull trailing ', ' */ + g_string_truncate(details, details->len - 2); } /* strip off the -s390x-cpu */ g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0; - qemu_printf("s390 %-15s %-35s %s\n", name, scc->desc, details); + if (details->len) { + qemu_printf("s390 %-15s %-35s (%s)\n", name, scc->desc, details->str); + } else { + qemu_printf("s390 %-15s %-35s\n", name, scc->desc); + } g_free(name); } diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index ad140184b9..1e3b7c0dc9 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -575,6 +575,7 @@ static uint16_t full_GEN16_GA1[] = { S390_FEAT_BEAR_ENH, S390_FEAT_RDP, S390_FEAT_PAI, + S390_FEAT_PAIE, }; @@ -669,6 +670,7 @@ static uint16_t default_GEN16_GA1[] = { S390_FEAT_BEAR_ENH, S390_FEAT_RDP, S390_FEAT_PAI, + S390_FEAT_PAIE, }; /* QEMU (CPU model) features */ @@ -742,13 +744,20 @@ static uint16_t qemu_V7_0[] = { S390_FEAT_MISC_INSTRUCTION_EXT3, }; +static uint16_t qemu_V7_1[] = { + S390_FEAT_VECTOR_ENH2, +}; + /* * Features for the "qemu" CPU model of the latest QEMU machine and the "max" * CPU model under TCG. Don't include features that are not part of the full * feature set of the current "max" CPU model generation. */ static uint16_t qemu_MAX[] = { - S390_FEAT_VECTOR_ENH2, + S390_FEAT_MSA_EXT_5, + S390_FEAT_KIMD_SHA_512, + S390_FEAT_KLMD_SHA_512, + S390_FEAT_PRNO_TRNG, }; /****** END FEATURE DEFS ******/ @@ -871,6 +880,7 @@ static FeatGroupDefSpec QemuFeatDef[] = { QEMU_FEAT_INITIALIZER(V6_0), QEMU_FEAT_INITIALIZER(V6_2), QEMU_FEAT_INITIALIZER(V7_0), + QEMU_FEAT_INITIALIZER(V7_1), QEMU_FEAT_INITIALIZER(MAX), }; diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 7bd8db0e7b..6a8dbadf7e 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -157,6 +157,7 @@ static int cap_ri; static int cap_hpage_1m; static int cap_vcpu_resets; static int cap_protected; +static int cap_zpci_op; static bool mem_op_storage_key_support; @@ -362,6 +363,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ); cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS); cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED); + cap_zpci_op = kvm_check_extension(s, KVM_CAP_S390_ZPCI_OP); kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0); kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0); @@ -2574,3 +2576,8 @@ bool kvm_arch_cpu_check_are_resettable(void) { return true; } + +int kvm_s390_get_zpci_op(void) +{ + return cap_zpci_op; +} diff --git a/target/s390x/kvm/kvm_s390x.h b/target/s390x/kvm/kvm_s390x.h index 05a5e1e6f4..aaae8570de 100644 --- a/target/s390x/kvm/kvm_s390x.h +++ b/target/s390x/kvm/kvm_s390x.h @@ -27,6 +27,7 @@ void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); int kvm_s390_get_hpage_1m(void); int kvm_s390_get_ri(void); +int kvm_s390_get_zpci_op(void); int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock); int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock); int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock); diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h index 6aba7fd0ca..b5ae0ae364 100644 --- a/target/s390x/s390x-internal.h +++ b/target/s390x/s390x-internal.h @@ -227,7 +227,7 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, /* arch_dump.c */ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); + int cpuid, DumpState *s); /* cc_helper.c */ diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c index 138d9e7ad9..762b277884 100644 --- a/target/s390x/tcg/crypto_helper.c +++ b/target/s390x/tcg/crypto_helper.c @@ -1,10 +1,12 @@ /* * s390x crypto helpers * + * Copyright (C) 2022 Jason A. Donenfeld . All Rights Reserved. * Copyright (c) 2017 Red Hat Inc * * Authors: * David Hildenbrand + * Jason A. Donenfeld * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -12,12 +14,262 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" +#include "qemu/guest-random.h" #include "s390x-internal.h" #include "tcg_s390x.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" +static uint64_t R(uint64_t x, int c) +{ + return (x >> c) | (x << (64 - c)); +} +static uint64_t Ch(uint64_t x, uint64_t y, uint64_t z) +{ + return (x & y) ^ (~x & z); +} +static uint64_t Maj(uint64_t x, uint64_t y, uint64_t z) +{ + return (x & y) ^ (x & z) ^ (y & z); +} +static uint64_t Sigma0(uint64_t x) +{ + return R(x, 28) ^ R(x, 34) ^ R(x, 39); +} +static uint64_t Sigma1(uint64_t x) +{ + return R(x, 14) ^ R(x, 18) ^ R(x, 41); +} +static uint64_t sigma0(uint64_t x) +{ + return R(x, 1) ^ R(x, 8) ^ (x >> 7); +} +static uint64_t sigma1(uint64_t x) +{ + return R(x, 19) ^ R(x, 61) ^ (x >> 6); +} + +static const uint64_t K[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, + 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, + 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, + 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, + 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, + 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, + 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, + 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* a is icv/ocv, w is a single message block. w will get reused internally. */ +static void sha512_bda(uint64_t a[8], uint64_t w[16]) +{ + uint64_t t, z[8], b[8]; + int i, j; + + memcpy(z, a, sizeof(z)); + for (i = 0; i < 80; i++) { + memcpy(b, a, sizeof(b)); + + t = a[7] + Sigma1(a[4]) + Ch(a[4], a[5], a[6]) + K[i] + w[i % 16]; + b[7] = t + Sigma0(a[0]) + Maj(a[0], a[1], a[2]); + b[3] += t; + for (j = 0; j < 8; ++j) { + a[(j + 1) % 8] = b[j]; + } + if (i % 16 == 15) { + for (j = 0; j < 16; ++j) { + w[j] += w[(j + 9) % 16] + sigma0(w[(j + 1) % 16]) + + sigma1(w[(j + 14) % 16]); + } + } + } + + for (i = 0; i < 8; i++) { + a[i] += z[i]; + } +} + +/* a is icv/ocv, w is a single message block that needs be64 conversion. */ +static void sha512_bda_be64(uint64_t a[8], uint64_t w[16]) +{ + uint64_t t[16]; + int i; + + for (i = 0; i < 16; i++) { + t[i] = be64_to_cpu(w[i]); + } + sha512_bda(a, t); +} + +static void sha512_read_icv(CPUS390XState *env, uint64_t addr, + uint64_t a[8], uintptr_t ra) +{ + int i; + + for (i = 0; i < 8; i++, addr += 8) { + addr = wrap_address(env, addr); + a[i] = cpu_ldq_be_data_ra(env, addr, ra); + } +} + +static void sha512_write_ocv(CPUS390XState *env, uint64_t addr, + uint64_t a[8], uintptr_t ra) +{ + int i; + + for (i = 0; i < 8; i++, addr += 8) { + addr = wrap_address(env, addr); + cpu_stq_be_data_ra(env, addr, a[i], ra); + } +} + +static void sha512_read_block(CPUS390XState *env, uint64_t addr, + uint64_t a[16], uintptr_t ra) +{ + int i; + + for (i = 0; i < 16; i++, addr += 8) { + addr = wrap_address(env, addr); + a[i] = cpu_ldq_be_data_ra(env, addr, ra); + } +} + +static void sha512_read_mbl_be64(CPUS390XState *env, uint64_t addr, + uint8_t a[16], uintptr_t ra) +{ + int i; + + for (i = 0; i < 16; i++, addr += 1) { + addr = wrap_address(env, addr); + a[i] = cpu_ldub_data_ra(env, addr, ra); + } +} + +static int cpacf_sha512(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, + uint64_t *message_reg, uint64_t *len_reg, uint32_t type) +{ + enum { MAX_BLOCKS_PER_RUN = 64 }; /* Arbitrary: keep interactivity. */ + uint64_t len = *len_reg, a[8], processed = 0; + int i, message_reg_len = 64; + + g_assert(type == S390_FEAT_TYPE_KIMD || type == S390_FEAT_TYPE_KLMD); + + if (!(env->psw.mask & PSW_MASK_64)) { + len = (uint32_t)len; + message_reg_len = (env->psw.mask & PSW_MASK_32) ? 32 : 24; + } + + /* KIMD: length has to be properly aligned. */ + if (type == S390_FEAT_TYPE_KIMD && !QEMU_IS_ALIGNED(len, 128)) { + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); + } + + sha512_read_icv(env, param_addr, a, ra); + + /* Process full blocks first. */ + for (; len >= 128; len -= 128, processed += 128) { + uint64_t w[16]; + + if (processed >= MAX_BLOCKS_PER_RUN * 128) { + break; + } + + sha512_read_block(env, *message_reg + processed, w, ra); + sha512_bda(a, w); + } + + /* KLMD: Process partial/empty block last. */ + if (type == S390_FEAT_TYPE_KLMD && len < 128) { + uint8_t x[128]; + + /* Read the remainder of the message byte-per-byte. */ + for (i = 0; i < len; i++) { + uint64_t addr = wrap_address(env, *message_reg + processed + i); + + x[i] = cpu_ldub_data_ra(env, addr, ra); + } + /* Pad the remainder with zero and set the top bit. */ + memset(x + len, 0, 128 - len); + x[len] = 128; + + /* + * Place the MBL either into this block (if there is space left), + * or use an additional one. + */ + if (len < 112) { + sha512_read_mbl_be64(env, param_addr + 64, x + 112, ra); + } + sha512_bda_be64(a, (uint64_t *)x); + + if (len >= 112) { + memset(x, 0, 112); + sha512_read_mbl_be64(env, param_addr + 64, x + 112, ra); + sha512_bda_be64(a, (uint64_t *)x); + } + + processed += len; + len = 0; + } + + /* + * Modify memory after we read all inputs and modify registers only after + * writing memory succeeded. + * + * TODO: if writing fails halfway through (e.g., when crossing page + * boundaries), we're in trouble. We'd need something like access_prepare(). + */ + sha512_write_ocv(env, param_addr, a, ra); + *message_reg = deposit64(*message_reg, 0, message_reg_len, + *message_reg + processed); + *len_reg -= processed; + return !len ? 0 : 3; +} + +static void fill_buf_random(CPUS390XState *env, uintptr_t ra, + uint64_t *buf_reg, uint64_t *len_reg) +{ + uint8_t tmp[256]; + uint64_t len = *len_reg; + int buf_reg_len = 64; + + if (!(env->psw.mask & PSW_MASK_64)) { + len = (uint32_t)len; + buf_reg_len = (env->psw.mask & PSW_MASK_32) ? 32 : 24; + } + + while (len) { + size_t block = MIN(len, sizeof(tmp)); + + qemu_guest_getrandom_nofail(tmp, block); + for (size_t i = 0; i < block; ++i) { + cpu_stb_data_ra(env, wrap_address(env, *buf_reg), tmp[i], ra); + *buf_reg = deposit64(*buf_reg, 0, buf_reg_len, *buf_reg + 1); + --*len_reg; + } + len -= block; + } +} + uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, uint32_t type) { @@ -52,6 +304,13 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, cpu_stb_data_ra(env, param_addr, subfunc[i], ra); } break; + case 3: /* CPACF_*_SHA_512 */ + return cpacf_sha512(env, ra, env->regs[1], &env->regs[r2], + &env->regs[r2 + 1], type); + case 114: /* CPACF_PRNO_TRNG */ + fill_buf_random(env, ra, &env->regs[r1], &env->regs[r1 + 1]); + fill_buf_random(env, ra, &env->regs[r2], &env->regs[r2 + 1]); + break; default: /* we don't implement any other subfunction yet */ g_assert_not_reached(); diff --git a/target/s390x/tcg/insn-data.def b/target/s390x/tcg/insn-data.def index 5e448bb2c4..6382ceabfc 100644 --- a/target/s390x/tcg/insn-data.def +++ b/target/s390x/tcg/insn-data.def @@ -290,8 +290,8 @@ D(0xb961, CLGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1) D(0xeb23, CLT, RSY_b, MIE, r1_32u, m2_32u, 0, 0, ct, 0, 1) D(0xeb2b, CLGT, RSY_b, MIE, r1_o, m2_64, 0, 0, ct, 0, 1) - D(0xec73, CLFIT, RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1) - D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 1) + D(0xec73, CLFIT, RIE_a, GIE, r1_32u, i2_16u, 0, 0, ct, 0, 1) + D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_16u, 0, 0, ct, 0, 1) /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) @@ -466,7 +466,7 @@ C(0xe39f, LAT, RXY_a, LAT, 0, m2_32u, r1, 0, lat, 0) C(0xe385, LGAT, RXY_a, LAT, 0, a2, r1, 0, lgat, 0) /* LOAD AND ZERO RIGHTMOST BYTE */ - C(0xe3eb, LZRF, RXY_a, LZRB, 0, m2_32u, new, r1_32, lzrb, 0) + C(0xe33b, LZRF, RXY_a, LZRB, 0, m2_32u, new, r1_32, lzrb, 0) C(0xe32a, LZRG, RXY_a, LZRB, 0, m2_64, r1, 0, lzrb, 0) /* LOAD LOGICAL AND ZERO RIGHTMOST BYTE */ C(0xe33a, LLZRGF, RXY_a, LZRB, 0, m2_32u, r1, 0, lzrb, 0) diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index fc52aa128b..3758b9e688 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -148,10 +148,6 @@ static int s390_probe_access(CPUArchState *env, target_ulong addr, int size, #else int flags; - /* - * For !CONFIG_USER_ONLY, we cannot rely on TLB_INVALID_MASK or haddr==NULL - * to detect if there was an exception during tlb_fill(). - */ env->tlb_fill_exc = 0; flags = probe_access_flags(env, addr, access_type, mmu_idx, nonfault, phost, ra); diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index e2ee005671..1d2dddab1c 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -6609,6 +6609,14 @@ static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) dc->insn_start = tcg_last_op(); } +static target_ulong get_next_pc(CPUS390XState *env, DisasContext *s, + uint64_t pc) +{ + uint64_t insn = ld_code2(env, s, pc); + + return pc + get_ilen((insn >> 8) & 0xff); +} + static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { CPUS390XState *env = cs->env_ptr; @@ -6616,10 +6624,9 @@ static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) dc->base.is_jmp = translate_one(env, dc); if (dc->base.is_jmp == DISAS_NEXT) { - uint64_t page_start; - - page_start = dc->base.pc_first & TARGET_PAGE_MASK; - if (dc->base.pc_next - page_start >= TARGET_PAGE_SIZE || dc->ex_value) { + if (!is_same_page(dcbase, dc->base.pc_next) || + !is_same_page(dcbase, get_next_pc(env, dc, dc->base.pc_next)) || + dc->ex_value) { dc->base.is_jmp = DISAS_TOO_MANY; } } @@ -6676,11 +6683,12 @@ static const TranslatorOps s390x_tr_ops = { .disas_log = s390x_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc; - translator_loop(&s390x_tr_ops, &dc.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &s390x_tr_ops, &dc.base); } void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb, diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 06b2691dc4..56c50530da 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -34,13 +34,20 @@ static void superh_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.pc = value; } +static vaddr superh_cpu_get_pc(CPUState *cs) +{ + SuperHCPU *cpu = SUPERH_CPU(cs); + + return cpu->env.pc; +} + static void superh_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { SuperHCPU *cpu = SUPERH_CPU(cs); - cpu->env.pc = tb->pc; - cpu->env.flags = tb->flags & TB_FLAG_ENVFLAGS_MASK; + cpu->env.pc = tb_pc(tb); + cpu->env.flags = tb->flags; } #ifndef CONFIG_USER_ONLY @@ -50,10 +57,10 @@ static bool superh_io_recompile_replay_branch(CPUState *cs, SuperHCPU *cpu = SUPERH_CPU(cs); CPUSH4State *env = &cpu->env; - if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 - && env->pc != tb->pc) { + if ((env->flags & (TB_FLAG_DELAY_SLOT | TB_FLAG_DELAY_SLOT_COND)) + && env->pc != tb_pc(tb)) { env->pc -= 2; - env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); + env->flags &= ~(TB_FLAG_DELAY_SLOT | TB_FLAG_DELAY_SLOT_COND); return true; } return false; @@ -261,6 +268,7 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = superh_cpu_has_work; cc->dump_state = superh_cpu_dump_state; cc->set_pc = superh_cpu_set_pc; + cc->get_pc = superh_cpu_get_pc; cc->gdb_read_register = superh_cpu_gdb_read_register; cc->gdb_write_register = superh_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 9f15ef913c..727b829598 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -78,26 +78,33 @@ #define FPSCR_RM_NEAREST (0 << 0) #define FPSCR_RM_ZERO (1 << 0) -#define DELAY_SLOT_MASK 0x7 -#define DELAY_SLOT (1 << 0) -#define DELAY_SLOT_CONDITIONAL (1 << 1) -#define DELAY_SLOT_RTE (1 << 2) +#define TB_FLAG_DELAY_SLOT (1 << 0) +#define TB_FLAG_DELAY_SLOT_COND (1 << 1) +#define TB_FLAG_DELAY_SLOT_RTE (1 << 2) +#define TB_FLAG_PENDING_MOVCA (1 << 3) +#define TB_FLAG_GUSA_SHIFT 4 /* [11:4] */ +#define TB_FLAG_GUSA_EXCLUSIVE (1 << 12) +#define TB_FLAG_UNALIGN (1 << 13) +#define TB_FLAG_SR_FD (1 << SR_FD) /* 15 */ +#define TB_FLAG_FPSCR_PR FPSCR_PR /* 19 */ +#define TB_FLAG_FPSCR_SZ FPSCR_SZ /* 20 */ +#define TB_FLAG_FPSCR_FR FPSCR_FR /* 21 */ +#define TB_FLAG_SR_RB (1 << SR_RB) /* 29 */ +#define TB_FLAG_SR_MD (1 << SR_MD) /* 30 */ -#define TB_FLAG_PENDING_MOVCA (1 << 3) -#define TB_FLAG_UNALIGN (1 << 4) - -#define GUSA_SHIFT 4 -#ifdef CONFIG_USER_ONLY -#define GUSA_EXCLUSIVE (1 << 12) -#define GUSA_MASK ((0xff << GUSA_SHIFT) | GUSA_EXCLUSIVE) -#else -/* Provide dummy versions of the above to allow tests against tbflags - to be elided while avoiding ifdefs. */ -#define GUSA_EXCLUSIVE 0 -#define GUSA_MASK 0 -#endif - -#define TB_FLAG_ENVFLAGS_MASK (DELAY_SLOT_MASK | GUSA_MASK) +#define TB_FLAG_DELAY_SLOT_MASK (TB_FLAG_DELAY_SLOT | \ + TB_FLAG_DELAY_SLOT_COND | \ + TB_FLAG_DELAY_SLOT_RTE) +#define TB_FLAG_GUSA_MASK ((0xff << TB_FLAG_GUSA_SHIFT) | \ + TB_FLAG_GUSA_EXCLUSIVE) +#define TB_FLAG_FPSCR_MASK (TB_FLAG_FPSCR_PR | \ + TB_FLAG_FPSCR_SZ | \ + TB_FLAG_FPSCR_FR) +#define TB_FLAG_SR_MASK (TB_FLAG_SR_FD | \ + TB_FLAG_SR_RB | \ + TB_FLAG_SR_MD) +#define TB_FLAG_ENVFLAGS_MASK (TB_FLAG_DELAY_SLOT_MASK | \ + TB_FLAG_GUSA_MASK) typedef struct tlb_t { uint32_t vpn; /* virtual page number */ @@ -258,7 +265,7 @@ static inline int cpu_mmu_index (CPUSH4State *env, bool ifetch) { /* The instruction in a RTE delay slot is fetched in privileged mode, but executed in user mode. */ - if (ifetch && (env->flags & DELAY_SLOT_RTE)) { + if (ifetch && (env->flags & TB_FLAG_DELAY_SLOT_RTE)) { return 0; } else { return (env->sr & (1u << SR_MD)) == 0 ? 1 : 0; @@ -366,11 +373,10 @@ static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc, { *pc = env->pc; /* For a gUSA region, notice the end of the region. */ - *cs_base = env->flags & GUSA_MASK ? env->gregs[0] : 0; - *flags = env->flags /* TB_FLAG_ENVFLAGS_MASK: bits 0-2, 4-12 */ - | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */ - | (env->sr & ((1u << SR_MD) | (1u << SR_RB))) /* Bits 29-30 */ - | (env->sr & (1u << SR_FD)) /* Bit 15 */ + *cs_base = env->flags & TB_FLAG_GUSA_MASK ? env->gregs[0] : 0; + *flags = env->flags + | (env->fpscr & TB_FLAG_FPSCR_MASK) + | (env->sr & TB_FLAG_SR_MASK) | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 3 */ #ifdef CONFIG_USER_ONLY *flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; diff --git a/target/sh4/helper.c b/target/sh4/helper.c index 6a620e36fc..e02e7af607 100644 --- a/target/sh4/helper.c +++ b/target/sh4/helper.c @@ -147,11 +147,11 @@ void superh_cpu_do_interrupt(CPUState *cs) env->sr |= (1u << SR_BL) | (1u << SR_MD) | (1u << SR_RB); env->lock_addr = -1; - if (env->flags & DELAY_SLOT_MASK) { + if (env->flags & TB_FLAG_DELAY_SLOT_MASK) { /* Branch instruction should be executed again before delay slot. */ env->spc -= 2; /* Clear flags for exception/interrupt routine. */ - env->flags &= ~DELAY_SLOT_MASK; + env->flags &= ~TB_FLAG_DELAY_SLOT_MASK; } if (do_exp) { @@ -786,7 +786,7 @@ bool superh_cpu_exec_interrupt(CPUState *cs, int interrupt_request) CPUSH4State *env = &cpu->env; /* Delay slots are indivisible, ignore interrupts */ - if (env->flags & DELAY_SLOT_MASK) { + if (env->flags & TB_FLAG_DELAY_SLOT_MASK) { return false; } else { superh_cpu_do_interrupt(cs); diff --git a/target/sh4/translate.c b/target/sh4/translate.c index f1b190e7cf..26231b2a5a 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -175,13 +175,13 @@ void superh_cpu_dump_state(CPUState *cs, FILE *f, int flags) i, env->gregs[i], i + 1, env->gregs[i + 1], i + 2, env->gregs[i + 2], i + 3, env->gregs[i + 3]); } - if (env->flags & DELAY_SLOT) { + if (env->flags & TB_FLAG_DELAY_SLOT) { qemu_printf("in delay slot (delayed_pc=0x%08x)\n", env->delayed_pc); - } else if (env->flags & DELAY_SLOT_CONDITIONAL) { + } else if (env->flags & TB_FLAG_DELAY_SLOT_COND) { qemu_printf("in conditional delay slot (delayed_pc=0x%08x)\n", env->delayed_pc); - } else if (env->flags & DELAY_SLOT_RTE) { + } else if (env->flags & TB_FLAG_DELAY_SLOT_RTE) { qemu_fprintf(f, "in rte delay slot (delayed_pc=0x%08x)\n", env->delayed_pc); } @@ -223,7 +223,7 @@ static inline void gen_save_cpu_state(DisasContext *ctx, bool save_pc) static inline bool use_exit_tb(DisasContext *ctx) { - return (ctx->tbflags & GUSA_EXCLUSIVE) != 0; + return (ctx->tbflags & TB_FLAG_GUSA_EXCLUSIVE) != 0; } static bool use_goto_tb(DisasContext *ctx, target_ulong dest) @@ -276,12 +276,12 @@ static void gen_conditional_jump(DisasContext *ctx, target_ulong dest, TCGLabel *l1 = gen_new_label(); TCGCond cond_not_taken = jump_if_true ? TCG_COND_EQ : TCG_COND_NE; - if (ctx->tbflags & GUSA_EXCLUSIVE) { + if (ctx->tbflags & TB_FLAG_GUSA_EXCLUSIVE) { /* When in an exclusive region, we must continue to the end. Therefore, exit the region on a taken branch, but otherwise fall through to the next instruction. */ tcg_gen_brcondi_i32(cond_not_taken, cpu_sr_t, 0, l1); - tcg_gen_movi_i32(cpu_flags, ctx->envflags & ~GUSA_MASK); + tcg_gen_movi_i32(cpu_flags, ctx->envflags & ~TB_FLAG_GUSA_MASK); /* Note that this won't actually use a goto_tb opcode because we disallow it in use_goto_tb, but it handles exit + singlestep. */ gen_goto_tb(ctx, 0, dest); @@ -307,14 +307,14 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) tcg_gen_mov_i32(ds, cpu_delayed_cond); tcg_gen_discard_i32(cpu_delayed_cond); - if (ctx->tbflags & GUSA_EXCLUSIVE) { + if (ctx->tbflags & TB_FLAG_GUSA_EXCLUSIVE) { /* When in an exclusive region, we must continue to the end. Therefore, exit the region on a taken branch, but otherwise fall through to the next instruction. */ tcg_gen_brcondi_i32(TCG_COND_EQ, ds, 0, l1); /* Leave the gUSA region. */ - tcg_gen_movi_i32(cpu_flags, ctx->envflags & ~GUSA_MASK); + tcg_gen_movi_i32(cpu_flags, ctx->envflags & ~TB_FLAG_GUSA_MASK); gen_jump(ctx); gen_set_label(l1); @@ -361,8 +361,8 @@ static inline void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) #define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe)) #define CHECK_NOT_DELAY_SLOT \ - if (ctx->envflags & DELAY_SLOT_MASK) { \ - goto do_illegal_slot; \ + if (ctx->envflags & TB_FLAG_DELAY_SLOT_MASK) { \ + goto do_illegal_slot; \ } #define CHECK_PRIVILEGED \ @@ -436,7 +436,7 @@ static void _decode_opc(DisasContext * ctx) case 0x000b: /* rts */ CHECK_NOT_DELAY_SLOT tcg_gen_mov_i32(cpu_delayed_pc, cpu_pr); - ctx->envflags |= DELAY_SLOT; + ctx->envflags |= TB_FLAG_DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0028: /* clrmac */ @@ -458,7 +458,7 @@ static void _decode_opc(DisasContext * ctx) CHECK_NOT_DELAY_SLOT gen_write_sr(cpu_ssr); tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc); - ctx->envflags |= DELAY_SLOT_RTE; + ctx->envflags |= TB_FLAG_DELAY_SLOT_RTE; ctx->delayed_pc = (uint32_t) - 1; ctx->base.is_jmp = DISAS_STOP; return; @@ -513,12 +513,15 @@ static void _decode_opc(DisasContext * ctx) return; case 0xe000: /* mov #imm,Rn */ #ifdef CONFIG_USER_ONLY - /* Detect the start of a gUSA region. If so, update envflags - and end the TB. This will allow us to see the end of the - region (stored in R0) in the next TB. */ + /* + * Detect the start of a gUSA region (mov #-n, r15). + * If so, update envflags and end the TB. This will allow us + * to see the end of the region (stored in R0) in the next TB. + */ if (B11_8 == 15 && B7_0s < 0 && (tb_cflags(ctx->base.tb) & CF_PARALLEL)) { - ctx->envflags = deposit32(ctx->envflags, GUSA_SHIFT, 8, B7_0s); + ctx->envflags = + deposit32(ctx->envflags, TB_FLAG_GUSA_SHIFT, 8, B7_0s); ctx->base.is_jmp = DISAS_STOP; } #endif @@ -544,13 +547,13 @@ static void _decode_opc(DisasContext * ctx) case 0xa000: /* bra disp */ CHECK_NOT_DELAY_SLOT ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2; - ctx->envflags |= DELAY_SLOT; + ctx->envflags |= TB_FLAG_DELAY_SLOT; return; case 0xb000: /* bsr disp */ CHECK_NOT_DELAY_SLOT tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4); ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2; - ctx->envflags |= DELAY_SLOT; + ctx->envflags |= TB_FLAG_DELAY_SLOT; return; } @@ -1194,7 +1197,7 @@ static void _decode_opc(DisasContext * ctx) CHECK_NOT_DELAY_SLOT tcg_gen_xori_i32(cpu_delayed_cond, cpu_sr_t, 1); ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2; - ctx->envflags |= DELAY_SLOT_CONDITIONAL; + ctx->envflags |= TB_FLAG_DELAY_SLOT_COND; return; case 0x8900: /* bt label */ CHECK_NOT_DELAY_SLOT @@ -1204,7 +1207,7 @@ static void _decode_opc(DisasContext * ctx) CHECK_NOT_DELAY_SLOT tcg_gen_mov_i32(cpu_delayed_cond, cpu_sr_t); ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2; - ctx->envflags |= DELAY_SLOT_CONDITIONAL; + ctx->envflags |= TB_FLAG_DELAY_SLOT_COND; return; case 0x8800: /* cmp/eq #imm,R0 */ tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_sr_t, REG(0), B7_0s); @@ -1388,14 +1391,14 @@ static void _decode_opc(DisasContext * ctx) case 0x0023: /* braf Rn */ CHECK_NOT_DELAY_SLOT tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->base.pc_next + 4); - ctx->envflags |= DELAY_SLOT; + ctx->envflags |= TB_FLAG_DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0003: /* bsrf Rn */ CHECK_NOT_DELAY_SLOT tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4); tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr); - ctx->envflags |= DELAY_SLOT; + ctx->envflags |= TB_FLAG_DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x4015: /* cmp/pl Rn */ @@ -1411,14 +1414,14 @@ static void _decode_opc(DisasContext * ctx) case 0x402b: /* jmp @Rn */ CHECK_NOT_DELAY_SLOT tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8)); - ctx->envflags |= DELAY_SLOT; + ctx->envflags |= TB_FLAG_DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x400b: /* jsr @Rn */ CHECK_NOT_DELAY_SLOT tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4); tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8)); - ctx->envflags |= DELAY_SLOT; + ctx->envflags |= TB_FLAG_DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x400e: /* ldc Rm,SR */ @@ -1839,7 +1842,7 @@ static void _decode_opc(DisasContext * ctx) fflush(stderr); #endif do_illegal: - if (ctx->envflags & DELAY_SLOT_MASK) { + if (ctx->envflags & TB_FLAG_DELAY_SLOT_MASK) { do_illegal_slot: gen_save_cpu_state(ctx, true); gen_helper_raise_slot_illegal_instruction(cpu_env); @@ -1852,7 +1855,7 @@ static void _decode_opc(DisasContext * ctx) do_fpu_disabled: gen_save_cpu_state(ctx, true); - if (ctx->envflags & DELAY_SLOT_MASK) { + if (ctx->envflags & TB_FLAG_DELAY_SLOT_MASK) { gen_helper_raise_slot_fpu_disable(cpu_env); } else { gen_helper_raise_fpu_disable(cpu_env); @@ -1867,23 +1870,23 @@ static void decode_opc(DisasContext * ctx) _decode_opc(ctx); - if (old_flags & DELAY_SLOT_MASK) { + if (old_flags & TB_FLAG_DELAY_SLOT_MASK) { /* go out of the delay slot */ - ctx->envflags &= ~DELAY_SLOT_MASK; + ctx->envflags &= ~TB_FLAG_DELAY_SLOT_MASK; /* When in an exclusive region, we must continue to the end for conditional branches. */ - if (ctx->tbflags & GUSA_EXCLUSIVE - && old_flags & DELAY_SLOT_CONDITIONAL) { + if (ctx->tbflags & TB_FLAG_GUSA_EXCLUSIVE + && old_flags & TB_FLAG_DELAY_SLOT_COND) { gen_delayed_conditional_jump(ctx); return; } /* Otherwise this is probably an invalid gUSA region. Drop the GUSA bits so the next TB doesn't see them. */ - ctx->envflags &= ~GUSA_MASK; + ctx->envflags &= ~TB_FLAG_GUSA_MASK; tcg_gen_movi_i32(cpu_flags, ctx->envflags); - if (old_flags & DELAY_SLOT_CONDITIONAL) { + if (old_flags & TB_FLAG_DELAY_SLOT_COND) { gen_delayed_conditional_jump(ctx); } else { gen_jump(ctx); @@ -2223,7 +2226,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) } /* The entire region has been translated. */ - ctx->envflags &= ~GUSA_MASK; + ctx->envflags &= ~TB_FLAG_GUSA_MASK; ctx->base.pc_next = pc_end; ctx->base.num_insns += max_insns - 1; return; @@ -2234,7 +2237,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) /* Restart with the EXCLUSIVE bit set, within a TB run via cpu_exec_step_atomic holding the exclusive lock. */ - ctx->envflags |= GUSA_EXCLUSIVE; + ctx->envflags |= TB_FLAG_GUSA_EXCLUSIVE; gen_save_cpu_state(ctx, false); gen_helper_exclusive(cpu_env); ctx->base.is_jmp = DISAS_NORETURN; @@ -2267,17 +2270,19 @@ static void sh4_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) (tbflags & (1 << SR_RB))) * 0x10; ctx->fbank = tbflags & FPSCR_FR ? 0x10 : 0; - if (tbflags & GUSA_MASK) { +#ifdef CONFIG_USER_ONLY + if (tbflags & TB_FLAG_GUSA_MASK) { + /* In gUSA exclusive region. */ uint32_t pc = ctx->base.pc_next; uint32_t pc_end = ctx->base.tb->cs_base; - int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8); + int backup = sextract32(ctx->tbflags, TB_FLAG_GUSA_SHIFT, 8); int max_insns = (pc_end - pc) / 2; if (pc != pc_end + backup || max_insns < 2) { /* This is a malformed gUSA region. Don't do anything special, since the interpreter is likely to get confused. */ - ctx->envflags &= ~GUSA_MASK; - } else if (tbflags & GUSA_EXCLUSIVE) { + ctx->envflags &= ~TB_FLAG_GUSA_MASK; + } else if (tbflags & TB_FLAG_GUSA_EXCLUSIVE) { /* Regardless of single-stepping or the end of the page, we must complete execution of the gUSA region while holding the exclusive lock. */ @@ -2285,6 +2290,7 @@ static void sh4_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) return; } } +#endif /* Since the ISA is fixed-width, we can bound by the number of instructions remaining on the page. */ @@ -2309,8 +2315,8 @@ static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) DisasContext *ctx = container_of(dcbase, DisasContext, base); #ifdef CONFIG_USER_ONLY - if (unlikely(ctx->envflags & GUSA_MASK) - && !(ctx->envflags & GUSA_EXCLUSIVE)) { + if (unlikely(ctx->envflags & TB_FLAG_GUSA_MASK) + && !(ctx->envflags & TB_FLAG_GUSA_EXCLUSIVE)) { /* We're in an gUSA region, and we have not already fallen back on using an exclusive region. Attempt to parse the region into a single supported atomic operation. Failure @@ -2330,9 +2336,9 @@ static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); - if (ctx->tbflags & GUSA_EXCLUSIVE) { + if (ctx->tbflags & TB_FLAG_GUSA_EXCLUSIVE) { /* Ending the region of exclusivity. Clear the bits. */ - ctx->envflags &= ~GUSA_MASK; + ctx->envflags &= ~TB_FLAG_GUSA_MASK; } switch (ctx->base.is_jmp) { @@ -2368,11 +2374,12 @@ static const TranslatorOps sh4_tr_ops = { .disas_log = sh4_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&sh4_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &sh4_tr_ops, &ctx.base); } void restore_state_to_opc(CPUSH4State *env, TranslationBlock *tb, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 55268ed2a1..1f9ef7afd8 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -693,12 +693,19 @@ static void sparc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.npc = value + 4; } +static vaddr sparc_cpu_get_pc(CPUState *cs) +{ + SPARCCPU *cpu = SPARC_CPU(cs); + + return cpu->env.pc; +} + static void sparc_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { SPARCCPU *cpu = SPARC_CPU(cs); - cpu->env.pc = tb->pc; + cpu->env.pc = tb_pc(tb); cpu->env.npc = tb->cs_base; } @@ -896,6 +903,7 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) cc->memory_rw_debug = sparc_cpu_memory_rw_debug; #endif cc->set_pc = sparc_cpu_set_pc; + cc->get_pc = sparc_cpu_get_pc; cc->gdb_read_register = sparc_cpu_gdb_read_register; cc->gdb_write_register = sparc_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 2e28222d31..2cbbe2396a 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -5917,11 +5917,12 @@ static const TranslatorOps sparc_tr_ops = { .disas_log = sparc_tr_disas_log, }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc = {}; - translator_loop(&sparc_tr_ops, &dc.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, &sparc_tr_ops, &dc.base); } void sparc_tcg_init(void) diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index b95682b7f0..ab7a1e3a6d 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -41,13 +41,21 @@ static void tricore_cpu_set_pc(CPUState *cs, vaddr value) env->PC = value & ~(target_ulong)1; } +static vaddr tricore_cpu_get_pc(CPUState *cs) +{ + TriCoreCPU *cpu = TRICORE_CPU(cs); + CPUTriCoreState *env = &cpu->env; + + return env->PC; +} + static void tricore_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { TriCoreCPU *cpu = TRICORE_CPU(cs); CPUTriCoreState *env = &cpu->env; - env->PC = tb->pc; + env->PC = tb_pc(tb); } static void tricore_cpu_reset(DeviceState *dev) @@ -176,6 +184,7 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data) cc->dump_state = tricore_cpu_dump_state; cc->set_pc = tricore_cpu_set_pc; + cc->get_pc = tricore_cpu_get_pc; cc->sysemu_ops = &tricore_sysemu_ops; cc->tcg_ops = &tricore_tcg_ops; } diff --git a/target/tricore/translate.c b/target/tricore/translate.c index d170500fa5..a0558ead71 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -8878,10 +8878,12 @@ static const TranslatorOps tricore_tr_ops = { }; -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext ctx; - translator_loop(&tricore_tr_ops, &ctx.base, cs, tb, max_insns); + translator_loop(cs, tb, max_insns, pc, host_pc, + &tricore_tr_ops, &ctx.base); } void diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index fd553fdfb5..cbbe0e84a2 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -44,6 +44,13 @@ static void xtensa_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.pc = value; } +static vaddr xtensa_cpu_get_pc(CPUState *cs) +{ + XtensaCPU *cpu = XTENSA_CPU(cs); + + return cpu->env.pc; +} + static bool xtensa_cpu_has_work(CPUState *cs) { #ifndef CONFIG_USER_ONLY @@ -233,6 +240,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) cc->has_work = xtensa_cpu_has_work; cc->dump_state = xtensa_cpu_dump_state; cc->set_pc = xtensa_cpu_set_pc; + cc->get_pc = xtensa_cpu_get_pc; cc->gdb_read_register = xtensa_cpu_gdb_read_register; cc->gdb_write_register = xtensa_cpu_gdb_write_register; cc->gdb_stop_before_watchpoint = true; diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 70e11eeb45..bdd4690a5c 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1279,10 +1279,12 @@ static const TranslatorOps xtensa_translator_ops = { .disas_log = xtensa_tr_disas_log, }; -void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns, + target_ulong pc, void *host_pc) { DisasContext dc = {}; - translator_loop(&xtensa_translator_ops, &dc.base, cpu, tb, max_insns); + translator_loop(cpu, tb, max_insns, pc, host_pc, + &xtensa_translator_ops, &dc.base); } void xtensa_cpu_dump_state(CPUState *cs, FILE *f, int flags) @@ -2360,13 +2362,14 @@ static uint32_t test_exceptions_simcall(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { + bool is_semi = semihosting_enabled(dc->cring != 0); #ifdef CONFIG_USER_ONLY bool ill = true; #else /* Between RE.2 and RE.3 simcall opcode's become nop for the hardware. */ - bool ill = dc->config->hw_version <= 250002 && !semihosting_enabled(); + bool ill = dc->config->hw_version <= 250002 && !is_semi; #endif - if (ill || !semihosting_enabled()) { + if (ill || !is_semi) { qemu_log_mask(LOG_GUEST_ERROR, "SIMCALL but semihosting is disabled\n"); } return ill ? XTENSA_OP_ILL : 0; @@ -2376,7 +2379,7 @@ static void translate_simcall(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { #ifndef CONFIG_USER_ONLY - if (semihosting_enabled()) { + if (semihosting_enabled(dc->cring != 0)) { gen_helper_simcall(cpu_env); } #endif diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index d52206ba4d..cb04e4b3ad 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1652,7 +1652,7 @@ static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest) } else { /* rip-relative addressing into the constant pool. This is 6 + 8 = 14 bytes, as compared to using an - an immediate load 10 + 6 = 16 bytes, plus we may + immediate load 10 + 6 = 16 bytes, plus we may be able to re-use the pool constant for more calls. */ tcg_out_opc(s, OPC_GRP5, 0, 0, 0); tcg_out8(s, (call ? EXT5_CALLN_Ev : EXT5_JMPN_Ev) << 3 | 5); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 1cbd047ab3..e3dba47697 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1847,44 +1847,101 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0) tcg_out32(s, insn); } +static inline uint64_t make_pair(tcg_insn_unit i1, tcg_insn_unit i2) +{ + if (HOST_BIG_ENDIAN) { + return (uint64_t)i1 << 32 | i2; + } + return (uint64_t)i2 << 32 | i1; +} + +static inline void ppc64_replace2(uintptr_t rx, uintptr_t rw, + tcg_insn_unit i0, tcg_insn_unit i1) +{ +#if TCG_TARGET_REG_BITS == 64 + qatomic_set((uint64_t *)rw, make_pair(i0, i1)); + flush_idcache_range(rx, rw, 8); +#else + qemu_build_not_reached(); +#endif +} + +static inline void ppc64_replace4(uintptr_t rx, uintptr_t rw, + tcg_insn_unit i0, tcg_insn_unit i1, + tcg_insn_unit i2, tcg_insn_unit i3) +{ + uint64_t p[2]; + + p[!HOST_BIG_ENDIAN] = make_pair(i0, i1); + p[HOST_BIG_ENDIAN] = make_pair(i2, i3); + + /* + * There's no convenient way to get the compiler to allocate a pair + * of registers at an even index, so copy into r6/r7 and clobber. + */ + asm("mr %%r6, %1\n\t" + "mr %%r7, %2\n\t" + "stq %%r6, %0" + : "=Q"(*(__int128 *)rw) : "r"(p[0]), "r"(p[1]) : "r6", "r7"); + flush_idcache_range(rx, rw, 16); +} + void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, uintptr_t jmp_rw, uintptr_t addr) { - if (TCG_TARGET_REG_BITS == 64) { - tcg_insn_unit i1, i2; - intptr_t tb_diff = addr - tc_ptr; - intptr_t br_diff = addr - (jmp_rx + 4); - uint64_t pair; + tcg_insn_unit i0, i1, i2, i3; + intptr_t tb_diff = addr - tc_ptr; + intptr_t br_diff = addr - (jmp_rx + 4); + intptr_t lo, hi; - /* This does not exercise the range of the branch, but we do - still need to be able to load the new value of TCG_REG_TB. - But this does still happen quite often. */ - if (tb_diff == (int16_t)tb_diff) { - i1 = ADDI | TAI(TCG_REG_TB, TCG_REG_TB, tb_diff); - i2 = B | (br_diff & 0x3fffffc); - } else { - intptr_t lo = (int16_t)tb_diff; - intptr_t hi = (int32_t)(tb_diff - lo); - assert(tb_diff == hi + lo); - i1 = ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, hi >> 16); - i2 = ADDI | TAI(TCG_REG_TB, TCG_REG_TB, lo); - } -#if HOST_BIG_ENDIAN - pair = (uint64_t)i1 << 32 | i2; -#else - pair = (uint64_t)i2 << 32 | i1; -#endif - - /* As per the enclosing if, this is ppc64. Avoid the _Static_assert - within qatomic_set that would fail to build a ppc32 host. */ - qatomic_set__nocheck((uint64_t *)jmp_rw, pair); - flush_idcache_range(jmp_rx, jmp_rw, 8); - } else { + if (TCG_TARGET_REG_BITS == 32) { intptr_t diff = addr - jmp_rx; tcg_debug_assert(in_range_b(diff)); qatomic_set((uint32_t *)jmp_rw, B | (diff & 0x3fffffc)); flush_idcache_range(jmp_rx, jmp_rw, 4); + return; } + + /* + * For 16-bit displacements, we can use a single add + branch. + * This happens quite often. + */ + if (tb_diff == (int16_t)tb_diff) { + i0 = ADDI | TAI(TCG_REG_TB, TCG_REG_TB, tb_diff); + i1 = B | (br_diff & 0x3fffffc); + ppc64_replace2(jmp_rx, jmp_rw, i0, i1); + return; + } + + lo = (int16_t)tb_diff; + hi = (int32_t)(tb_diff - lo); + assert(tb_diff == hi + lo); + i0 = ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, hi >> 16); + i1 = ADDI | TAI(TCG_REG_TB, TCG_REG_TB, lo); + + /* + * Without stq from 2.07, we can only update two insns, + * and those must be the ones that load the target address. + */ + if (!have_isa_2_07) { + ppc64_replace2(jmp_rx, jmp_rw, i0, i1); + return; + } + + /* + * For 26-bit displacements, we can use a direct branch. + * Otherwise we still need the indirect branch, which we + * must restore after a potential direct branch write. + */ + br_diff -= 4; + if (in_range_b(br_diff)) { + i2 = B | (br_diff & 0x3fffffc); + i3 = NOP; + } else { + i2 = MTSPR | RS(TCG_REG_TB) | CTR; + i3 = BCCTR | BO_ALWAYS; + } + ppc64_replace4(jmp_rx, jmp_rw, i0, i1, i2, i3); } static void tcg_out_call_int(TCGContext *s, int lk, @@ -2574,8 +2631,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, if (s->tb_jmp_insn_offset) { /* Direct jump. */ if (TCG_TARGET_REG_BITS == 64) { - /* Ensure the next insns are 8-byte aligned. */ - if ((uintptr_t)s->code_ptr & 7) { + /* Ensure the next insns are 8 or 16-byte aligned. */ + while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) { tcg_out32(s, NOP); } s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s); diff --git a/tcg/tcg.c b/tcg/tcg.c index 7b68244ebc..8843e6a978 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -4198,7 +4198,7 @@ int64_t tcg_cpu_exec_time(void) #endif -int tcg_gen_code(TCGContext *s, TranslationBlock *tb) +int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) { #ifdef CONFIG_PROFILER TCGProfile *prof = &s->prof; @@ -4228,7 +4228,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) - && qemu_log_in_addr_range(tb->pc))) { + && qemu_log_in_addr_range(pc_start))) { FILE *logfile = qemu_log_trylock(); if (logfile) { fprintf(logfile, "OP:\n"); @@ -4275,7 +4275,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) if (s->nb_indirects > 0) { #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_IND) - && qemu_log_in_addr_range(tb->pc))) { + && qemu_log_in_addr_range(pc_start))) { FILE *logfile = qemu_log_trylock(); if (logfile) { fprintf(logfile, "OP before indirect lowering:\n"); @@ -4298,7 +4298,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) - && qemu_log_in_addr_range(tb->pc))) { + && qemu_log_in_addr_range(pc_start))) { FILE *logfile = qemu_log_trylock(); if (logfile) { fprintf(logfile, "OP after optimization and liveness analysis:\n"); diff --git a/tests/Makefile.include b/tests/Makefile.include index 3accb83b13..9422ddaece 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -36,12 +36,10 @@ export SRC_PATH SPEED = quick --include tests/tcg/Makefile.prereqs -tests/tcg/Makefile.prereqs: config-host.mak - # Per guest TCG tests BUILD_TCG_TARGET_RULES=$(patsubst %,build-tcg-tests-%, $(TCG_TESTS_TARGETS)) CLEAN_TCG_TARGET_RULES=$(patsubst %,clean-tcg-tests-%, $(TCG_TESTS_TARGETS)) +DISTCLEAN_TCG_TARGET_RULES=$(patsubst %,distclean-tcg-tests-%, $(TCG_TESTS_TARGETS)) RUN_TCG_TARGET_RULES=$(patsubst %,run-tcg-tests-%, $(TCG_TESTS_TARGETS)) $(foreach TARGET,$(TCG_TESTS_TARGETS), \ @@ -50,23 +48,25 @@ $(foreach TARGET,$(TCG_TESTS_TARGETS), \ .PHONY: $(TCG_TESTS_TARGETS:%=build-tcg-tests-%) $(TCG_TESTS_TARGETS:%=build-tcg-tests-%): build-tcg-tests-%: $(BUILD_DIR)/tests/tcg/config-%.mak $(call quiet-command, \ - $(MAKE) -C tests/tcg/$* -f ../Makefile.target $(SUBDIR_MAKEFLAGS) \ - DOCKER_SCRIPT="$(DOCKER_SCRIPT)" \ - TARGET="$*" SRC_PATH="$(SRC_PATH)", \ + $(MAKE) -C tests/tcg/$* $(SUBDIR_MAKEFLAGS), \ "BUILD","$* guest-tests") .PHONY: $(TCG_TESTS_TARGETS:%=run-tcg-tests-%) $(TCG_TESTS_TARGETS:%=run-tcg-tests-%): run-tcg-tests-%: build-tcg-tests-% $(call quiet-command, \ - $(MAKE) -C tests/tcg/$* -f ../Makefile.target $(SUBDIR_MAKEFLAGS) \ - TARGET="$*" SRC_PATH="$(SRC_PATH)" SPEED=$(SPEED) run, \ + $(MAKE) -C tests/tcg/$* $(SUBDIR_MAKEFLAGS) SPEED=$(SPEED) run, \ "RUN", "$* guest-tests") .PHONY: $(TCG_TESTS_TARGETS:%=clean-tcg-tests-%) $(TCG_TESTS_TARGETS:%=clean-tcg-tests-%): clean-tcg-tests-%: $(call quiet-command, \ - $(MAKE) -C tests/tcg/$* -f ../Makefile.target $(SUBDIR_MAKEFLAGS) \ - TARGET="$*" SRC_PATH="$(SRC_PATH)" clean, \ + $(MAKE) -C tests/tcg/$* $(SUBDIR_MAKEFLAGS) clean, \ + "CLEAN", "$* guest-tests") + +.PHONY: $(TCG_TESTS_TARGETS:%=distclean-tcg-tests-%) +$(TCG_TESTS_TARGETS:%=distclean-tcg-tests-%): distclean-tcg-tests-%: + $(call quiet-command, \ + $(MAKE) -C tests/tcg/$* $(SUBDIR_MAKEFLAGS) distclean, \ "CLEAN", "$* guest-tests") .PHONY: build-tcg @@ -79,6 +79,9 @@ check-tcg: $(RUN_TCG_TARGET_RULES) .PHONY: clean-tcg clean-tcg: $(CLEAN_TCG_TARGET_RULES) +.PHONY: distclean-tcg +distclean-tcg: $(DISTCLEAN_TCG_TARGET_RULES) + # Python venv for running tests .PHONY: check-venv check-avocado check-acceptance check-acceptance-deprecated-warning @@ -163,5 +166,6 @@ check-clean: rm -rf $(TESTS_VENV_DIR) $(TESTS_RESULTS_DIR) clean: check-clean clean-tcg +distclean: distclean-tcg endif diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index ed4853c805..910f3ba1ea 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -227,6 +227,10 @@ def exec_command_and_wait_for_pattern(test, command, _console_interaction(test, success_message, failure_message, command + '\r') class QemuBaseTest(avocado.Test): + + # default timeout for all tests, can be overridden + timeout = 120 + def _get_unique_tag_val(self, tag_name): """ Gets a tag value, if unique for a key @@ -295,6 +299,12 @@ class QemuSystemTest(QemuBaseTest): self.cancel("%s accelerator does not seem to be " "available" % accelerator) + def require_netdev(self, netdevname): + netdevhelp = run_cmd([self.qemu_bin, + '-M', 'none', '-netdev', 'help'])[0]; + if netdevhelp.find('\n' + netdevname + '\n') < 0: + self.cancel('no support for user networking') + def _new_vm(self, name, *args): self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_") vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, @@ -508,11 +518,10 @@ class LinuxDistro: class LinuxTest(LinuxSSHMixIn, QemuSystemTest): """Facilitates having a cloud-image Linux based available. - For tests that indent to interact with guests, this is a better choice + For tests that intend to interact with guests, this is a better choice to start with than the more vanilla `QemuSystemTest` class. """ - timeout = 900 distro = None username = 'root' password = 'password' @@ -547,6 +556,7 @@ class LinuxTest(LinuxSSHMixIn, QemuSystemTest): def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'): super().setUp() + self.require_netdev('user') self._set_distro() self.vm.add_args('-smp', self.smp) self.vm.add_args('-m', self.memory) diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py index ee584d2fdf..b7522ad3a1 100644 --- a/tests/avocado/boot_linux.py +++ b/tests/avocado/boot_linux.py @@ -63,6 +63,7 @@ class BootLinuxAarch64(LinuxTest): :avocado: tags=machine:virt :avocado: tags=machine:gic-version=2 """ + timeout = 240 def add_common_args(self): self.vm.add_args('-bios', @@ -114,6 +115,8 @@ class BootLinuxPPC64(LinuxTest): :avocado: tags=arch:ppc64 """ + timeout = 180 + def test_pseries_tcg(self): """ :avocado: tags=machine:pseries @@ -129,6 +132,8 @@ class BootLinuxS390X(LinuxTest): :avocado: tags=arch:s390x """ + timeout = 240 + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_s390_ccw_virtio_tcg(self): """ diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index 6b1533c17c..f26e036ab5 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -335,13 +335,13 @@ class BootLinuxConsole(LinuxKernelTest): """ images_url = ('http://ports.ubuntu.com/ubuntu-ports/dists/' 'bionic-updates/main/installer-arm64/' - '20101020ubuntu543.15/images/') + '20101020ubuntu543.19/images/') kernel_url = images_url + 'netboot/ubuntu-installer/arm64/linux' - kernel_hash = '5bfc54cf7ed8157d93f6e5b0241e727b6dc22c50' + kernel_hash = 'e167757620640eb26de0972f578741924abb3a82' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) initrd_url = images_url + 'netboot/ubuntu-installer/arm64/initrd.gz' - initrd_hash = 'd385d3e88d53e2004c5d43cbe668b458a094f772' + initrd_hash = 'cab5cb3fcefca8408aa5aae57f24574bfce8bdb9' initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash) self.vm.set_console() diff --git a/tests/avocado/info_usernet.py b/tests/avocado/info_usernet.py index dc01f74150..b862a47dba 100644 --- a/tests/avocado/info_usernet.py +++ b/tests/avocado/info_usernet.py @@ -16,6 +16,7 @@ from qemu.utils import get_info_usernet_hostfwd_port class InfoUsernet(QemuSystemTest): def test_hostfwd(self): + self.require_netdev('user') self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22') self.vm.launch() res = self.vm.command('human-monitor-command', diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py index b4e35a3d07..0f64eb636c 100644 --- a/tests/avocado/machine_aspeed.py +++ b/tests/avocado/machine_aspeed.py @@ -6,12 +6,14 @@ # later. See the COPYING file in the top-level directory. import time +import os from avocado_qemu import QemuSystemTest from avocado_qemu import wait_for_console_pattern from avocado_qemu import exec_command from avocado_qemu import exec_command_and_wait_for_pattern from avocado.utils import archive +from avocado import skipIf class AST1030Machine(QemuSystemTest): @@ -40,6 +42,8 @@ class AST1030Machine(QemuSystemTest): class AST2x00Machine(QemuSystemTest): + timeout = 90 + def wait_for_console_pattern(self, success_message, vm=None): wait_for_console_pattern(self, success_message, failure_message='Kernel panic - not syncing', @@ -99,7 +103,9 @@ class AST2x00Machine(QemuSystemTest): self.wait_for_console_pattern('Starting kernel ...') self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id) self.wait_for_console_pattern('lease of 10.0.2.15') + # the line before login: self.wait_for_console_pattern('Aspeed EVB') + time.sleep(0.1) exec_command(self, 'root') time.sleep(0.1) @@ -172,6 +178,20 @@ class AST2x00Machine(QemuSystemTest): self.do_test_arm_aspeed_buidroot_poweroff() +class AST2x00MachineSDK(QemuSystemTest): + + # FIXME: Although these tests boot a whole distro they are still + # slower than comparable machine models. There may be some + # optimisations which bring down the runtime. In the meantime they + # have generous timeouts and are disable for CI which aims for all + # tests to run in less than 60 seconds. + timeout = 240 + + def wait_for_console_pattern(self, success_message, vm=None): + wait_for_console_pattern(self, success_message, + failure_message='Kernel panic - not syncing', + vm=vm) + def do_test_arm_aspeed_sdk_start(self, image, cpu_id): self.vm.set_console() self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', @@ -183,6 +203,7 @@ class AST2x00Machine(QemuSystemTest): self.wait_for_console_pattern('Starting kernel ...') self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id) + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_arm_ast2500_evb_sdk(self): """ :avocado: tags=arch:arm @@ -200,6 +221,7 @@ class AST2x00Machine(QemuSystemTest): self.workdir + '/ast2500-default/image-bmc', '0x0') self.wait_for_console_pattern('ast2500-default login:') + @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') def test_arm_ast2600_evb_sdk(self): """ :avocado: tags=arch:arm diff --git a/tests/avocado/machine_s390_ccw_virtio.py b/tests/avocado/machine_s390_ccw_virtio.py index 438a6f4321..78152f2ad1 100644 --- a/tests/avocado/machine_s390_ccw_virtio.py +++ b/tests/avocado/machine_s390_ccw_virtio.py @@ -66,6 +66,7 @@ class S390CCWVirtioMachine(QemuSystemTest): '-kernel', kernel_path, '-initrd', initrd_path, '-append', kernel_command_line, + '-cpu', 'max,prno-trng=off', '-device', 'virtio-net-ccw,devno=fe.1.1111', '-device', 'virtio-rng-ccw,devno=fe.2.0000,max_revision=0,id=rn1', diff --git a/tests/avocado/migration.py b/tests/avocado/migration.py index 584d6ef53f..4b25680c50 100644 --- a/tests/avocado/migration.py +++ b/tests/avocado/migration.py @@ -14,7 +14,7 @@ import tempfile from avocado_qemu import QemuSystemTest from avocado import skipUnless -from avocado.utils import network +from avocado.utils.network import ports from avocado.utils import wait from avocado.utils.path import find_command @@ -57,7 +57,7 @@ class Migration(QemuSystemTest): self.assert_migration(source_vm, dest_vm) def _get_free_port(self): - port = network.find_free_port() + port = ports.find_free_port() if port is None: self.cancel('Failed to find a free port') return port diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py index 40e4f6908e..a76dd507fc 100644 --- a/tests/avocado/replay_linux.py +++ b/tests/avocado/replay_linux.py @@ -55,6 +55,7 @@ class ReplayLinux(LinuxTest): '%s,drive=disk%s-rr%s' % (device, id, bus_string)) def launch_and_wait(self, record, args, shift): + self.require_netdev('user') vm = self.get_vm() vm.add_args('-smp', '1') vm.add_args('-m', '1024') @@ -189,3 +190,4 @@ class ReplayLinuxAarch64(ReplayLinux): self.run_rr(shift=3, args=(*self.get_common_args(), + "-machine", "virt,gic-version=3")) diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index e80bef3031..da2a3e5c05 100644 Binary files a/tests/data/acpi/pc/DSDT and b/tests/data/acpi/pc/DSDT differ diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst index d5a2ca5165..abcd6d9d30 100644 Binary files a/tests/data/acpi/pc/DSDT.acpierst and b/tests/data/acpi/pc/DSDT.acpierst differ diff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat index f86c743c4d..884d4871a2 100644 Binary files a/tests/data/acpi/pc/DSDT.acpihmat and b/tests/data/acpi/pc/DSDT.acpihmat differ diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge index 14ed0d995a..31a79aa476 100644 Binary files a/tests/data/acpi/pc/DSDT.bridge and b/tests/data/acpi/pc/DSDT.bridge differ diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp index c653302a84..8b0cae4dbf 100644 Binary files a/tests/data/acpi/pc/DSDT.cphp and b/tests/data/acpi/pc/DSDT.cphp differ diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm index 247a1796b1..38865fb667 100644 Binary files a/tests/data/acpi/pc/DSDT.dimmpxm and b/tests/data/acpi/pc/DSDT.dimmpxm differ diff --git a/tests/data/acpi/pc/DSDT.hpbridge b/tests/data/acpi/pc/DSDT.hpbridge index d5a2ca5165..abcd6d9d30 100644 Binary files a/tests/data/acpi/pc/DSDT.hpbridge and b/tests/data/acpi/pc/DSDT.hpbridge differ diff --git a/tests/data/acpi/pc/DSDT.hpbrroot b/tests/data/acpi/pc/DSDT.hpbrroot index ec99b16229..dd2c8c0c8c 100644 Binary files a/tests/data/acpi/pc/DSDT.hpbrroot and b/tests/data/acpi/pc/DSDT.hpbrroot differ diff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs index f0d9e75841..e819ce6946 100644 Binary files a/tests/data/acpi/pc/DSDT.ipmikcs and b/tests/data/acpi/pc/DSDT.ipmikcs differ diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp index d0a7c46209..03a9decdc1 100644 Binary files a/tests/data/acpi/pc/DSDT.memhp and b/tests/data/acpi/pc/DSDT.memhp differ diff --git a/tests/data/acpi/pc/DSDT.nohpet b/tests/data/acpi/pc/DSDT.nohpet index cb7bf7d850..b413d9f31d 100644 Binary files a/tests/data/acpi/pc/DSDT.nohpet and b/tests/data/acpi/pc/DSDT.nohpet differ diff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem index 2f512cfbe1..9e701b2983 100644 Binary files a/tests/data/acpi/pc/DSDT.numamem and b/tests/data/acpi/pc/DSDT.numamem differ diff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp index 46e03d39e0..8c3956c9ec 100644 Binary files a/tests/data/acpi/pc/DSDT.roothp and b/tests/data/acpi/pc/DSDT.roothp differ diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT index 2cd8d5fc47..3870958969 100644 Binary files a/tests/data/acpi/q35/DSDT and b/tests/data/acpi/q35/DSDT differ diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst index 0bc5de8065..c9c18fa4e4 100644 Binary files a/tests/data/acpi/q35/DSDT.acpierst and b/tests/data/acpi/q35/DSDT.acpierst differ diff --git a/tests/data/acpi/q35/DSDT.acpihmat b/tests/data/acpi/q35/DSDT.acpihmat index af10345e88..a32e90b5d9 100644 Binary files a/tests/data/acpi/q35/DSDT.acpihmat and b/tests/data/acpi/q35/DSDT.acpihmat differ diff --git a/tests/data/acpi/q35/DSDT.applesmc b/tests/data/acpi/q35/DSDT.applesmc index 00092aacc6..5507b6b8f5 100644 Binary files a/tests/data/acpi/q35/DSDT.applesmc and b/tests/data/acpi/q35/DSDT.applesmc differ diff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge index d820098355..a42eb674fa 100644 Binary files a/tests/data/acpi/q35/DSDT.bridge and b/tests/data/acpi/q35/DSDT.bridge differ diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp index ac8456a43d..2d8cb603c9 100644 Binary files a/tests/data/acpi/q35/DSDT.cphp and b/tests/data/acpi/q35/DSDT.cphp differ diff --git a/tests/data/acpi/q35/DSDT.cxl b/tests/data/acpi/q35/DSDT.cxl index 369ae90196..20d0fb64ea 100644 Binary files a/tests/data/acpi/q35/DSDT.cxl and b/tests/data/acpi/q35/DSDT.cxl differ diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm index bb0eadf869..b23339513a 100644 Binary files a/tests/data/acpi/q35/DSDT.dimmpxm and b/tests/data/acpi/q35/DSDT.dimmpxm differ diff --git a/tests/data/acpi/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt index bb25827950..8af2695ede 100644 Binary files a/tests/data/acpi/q35/DSDT.ipmibt and b/tests/data/acpi/q35/DSDT.ipmibt differ diff --git a/tests/data/acpi/q35/DSDT.ipmismbus b/tests/data/acpi/q35/DSDT.ipmismbus index 15000c357f..479df48cd3 100644 Binary files a/tests/data/acpi/q35/DSDT.ipmismbus and b/tests/data/acpi/q35/DSDT.ipmismbus differ diff --git a/tests/data/acpi/q35/DSDT.ivrs b/tests/data/acpi/q35/DSDT.ivrs index 0bc5de8065..c9c18fa4e4 100644 Binary files a/tests/data/acpi/q35/DSDT.ivrs and b/tests/data/acpi/q35/DSDT.ivrs differ diff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp index 663456fc0d..a5730b8ab8 100644 Binary files a/tests/data/acpi/q35/DSDT.memhp and b/tests/data/acpi/q35/DSDT.memhp differ diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64 index 91afd01d59..a4293c20fe 100644 Binary files a/tests/data/acpi/q35/DSDT.mmio64 and b/tests/data/acpi/q35/DSDT.mmio64 differ diff --git a/tests/data/acpi/q35/DSDT.multi-bridge b/tests/data/acpi/q35/DSDT.multi-bridge index afde339a18..88bf47ab18 100644 Binary files a/tests/data/acpi/q35/DSDT.multi-bridge and b/tests/data/acpi/q35/DSDT.multi-bridge differ diff --git a/tests/data/acpi/q35/DSDT.nohpet b/tests/data/acpi/q35/DSDT.nohpet index 0fb09121cf..6feed2ee10 100644 Binary files a/tests/data/acpi/q35/DSDT.nohpet and b/tests/data/acpi/q35/DSDT.nohpet differ diff --git a/tests/data/acpi/q35/DSDT.numamem b/tests/data/acpi/q35/DSDT.numamem index e537669949..414b8af67b 100644 Binary files a/tests/data/acpi/q35/DSDT.numamem and b/tests/data/acpi/q35/DSDT.numamem differ diff --git a/tests/data/acpi/q35/DSDT.pvpanic-isa b/tests/data/acpi/q35/DSDT.pvpanic-isa index cc545b5d25..7277a01050 100644 Binary files a/tests/data/acpi/q35/DSDT.pvpanic-isa and b/tests/data/acpi/q35/DSDT.pvpanic-isa differ diff --git a/tests/data/acpi/q35/DSDT.tis.tpm12 b/tests/data/acpi/q35/DSDT.tis.tpm12 index a97d884c50..253a66e658 100644 Binary files a/tests/data/acpi/q35/DSDT.tis.tpm12 and b/tests/data/acpi/q35/DSDT.tis.tpm12 differ diff --git a/tests/data/acpi/q35/DSDT.tis.tpm2 b/tests/data/acpi/q35/DSDT.tis.tpm2 index 1f5392919b..76bd4661e6 100644 Binary files a/tests/data/acpi/q35/DSDT.tis.tpm2 and b/tests/data/acpi/q35/DSDT.tis.tpm2 differ diff --git a/tests/data/acpi/q35/DSDT.viot b/tests/data/acpi/q35/DSDT.viot index e20e4ee5e9..3f14b57f07 100644 Binary files a/tests/data/acpi/q35/DSDT.viot and b/tests/data/acpi/q35/DSDT.viot differ diff --git a/tests/data/acpi/q35/DSDT.xapic b/tests/data/acpi/q35/DSDT.xapic index 3cab5956ee..baa88f6f21 100644 Binary files a/tests/data/acpi/q35/DSDT.xapic and b/tests/data/acpi/q35/DSDT.xapic differ diff --git a/tests/data/acpi/virt/GTDT b/tests/data/acpi/virt/GTDT index 9408b71b59..6f8cb9b8f3 100644 Binary files a/tests/data/acpi/virt/GTDT and b/tests/data/acpi/virt/GTDT differ diff --git a/tests/data/acpi/virt/GTDT.memhp b/tests/data/acpi/virt/GTDT.memhp index 9408b71b59..6f8cb9b8f3 100644 Binary files a/tests/data/acpi/virt/GTDT.memhp and b/tests/data/acpi/virt/GTDT.memhp differ diff --git a/tests/data/acpi/virt/GTDT.numamem b/tests/data/acpi/virt/GTDT.numamem index 9408b71b59..6f8cb9b8f3 100644 Binary files a/tests/data/acpi/virt/GTDT.numamem and b/tests/data/acpi/virt/GTDT.numamem differ diff --git a/tests/data/test-qga-config b/tests/data/test-qga-config index 4bb721a4a1..b6b7bc9dfd 100644 --- a/tests/data/test-qga-config +++ b/tests/data/test-qga-config @@ -5,4 +5,4 @@ path=/path/to/org.qemu.guest_agent.0 pidfile=/var/foo/qemu-ga.pid statedir=/var/state verbose=true -blacklist=guest-ping;guest-get-time +block-rpcs=guest-ping;guest-get-time diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 9a45e8890b..c87f14477a 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -14,7 +14,7 @@ DOCKER_DEFAULT_REGISTRY := registry.gitlab.com/qemu-project/qemu endif DOCKER_REGISTRY := $(if $(REGISTRY),$(REGISTRY),$(DOCKER_DEFAULT_REGISTRY)) -ENGINE := auto +ENGINE ?= auto DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(ENGINE) CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$) @@ -69,40 +69,24 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker { echo "You will need to build $(EXECUTABLE)"; exit 1;},\ "CHECK", "debian-$* exists")) -# Enforce dependencies for composite images -# we don't run tests on intermediate images (used as base by another image) -DOCKER_PARTIAL_IMAGES := debian10 debian11 +# Special case cross-compiling x86_64 on non-x86_64 systems. ifeq ($(HOST_ARCH),x86_64) -docker-image-debian-amd64: docker-image-debian10 DOCKER_PARTIAL_IMAGES += debian-amd64-cross else -docker-image-debian-amd64-cross: docker-image-debian10 DOCKER_PARTIAL_IMAGES += debian-amd64 endif # For non-x86 hosts not all cross-compilers have been packaged ifneq ($(HOST_ARCH),x86_64) -DOCKER_PARTIAL_IMAGES += debian-mips-cross debian-mipsel-cross debian-mips64el-cross +DOCKER_PARTIAL_IMAGES += debian-mipsel-cross debian-mips64el-cross DOCKER_PARTIAL_IMAGES += debian-ppc64el-cross DOCKER_PARTIAL_IMAGES += debian-s390x-cross DOCKER_PARTIAL_IMAGES += fedora endif -docker-image-debian-alpha-cross: docker-image-debian10 -docker-image-debian-hppa-cross: docker-image-debian10 -docker-image-debian-m68k-cross: docker-image-debian10 -docker-image-debian-mips-cross: docker-image-debian10 -docker-image-debian-mips64-cross: docker-image-debian10 -docker-image-debian-sh4-cross: docker-image-debian10 -docker-image-debian-sparc64-cross: docker-image-debian10 - # The native build should never use the registry docker-image-debian-native: DOCKER_REGISTRY= -# base images should not add a local user -docker-image-debian10: NOUSER=1 -docker-image-debian11: NOUSER=1 - # alpine has no adduser docker-image-alpine: NOUSER=1 @@ -137,15 +121,6 @@ docker-image-debian-nios2-cross: $(DOCKER_FILES_DIR)/debian-toolchain.docker \ $(DOCKER_FILES_DIR)/debian-nios2-cross.d/build-toolchain.sh $(call debian-toolchain, $@) -# Specialist build images, sometimes very limited tools -docker-image-debian-tricore-cross: docker-image-debian10 -docker-image-debian-all-test-cross: docker-image-debian10 -docker-image-debian-loongarch-cross: docker-image-debian11 -docker-image-debian-microblaze-cross: docker-image-debian10 -docker-image-debian-nios2-cross: docker-image-debian10 -docker-image-debian-powerpc-test-cross: docker-image-debian11 -docker-image-debian-riscv64-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-powerpc-test-cross @@ -153,6 +128,7 @@ DOCKER_PARTIAL_IMAGES += debian-hppa-cross DOCKER_PARTIAL_IMAGES += debian-loongarch-cross DOCKER_PARTIAL_IMAGES += debian-m68k-cross debian-mips64-cross DOCKER_PARTIAL_IMAGES += debian-microblaze-cross +DOCKER_PARTIAL_IMAGES += debian-mips-cross DOCKER_PARTIAL_IMAGES += debian-nios2-cross DOCKER_PARTIAL_IMAGES += debian-riscv64-test-cross DOCKER_PARTIAL_IMAGES += debian-sh4-cross debian-sparc64-cross diff --git a/tests/docker/docker.py b/tests/docker/docker.py index d0af2861b8..3a1ed7cb18 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -205,22 +205,17 @@ def _read_qemu_dockerfile(img_name): return _read_dockerfile(df) -def _dockerfile_preprocess(df): - out = "" +def _dockerfile_verify_flat(df): + "Verify we do not include other qemu/ layers" for l in df.splitlines(): if len(l.strip()) == 0 or l.startswith("#"): continue from_pref = "FROM qemu/" if l.startswith(from_pref): - # TODO: Alternatively we could replace this line with "FROM $ID" - # where $ID is the image's hex id obtained with - # $ docker images $IMAGE --format="{{.Id}}" - # but unfortunately that's not supported by RHEL 7. - inlining = _read_qemu_dockerfile(l[len(from_pref):]) - out += _dockerfile_preprocess(inlining) - continue - out += l + "\n" - return out + print("We no longer support multiple QEMU layers.") + print("Dockerfiles should be flat, ideally created by lcitool") + return False + return True class Docker(object): @@ -309,23 +304,10 @@ class Docker(object): if argv is None: argv = [] - # pre-calculate the docker checksum before any - # substitutions we make for caching - checksum = _text_checksum(_dockerfile_preprocess(dockerfile)) + if not _dockerfile_verify_flat(dockerfile): + return -1 - if registry is not None: - sources = re.findall("FROM qemu\/(.*)", dockerfile) - # Fetch any cache layers we can, may fail - for s in sources: - pull_args = ["pull", "%s/qemu/%s" % (registry, s)] - if self._do(pull_args, quiet=quiet) != 0: - registry = None - break - # Make substitutions - if registry is not None: - dockerfile = dockerfile.replace("FROM qemu/", - "FROM %s/qemu/" % - (registry)) + checksum = _text_checksum(dockerfile) tmp_df = tempfile.NamedTemporaryFile(mode="w+t", encoding='utf-8', @@ -371,7 +353,7 @@ class Docker(object): checksum = self.get_image_dockerfile_checksum(tag) except Exception: return False - return checksum == _text_checksum(_dockerfile_preprocess(dockerfile)) + return checksum == _text_checksum(dockerfile) def run(self, cmd, keep, quiet, as_user=False): label = uuid.uuid4().hex diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index 3f4c0f95cb..9b7541261a 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -1,10 +1,10 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all alpine-edge qemu +# $ lcitool dockerfile --layers all alpine-316 qemu # # https://gitlab.com/libvirt/libvirt-ci -FROM docker.io/library/alpine:edge +FROM docker.io/library/alpine:3.16 RUN apk update && \ apk upgrade && \ @@ -13,6 +13,7 @@ RUN apk update && \ attr-dev \ bash \ bc \ + bison \ bzip2 \ bzip2-dev \ ca-certificates \ @@ -21,6 +22,7 @@ RUN apk update && \ cdrkit \ ceph-dev \ clang \ + cmocka-dev \ ctags \ curl-dev \ cyrus-sasl-dev \ @@ -29,6 +31,7 @@ RUN apk update && \ dtc-dev \ eudev-dev \ findutils \ + flex \ fuse3-dev \ g++ \ gcc \ @@ -39,6 +42,7 @@ RUN apk update && \ glib-static \ gnutls-dev \ gtk+3.0-dev \ + json-c-dev \ libaio-dev \ libbpf-dev \ libcap-ng-dev \ @@ -64,6 +68,7 @@ RUN apk update && \ mesa-dev \ meson \ multipath-tools \ + musl-dev \ ncurses-dev \ ndctl-dev \ net-tools \ @@ -81,7 +86,6 @@ RUN apk update && \ py3-pip \ py3-sphinx \ py3-sphinx_rtd_theme \ - py3-virtualenv \ py3-yaml \ python3 \ rpm2cpio \ diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 10618bfa83..d89113c0df 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -6,16 +6,18 @@ FROM quay.io/centos/centos:stream8 -RUN dnf update -y && \ +RUN dnf distro-sync -y && \ dnf install 'dnf-command(config-manager)' -y && \ dnf config-manager --set-enabled -y powertools && \ dnf install -y centos-release-advanced-virtualization && \ dnf install -y epel-release && \ + dnf install -y epel-next-release && \ dnf install -y \ SDL2-devel \ alsa-lib-devel \ bash \ bc \ + bison \ brlapi-devel \ bzip2 \ bzip2-devel \ @@ -30,6 +32,7 @@ RUN dnf update -y && \ device-mapper-multipath-devel \ diffutils \ findutils \ + flex \ fuse3-devel \ gcc \ gcc-c++ \ @@ -45,6 +48,7 @@ RUN dnf update -y && \ gtk3-devel \ hostname \ jemalloc-devel \ + json-c-devel \ libaio-devel \ libasan \ libattr-devel \ @@ -60,7 +64,6 @@ RUN dnf update -y && \ libgcrypt-devel \ libiscsi-devel \ libjpeg-devel \ - json-c-devel \ libnfs-devel \ libpmem-devel \ libpng-devel \ @@ -99,7 +102,6 @@ RUN dnf update -y && \ python3-pip \ python3-sphinx \ python3-sphinx_rtd_theme \ - python3-virtualenv \ rdma-core-devel \ rpm \ sed \ diff --git a/tests/docker/dockerfiles/debian-all-test-cross.docker b/tests/docker/dockerfiles/debian-all-test-cross.docker index dedcea58b4..2beb077fb4 100644 --- a/tests/docker/dockerfiles/debian-all-test-cross.docker +++ b/tests/docker/dockerfiles/debian-all-test-cross.docker @@ -6,16 +6,24 @@ # basic compilers for as many targets as possible. We shall use this # to build and run linux-user tests on GitLab # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -# What we need to build QEMU itself -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ +# Duplicate deb line as deb-src +RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list + +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ apt build-dep -yy qemu -# Add the foreign architecture we want and install dependencies +# Add extra build tools and as many cross compilers as we can for testing RUN DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ + ccache \ + clang \ + git \ + ninja-build \ gcc-aarch64-linux-gnu \ libc6-dev-arm64-cross \ gcc-alpha-linux-gnu \ diff --git a/tests/docker/dockerfiles/debian-alpha-cross.docker b/tests/docker/dockerfiles/debian-alpha-cross.docker index 10fe30df0d..4eeb43c78a 100644 --- a/tests/docker/dockerfiles/debian-alpha-cross.docker +++ b/tests/docker/dockerfiles/debian-alpha-cross.docker @@ -1,12 +1,14 @@ # # Docker cross-compiler target # -# This docker target builds on the debian Buster base image. +# This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ gcc-alpha-linux-gnu \ libc6.1-dev-alpha-cross diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index 870109ef6a..9047759e76 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -1,22 +1,171 @@ +# THIS FILE WAS AUTO-GENERATED # -# Docker x86_64 cross target +# $ lcitool dockerfile --layers all --cross x86_64 debian-11 qemu # -# This docker target is used on non-x86_64 machines which need the -# x86_64 cross compilers installed. -# -FROM qemu/debian10 -MAINTAINER Alex Bennée +# https://gitlab.com/libvirt/libvirt-ci -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture amd64 -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - crossbuild-essential-amd64 -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a amd64 --arch-only qemu +FROM docker.io/library/debian:11-slim -# Specify the cross prefix for this image (see tests/docker/common.rc) +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ + bash \ + bc \ + bison \ + bsdextrautils \ + bzip2 \ + ca-certificates \ + ccache \ + dbus \ + debianutils \ + diffutils \ + exuberant-ctags \ + findutils \ + flex \ + gcovr \ + genisoimage \ + gettext \ + git \ + hostname \ + libglib2.0-dev \ + libpcre2-dev \ + libspice-protocol-dev \ + llvm \ + locales \ + make \ + meson \ + ncat \ + ninja-build \ + openssh-client \ + perl-base \ + pkgconf \ + python3 \ + python3-numpy \ + python3-opencv \ + python3-pillow \ + python3-pip \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + python3-venv \ + python3-yaml \ + rpm2cpio \ + sed \ + sparse \ + tar \ + tesseract-ocr \ + tesseract-ocr-eng \ + texinfo && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ + dpkg-reconfigure locales + +ENV LANG "en_US.UTF-8" +ENV MAKE "/usr/bin/make" +ENV NINJA "/usr/bin/ninja" +ENV PYTHON "/usr/bin/python3" +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" + +RUN export DEBIAN_FRONTEND=noninteractive && \ + dpkg --add-architecture amd64 && \ + eatmydata apt-get update && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y dpkg-dev && \ + eatmydata apt-get install --no-install-recommends -y \ + g++-x86-64-linux-gnu \ + gcc-x86-64-linux-gnu \ + libaio-dev:amd64 \ + libasan5:amd64 \ + libasound2-dev:amd64 \ + libattr1-dev:amd64 \ + libbpf-dev:amd64 \ + libbrlapi-dev:amd64 \ + libbz2-dev:amd64 \ + libc6-dev:amd64 \ + libcacard-dev:amd64 \ + libcap-ng-dev:amd64 \ + libcapstone-dev:amd64 \ + libcmocka-dev:amd64 \ + libcurl4-gnutls-dev:amd64 \ + libdaxctl-dev:amd64 \ + libdrm-dev:amd64 \ + libepoxy-dev:amd64 \ + libfdt-dev:amd64 \ + libffi-dev:amd64 \ + libfuse3-dev:amd64 \ + libgbm-dev:amd64 \ + libgcrypt20-dev:amd64 \ + libglib2.0-dev:amd64 \ + libglusterfs-dev:amd64 \ + libgnutls28-dev:amd64 \ + libgtk-3-dev:amd64 \ + libibumad-dev:amd64 \ + libibverbs-dev:amd64 \ + libiscsi-dev:amd64 \ + libjemalloc-dev:amd64 \ + libjpeg62-turbo-dev:amd64 \ + libjson-c-dev:amd64 \ + liblttng-ust-dev:amd64 \ + liblzo2-dev:amd64 \ + libncursesw5-dev:amd64 \ + libnfs-dev:amd64 \ + libnuma-dev:amd64 \ + libpam0g-dev:amd64 \ + libpixman-1-dev:amd64 \ + libpmem-dev:amd64 \ + libpng-dev:amd64 \ + libpulse-dev:amd64 \ + librbd-dev:amd64 \ + librdmacm-dev:amd64 \ + libsasl2-dev:amd64 \ + libsdl2-dev:amd64 \ + libsdl2-image-dev:amd64 \ + libseccomp-dev:amd64 \ + libselinux1-dev:amd64 \ + libslirp-dev:amd64 \ + libsnappy-dev:amd64 \ + libspice-server-dev:amd64 \ + libssh-gcrypt-dev:amd64 \ + libsystemd-dev:amd64 \ + libtasn1-6-dev:amd64 \ + libubsan1:amd64 \ + libudev-dev:amd64 \ + liburing-dev:amd64 \ + libusb-1.0-0-dev:amd64 \ + libusbredirhost-dev:amd64 \ + libvdeplug-dev:amd64 \ + libvirglrenderer-dev:amd64 \ + libvte-2.91-dev:amd64 \ + libxen-dev:amd64 \ + libzstd-dev:amd64 \ + nettle-dev:amd64 \ + systemtap-sdt-dev:amd64 \ + xfslibs-dev:amd64 \ + zlib1g-dev:amd64 && \ + eatmydata apt-get autoremove -y && \ + eatmydata apt-get autoclean -y && \ + mkdir -p /usr/local/share/meson/cross && \ + echo "[binaries]\n\ +c = '/usr/bin/x86_64-linux-gnu-gcc'\n\ +ar = '/usr/bin/x86_64-linux-gnu-gcc-ar'\n\ +strip = '/usr/bin/x86_64-linux-gnu-strip'\n\ +pkgconfig = '/usr/bin/x86_64-linux-gnu-pkg-config'\n\ +\n\ +[host_machine]\n\ +system = 'linux'\n\ +cpu_family = 'x86_64'\n\ +cpu = 'x86_64'\n\ +endian = 'little'" > /usr/local/share/meson/cross/x86_64-linux-gnu && \ + dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/x86_64-linux-gnu-c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/x86_64-linux-gnu-cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/x86_64-linux-gnu-g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/x86_64-linux-gnu-gcc + +ENV ABI "x86_64-linux-gnu" +ENV MESON_OPTS "--cross-file=x86_64-linux-gnu" ENV QEMU_CONFIGURE_OPTS --cross-prefix=x86_64-linux-gnu- ENV DEF_TARGET_LIST x86_64-softmmu,x86_64-linux-user,i386-softmmu,i386-linux-user diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index 503e282802..a8b728ca64 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdextrautils \ bzip2 \ ca-certificates \ @@ -23,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ g++ \ gcc \ gcovr \ @@ -41,6 +43,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev \ libcap-ng-dev \ libcapstone-dev \ + libcmocka-dev \ libcurl4-gnutls-dev \ libdaxctl-dev \ libdrm-dev \ @@ -59,6 +62,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev \ libjemalloc-dev \ libjpeg62-turbo-dev \ + libjson-c-dev \ liblttng-ust-dev \ liblzo2-dev \ libncursesw5-dev \ diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index b60426834c..17a5709245 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdextrautils \ bzip2 \ ca-certificates \ @@ -22,11 +23,13 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ gcovr \ genisoimage \ gettext \ git \ hostname \ + libglib2.0-dev \ libpcre2-dev \ libspice-protocol-dev \ llvm \ @@ -84,6 +87,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev:arm64 \ libcap-ng-dev:arm64 \ libcapstone-dev:arm64 \ + libcmocka-dev:arm64 \ libcurl4-gnutls-dev:arm64 \ libdaxctl-dev:arm64 \ libdrm-dev:arm64 \ @@ -102,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev:arm64 \ libjemalloc-dev:arm64 \ libjpeg62-turbo-dev:arm64 \ + libjson-c-dev:arm64 \ liblttng-ust-dev:arm64 \ liblzo2-dev:arm64 \ libncursesw5-dev:arm64 \ diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index a6153e5a83..701fc70db0 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdextrautils \ bzip2 \ ca-certificates \ @@ -22,11 +23,13 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ gcovr \ genisoimage \ gettext \ git \ hostname \ + libglib2.0-dev \ libpcre2-dev \ libspice-protocol-dev \ llvm \ @@ -84,6 +87,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev:armel \ libcap-ng-dev:armel \ libcapstone-dev:armel \ + libcmocka-dev:armel \ libcurl4-gnutls-dev:armel \ libdaxctl-dev:armel \ libdrm-dev:armel \ @@ -102,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev:armel \ libjemalloc-dev:armel \ libjpeg62-turbo-dev:armel \ + libjson-c-dev:armel \ liblttng-ust-dev:armel \ liblzo2-dev:armel \ libncursesw5-dev:armel \ diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index a2ebce96f8..5a11fe3900 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdextrautils \ bzip2 \ ca-certificates \ @@ -22,11 +23,13 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ gcovr \ genisoimage \ gettext \ git \ hostname \ + libglib2.0-dev \ libpcre2-dev \ libspice-protocol-dev \ llvm \ @@ -84,6 +87,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev:armhf \ libcap-ng-dev:armhf \ libcapstone-dev:armhf \ + libcmocka-dev:armhf \ libcurl4-gnutls-dev:armhf \ libdaxctl-dev:armhf \ libdrm-dev:armhf \ @@ -102,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev:armhf \ libjemalloc-dev:armhf \ libjpeg62-turbo-dev:armhf \ + libjson-c-dev:armhf \ liblttng-ust-dev:armhf \ liblzo2-dev:armhf \ libncursesw5-dev:armhf \ diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker b/tests/docker/dockerfiles/debian-hexagon-cross.docker index d5dc299dc1..8d219bb81d 100644 --- a/tests/docker/dockerfiles/debian-hexagon-cross.docker +++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker @@ -2,12 +2,10 @@ # Docker Hexagon cross-compiler target # # This docker target is used for building hexagon tests. As it also -# needs to be able to build QEMU itself in CI we include it's -# build-deps. It is also a "stand-alone" image so as not to be -# triggered by re-builds on other base images given it takes a long -# time to build. +# needs to be able to build QEMU itself in CI we include its +# build-deps. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim # Install common build utilities RUN apt update && \ @@ -15,11 +13,18 @@ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ bison \ + ca-certificates \ + clang \ cmake \ flex \ + gcc \ lld \ + make \ + ninja-build \ + python3 \ rsync \ - wget + wget \ + xz-utils ENV TOOLCHAIN_INSTALL /usr/local ENV ROOTFS /usr/local @@ -32,7 +37,7 @@ ADD build-toolchain.sh /root/hexagon-toolchain/build-toolchain.sh RUN cd /root/hexagon-toolchain && ./build-toolchain.sh -FROM debian:buster-slim +FROM docker.io/library/debian:11-slim # Duplicate deb line as deb-src RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list # Install QEMU build deps for use in CI diff --git a/tests/docker/dockerfiles/debian-hppa-cross.docker b/tests/docker/dockerfiles/debian-hppa-cross.docker index 3d6c65a3ef..af1c8403d8 100644 --- a/tests/docker/dockerfiles/debian-hppa-cross.docker +++ b/tests/docker/dockerfiles/debian-hppa-cross.docker @@ -1,12 +1,14 @@ # # Docker cross-compiler target # -# This docker target builds on the debian Buster base image. +# This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ gcc-hppa-linux-gnu \ libc6-dev-hppa-cross diff --git a/tests/docker/dockerfiles/debian-loongarch-cross.docker b/tests/docker/dockerfiles/debian-loongarch-cross.docker index ca2469d2a8..a8e8e98909 100644 --- a/tests/docker/dockerfiles/debian-loongarch-cross.docker +++ b/tests/docker/dockerfiles/debian-loongarch-cross.docker @@ -1,11 +1,13 @@ # # Docker cross-compiler target # -# This docker target builds on the debian11 base image, -# using a prebuilt toolchains for LoongArch64 from: +# This docker target uses prebuilt toolchains for LoongArch64 from: # https://github.com/loongson/build-tools/releases # -FROM qemu/debian11 +FROM docker.io/library/debian:11-slim + +# Duplicate deb line as deb-src +RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ diff --git a/tests/docker/dockerfiles/debian-m68k-cross.docker b/tests/docker/dockerfiles/debian-m68k-cross.docker index fcb10e3534..dded71c5d2 100644 --- a/tests/docker/dockerfiles/debian-m68k-cross.docker +++ b/tests/docker/dockerfiles/debian-m68k-cross.docker @@ -1,12 +1,14 @@ # # Docker cross-compiler target # -# This docker target builds on the debian Buster base image. +# This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ gcc-m68k-linux-gnu \ libc6-dev-m68k-cross diff --git a/tests/docker/dockerfiles/debian-mips-cross.docker b/tests/docker/dockerfiles/debian-mips-cross.docker index 26c154014d..7b55f0f3b2 100644 --- a/tests/docker/dockerfiles/debian-mips-cross.docker +++ b/tests/docker/dockerfiles/debian-mips-cross.docker @@ -1,32 +1,14 @@ # # Docker mips cross-compiler target # -# This docker target builds on the debian Buster base image. +# This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -MAINTAINER Philippe Mathieu-Daudé - -# Add the foreign architecture we want and install dependencies -RUN dpkg --add-architecture mips -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - gcc-mips-linux-gnu - -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy -a mips --arch-only qemu - -# Specify the cross prefix for this image (see tests/docker/common.rc) -ENV QEMU_CONFIGURE_OPTS --cross-prefix=mips-linux-gnu- -ENV DEF_TARGET_LIST mips-softmmu,mipsel-linux-user - -# Install extra libraries to increase code coverage -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - libbz2-dev:mips \ - liblzo2-dev:mips \ - librdmacm-dev:mips \ - libsnappy-dev:mips +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ + gcc-mips-linux-gnu \ + libc6-dev-mips-cross diff --git a/tests/docker/dockerfiles/debian-mips64-cross.docker b/tests/docker/dockerfiles/debian-mips64-cross.docker index 09c2ba584e..afcff9726f 100644 --- a/tests/docker/dockerfiles/debian-mips64-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64-cross.docker @@ -1,12 +1,14 @@ # # Docker cross-compiler target # -# This docker target builds on the debian Buster base image. +# This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ gcc-mips64-linux-gnuabi64 \ libc6-dev-mips64-cross diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index b02dcb7fd9..9b90a4d6ff 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdextrautils \ bzip2 \ ca-certificates \ @@ -22,11 +23,13 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ gcovr \ genisoimage \ gettext \ git \ hostname \ + libglib2.0-dev \ libpcre2-dev \ libspice-protocol-dev \ llvm \ @@ -83,6 +86,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev:mips64el \ libcap-ng-dev:mips64el \ libcapstone-dev:mips64el \ + libcmocka-dev:mips64el \ libcurl4-gnutls-dev:mips64el \ libdaxctl-dev:mips64el \ libdrm-dev:mips64el \ @@ -101,6 +105,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev:mips64el \ libjemalloc-dev:mips64el \ libjpeg62-turbo-dev:mips64el \ + libjson-c-dev:mips64el \ liblttng-ust-dev:mips64el \ liblzo2-dev:mips64el \ libncursesw5-dev:mips64el \ diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index b6d99ae324..02feaf26cb 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdextrautils \ bzip2 \ ca-certificates \ @@ -22,11 +23,13 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ gcovr \ genisoimage \ gettext \ git \ hostname \ + libglib2.0-dev \ libpcre2-dev \ libspice-protocol-dev \ llvm \ @@ -83,6 +86,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev:mipsel \ libcap-ng-dev:mipsel \ libcapstone-dev:mipsel \ + libcmocka-dev:mipsel \ libcurl4-gnutls-dev:mipsel \ libdaxctl-dev:mipsel \ libdrm-dev:mipsel \ @@ -101,6 +105,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev:mipsel \ libjemalloc-dev:mipsel \ libjpeg62-turbo-dev:mipsel \ + libjson-c-dev:mipsel \ liblttng-ust-dev:mipsel \ liblzo2-dev:mipsel \ libncursesw5-dev:mipsel \ diff --git a/tests/docker/dockerfiles/debian-native.docker b/tests/docker/dockerfiles/debian-native.docker index efd55cb6e0..8dd033097c 100644 --- a/tests/docker/dockerfiles/debian-native.docker +++ b/tests/docker/dockerfiles/debian-native.docker @@ -1,7 +1,7 @@ # # Docker Debian Native # -# This this intended to build QEMU on native host systems. Debian is +# This is intended to build QEMU on native host systems. Debian is # chosen due to the broadest range on supported host systems for QEMU. # # This docker target is based on the docker.io Debian Bullseye base diff --git a/tests/docker/dockerfiles/debian-powerpc-test-cross.docker b/tests/docker/dockerfiles/debian-powerpc-test-cross.docker index 36b336f709..d6b2909cc4 100644 --- a/tests/docker/dockerfiles/debian-powerpc-test-cross.docker +++ b/tests/docker/dockerfiles/debian-powerpc-test-cross.docker @@ -1,13 +1,15 @@ # # Docker powerpc/ppc64/ppc64le cross-compiler target # -# This docker target builds on the debian Bullseye base image. +# This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian11 +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ gcc-powerpc-linux-gnu \ libc6-dev-powerpc-cross \ gcc-10-powerpc64-linux-gnu \ diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index bcf04bc90b..97d3872ee2 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdextrautils \ bzip2 \ ca-certificates \ @@ -22,11 +23,13 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ gcovr \ genisoimage \ gettext \ git \ hostname \ + libglib2.0-dev \ libpcre2-dev \ libspice-protocol-dev \ llvm \ @@ -84,6 +87,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev:ppc64el \ libcap-ng-dev:ppc64el \ libcapstone-dev:ppc64el \ + libcmocka-dev:ppc64el \ libcurl4-gnutls-dev:ppc64el \ libdaxctl-dev:ppc64el \ libdrm-dev:ppc64el \ @@ -102,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev:ppc64el \ libjemalloc-dev:ppc64el \ libjpeg62-turbo-dev:ppc64el \ + libjson-c-dev:ppc64el \ liblttng-ust-dev:ppc64el \ liblzo2-dev:ppc64el \ libncursesw5-dev:ppc64el \ diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index 594d97982c..9715791e0b 100644 --- a/tests/docker/dockerfiles/debian-riscv64-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker @@ -16,13 +16,16 @@ RUN apt update && \ # Install common build utilities RUN DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy \ + bison \ bc \ build-essential \ ca-certificates \ debian-ports-archive-keyring \ dpkg-dev \ + flex \ gettext \ git \ + libglib2.0-dev \ ninja-build \ pkg-config \ python3 diff --git a/tests/docker/dockerfiles/debian-riscv64-test-cross.docker b/tests/docker/dockerfiles/debian-riscv64-test-cross.docker index 1d90901298..e5f83a5aeb 100644 --- a/tests/docker/dockerfiles/debian-riscv64-test-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-test-cross.docker @@ -3,10 +3,12 @@ # # This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian11 +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ gcc-riscv64-linux-gnu \ libc6-dev-riscv64-cross diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index ff79a2cc4f..95585e9e56 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdextrautils \ bzip2 \ ca-certificates \ @@ -22,11 +23,13 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ gcovr \ genisoimage \ gettext \ git \ hostname \ + libglib2.0-dev \ libpcre2-dev \ libspice-protocol-dev \ llvm \ @@ -84,6 +87,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev:s390x \ libcap-ng-dev:s390x \ libcapstone-dev:s390x \ + libcmocka-dev:s390x \ libcurl4-gnutls-dev:s390x \ libdaxctl-dev:s390x \ libdrm-dev:s390x \ @@ -102,6 +106,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev:s390x \ libjemalloc-dev:s390x \ libjpeg62-turbo-dev:s390x \ + libjson-c-dev:s390x \ liblttng-ust-dev:s390x \ liblzo2-dev:s390x \ libncursesw5-dev:s390x \ diff --git a/tests/docker/dockerfiles/debian-sh4-cross.docker b/tests/docker/dockerfiles/debian-sh4-cross.docker index fd3af89575..d48ed9065f 100644 --- a/tests/docker/dockerfiles/debian-sh4-cross.docker +++ b/tests/docker/dockerfiles/debian-sh4-cross.docker @@ -1,12 +1,14 @@ # # Docker cross-compiler target # -# This docker target builds on the debian Buster base image. +# This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ gcc-sh4-linux-gnu \ libc6-dev-sh4-cross diff --git a/tests/docker/dockerfiles/debian-sparc64-cross.docker b/tests/docker/dockerfiles/debian-sparc64-cross.docker index f4bb9b561c..8d3d306bc1 100644 --- a/tests/docker/dockerfiles/debian-sparc64-cross.docker +++ b/tests/docker/dockerfiles/debian-sparc64-cross.docker @@ -1,12 +1,14 @@ # # Docker cross-compiler target # -# This docker target builds on the debian Buster base image. +# This docker target builds on the Debian Bullseye base image. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ +RUN export DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y eatmydata && \ + eatmydata apt-get dist-upgrade -y && \ + eatmydata apt-get install --no-install-recommends -y \ gcc-sparc64-linux-gnu \ libc6-dev-sparc64-cross diff --git a/tests/docker/dockerfiles/debian-toolchain.docker b/tests/docker/dockerfiles/debian-toolchain.docker index 738d808aa6..d3d4d3344e 100644 --- a/tests/docker/dockerfiles/debian-toolchain.docker +++ b/tests/docker/dockerfiles/debian-toolchain.docker @@ -4,7 +4,7 @@ # This dockerfile is used for building a cross-compiler toolchain. # The script for building the toolchain is supplied via extra-files. # -FROM qemu/debian10 +FROM docker.io/library/debian:11-slim # Install build utilities for building gcc and glibc. # ??? The build-dep isn't working, missing a number of @@ -15,6 +15,7 @@ RUN apt update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt install -y --no-install-recommends \ bison \ + ca-certificates \ flex \ gawk \ libmpc-dev \ @@ -32,5 +33,5 @@ RUN cd /root && ./build-toolchain.sh # Throw away the extra toolchain build deps, the downloaded source, # and the build trees by restoring the original debian10 image, # then copying the built toolchain from stage 0. -FROM qemu/debian10 +FROM docker.io/library/debian:bullseye-slim COPY --from=0 /usr/local /usr/local diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker deleted file mode 100644 index 03be923066..0000000000 --- a/tests/docker/dockerfiles/debian10.docker +++ /dev/null @@ -1,38 +0,0 @@ -# -# Docker multiarch cross-compiler target -# -# This docker target is builds on Debian cross compiler targets to build distro -# with a selection of cross compilers for building test binaries. -# -# On its own you can't build much but the docker-foo-cross targets -# build on top of the base debian image. -# -FROM docker.io/library/debian:buster-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 && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - bc \ - build-essential \ - ca-certificates \ - ccache \ - clang \ - dbus \ - gdb-multiarch \ - gettext \ - git \ - libffi-dev \ - libncurses5-dev \ - ninja-build \ - pkg-config \ - psmisc \ - python3 \ - python3-sphinx \ - python3-sphinx-rtd-theme \ - python3-venv \ - $(apt-get -s build-dep --arch-only qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2) diff --git a/tests/docker/dockerfiles/debian11.docker b/tests/docker/dockerfiles/debian11.docker deleted file mode 100644 index febf884f8f..0000000000 --- a/tests/docker/dockerfiles/debian11.docker +++ /dev/null @@ -1,18 +0,0 @@ -# -# 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 docker.io/library/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/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker index 0a3ec346e6..7eec648d2d 100644 --- a/tests/docker/dockerfiles/fedora-i386-cross.docker +++ b/tests/docker/dockerfiles/fedora-i386-cross.docker @@ -1,9 +1,11 @@ FROM registry.fedoraproject.org/fedora:34 ENV PACKAGES \ + bison \ bzip2 \ ccache \ diffutils \ + flex \ findutils \ gcc \ git \ diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index a06bd29e8e..aca37aabc4 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -3,13 +3,16 @@ FROM registry.fedoraproject.org/fedora:35 # Please keep this list sorted alphabetically ENV PACKAGES \ bc \ + bison \ bzip2 \ ccache \ diffutils \ findutils \ + flex \ gcc \ gettext \ git \ + glib2-devel \ hostname \ make \ meson \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index b71624330f..3642766479 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -3,13 +3,16 @@ FROM registry.fedoraproject.org/fedora:35 # Please keep this list sorted alphabetically ENV PACKAGES \ bc \ + bison \ bzip2 \ ccache \ diffutils \ findutils \ + flex \ gcc \ gettext \ git \ + glib2-devel \ hostname \ make \ meson \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 2e6a84abfd..fe84166ca1 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -23,6 +23,7 @@ exec "$@"' > /usr/bin/nosync && \ alsa-lib-devel \ bash \ bc \ + bison \ brlapi-devel \ bzip2 \ bzip2-devel \ @@ -37,6 +38,7 @@ exec "$@"' > /usr/bin/nosync && \ device-mapper-multipath-devel \ diffutils \ findutils \ + flex \ fuse3-devel \ gcc \ gcc-c++ \ @@ -53,12 +55,14 @@ exec "$@"' > /usr/bin/nosync && \ gtk3-devel \ hostname \ jemalloc-devel \ + json-c-devel \ libaio-devel \ libasan \ libattr-devel \ libbpf-devel \ libcacard-devel \ libcap-ng-devel \ + libcmocka-devel \ libcurl-devel \ libdrm-devel \ libepoxy-devel \ @@ -106,7 +110,6 @@ exec "$@"' > /usr/bin/nosync && \ python3-pip \ python3-sphinx \ python3-sphinx_rtd_theme \ - python3-virtualenv \ rdma-core-devel \ rpm \ sed \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index 6f5993d602..d80064756f 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -1,10 +1,10 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all opensuse-leap-152 qemu +# $ lcitool dockerfile --layers all opensuse-leap-153 qemu # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.opensuse.org/opensuse/leap:15.2 +FROM registry.opensuse.org/opensuse/leap:15.3 RUN zypper update -y && \ zypper install -y \ @@ -12,6 +12,7 @@ RUN zypper update -y && \ alsa-lib-devel \ bash \ bc \ + bison \ brlapi-devel \ bzip2 \ ca-certificates \ @@ -22,6 +23,7 @@ RUN zypper update -y && \ dbus-1 \ diffutils \ findutils \ + flex \ fuse3-devel \ gcc \ gcc-c++ \ @@ -44,6 +46,7 @@ RUN zypper update -y && \ libbz2-devel \ libcacard-devel \ libcap-ng-devel \ + libcmocka-devel \ libcurl-devel \ libdrm-devel \ libepoxy-devel \ @@ -53,6 +56,7 @@ RUN zypper update -y && \ libgnutls-devel \ libiscsi-devel \ libjpeg8-devel \ + libjson-c-devel \ libndctl-devel \ libnettle-devel \ libnfs-devel \ @@ -64,6 +68,7 @@ RUN zypper update -y && \ librbd-devel \ libseccomp-devel \ libselinux-devel \ + libslirp-devel \ libspice-server-devel \ libssh-devel \ libtasn1-devel \ @@ -94,7 +99,6 @@ RUN zypper update -y && \ python3-pip \ python3-setuptools \ python3-sphinx_rtd_theme \ - python3-virtualenv \ python3-wheel \ rdma-core-devel \ rpm \ @@ -126,7 +130,7 @@ RUN zypper update -y && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN pip3 install meson==0.56.0 +RUN /usr/bin/pip3 install meson==0.56.0 ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index a3b38884e3..24594afc15 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -13,6 +13,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ eatmydata apt-get install --no-install-recommends -y \ bash \ bc \ + bison \ bsdmainutils \ bzip2 \ ca-certificates \ @@ -23,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ diffutils \ exuberant-ctags \ findutils \ + flex \ g++ \ gcc \ gcovr \ @@ -40,6 +42,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libcacard-dev \ libcap-ng-dev \ libcapstone-dev \ + libcmocka-dev \ libcurl4-gnutls-dev \ libdaxctl-dev \ libdrm-dev \ @@ -58,6 +61,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ libiscsi-dev \ libjemalloc-dev \ libjpeg-turbo8-dev \ + libjson-c-dev \ liblttng-ust-dev \ liblzo2-dev \ libncursesw5-dev \ @@ -135,7 +139,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN pip3 install meson==0.56.0 +RUN /usr/bin/pip3 install meson==0.56.0 ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/run b/tests/docker/run index 421393046b..9eb96129da 100755 --- a/tests/docker/run +++ b/tests/docker/run @@ -15,7 +15,7 @@ if test -n "$V"; then set -x fi -BASE="$(dirname $(readlink -e $0))" +BASE="$(dirname $(realpath $0))" # Prepare the environment export PATH=/usr/lib/ccache:/usr/lib64/ccache:$PATH diff --git a/tests/fp/meson.build b/tests/fp/meson.build index 2b4f00b916..6258e2bd7d 100644 --- a/tests/fp/meson.build +++ b/tests/fp/meson.build @@ -632,7 +632,7 @@ test('fp-test-mulAdd', fptest, ['f16_mulAdd', 'f32_mulAdd', 'f64_mulAdd', 'f128_mulAdd'], suite: ['softfloat-slow', 'softfloat-ops-slow', 'slow'], timeout: 90) -fpbench = executable( +executable( 'fp-bench', ['fp-bench.c', '../../fpu/softfloat.c'], link_with: [libtestfloat, libsoftfloat], diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci index f83b916d5e..e3712b7912 160000 --- a/tests/lcitool/libvirt-ci +++ b/tests/lcitool/libvirt-ci @@ -1 +1 @@ -Subproject commit f83b916d5efa4bd33fbf4b7ea41bf6d535cc63fb +Subproject commit e3712b79122180fdb3b7a7ea8cbee47ece253f97 diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index d068a7a8de..0d92819249 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -3,12 +3,14 @@ packages: - alsa - bash - bc + - bison - brlapi - bzip2 - bzip2-libs - capstone - ccache - clang + - cmocka - column - ctags - cyrus-sasl @@ -18,6 +20,7 @@ packages: - diffutils - dtrace - findutils + - flex - fuse3 - g++ - gcc @@ -25,16 +28,18 @@ packages: - gettext - genisoimage - glib2 + - glib2-native - glib2-static - - glibc-static - glusterfs - gnutls - gtk3 - hostname + - json-c - libaio - libattr - libasan - libbpf + - libc-static - libcacard - libcap-ng - libcurl @@ -90,7 +95,7 @@ packages: - python3-pip - python3-sphinx - python3-sphinx-rtd-theme - - python3-virtualenv + - python3-venv - rpm2cpio - sdl2 - sdl2-image diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 5e260f8cd6..e45c99adbe 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -25,7 +25,7 @@ self_dir = Path(__file__).parent src_dir = self_dir.parent.parent dockerfiles_dir = Path(src_dir, "tests", "docker", "dockerfiles") -lcitool_path = Path(self_dir, "libvirt-ci", "lcitool") +lcitool_path = Path(self_dir, "libvirt-ci", "bin", "lcitool") lcitool_cmd = [lcitool_path, "--data-dir", self_dir] @@ -107,18 +107,25 @@ try: # # Standard native builds # - generate_dockerfile("alpine", "alpine-edge") + generate_dockerfile("alpine", "alpine-316") generate_dockerfile("centos8", "centos-stream-8") generate_dockerfile("debian-amd64", "debian-11", trailer="".join(debian11_extras)) generate_dockerfile("fedora", "fedora-35") - generate_dockerfile("opensuse-leap", "opensuse-leap-152") + generate_dockerfile("opensuse-leap", "opensuse-leap-153") generate_dockerfile("ubuntu2004", "ubuntu-2004", trailer="".join(ubuntu2004_tsanhack)) # # Cross compiling builds # + generate_dockerfile("debian-amd64-cross", "debian-11", + cross="x86_64", + trailer=debian_cross_build("x86_64-linux-gnu-", + "x86_64-softmmu," + "x86_64-linux-user," + "i386-softmmu,i386-linux-user")) + generate_dockerfile("debian-arm64-cross", "debian-11", cross="aarch64", trailer=debian_cross_build("aarch64-linux-gnu-", diff --git a/tests/migration/aarch64/a-b-kernel.S b/tests/migration/aarch64/a-b-kernel.S index 0225945348..a4103ecb71 100644 --- a/tests/migration/aarch64/a-b-kernel.S +++ b/tests/migration/aarch64/a-b-kernel.S @@ -53,7 +53,6 @@ innerloop: /* increment the first byte of each page by 1 */ ldrb w3, [x4] add w3, w3, #1 - and w3, w3, #0xff strb w3, [x4] /* make sure QEMU user space can see consistent data as MMU is off */ @@ -64,7 +63,7 @@ innerloop: blt innerloop add w5, w5, #1 - and w5, w5, #0xff + and w5, w5, #0x1f cmp w5, #0 bne mainloop diff --git a/tests/migration/aarch64/a-b-kernel.h b/tests/migration/aarch64/a-b-kernel.h index 0a9b01137e..34e518d061 100644 --- a/tests/migration/aarch64/a-b-kernel.h +++ b/tests/migration/aarch64/a-b-kernel.h @@ -10,9 +10,9 @@ unsigned char aarch64_kernel[] = { 0x03, 0x00, 0x80, 0x52, 0xe4, 0x03, 0x00, 0xaa, 0x83, 0x00, 0x00, 0x39, 0x84, 0x04, 0x40, 0x91, 0x9f, 0x00, 0x01, 0xeb, 0xad, 0xff, 0xff, 0x54, 0x05, 0x00, 0x80, 0x52, 0xe4, 0x03, 0x00, 0xaa, 0x83, 0x00, 0x40, 0x39, - 0x63, 0x04, 0x00, 0x11, 0x63, 0x1c, 0x00, 0x12, 0x83, 0x00, 0x00, 0x39, - 0x24, 0x7e, 0x0b, 0xd5, 0x84, 0x04, 0x40, 0x91, 0x9f, 0x00, 0x01, 0xeb, - 0x2b, 0xff, 0xff, 0x54, 0xa5, 0x04, 0x00, 0x11, 0xa5, 0x1c, 0x00, 0x12, - 0xbf, 0x00, 0x00, 0x71, 0x81, 0xfe, 0xff, 0x54, 0x43, 0x08, 0x80, 0x52, - 0x43, 0x00, 0x00, 0x39, 0xf1, 0xff, 0xff, 0x17 + 0x63, 0x04, 0x00, 0x11, 0x83, 0x00, 0x00, 0x39, 0x24, 0x7e, 0x0b, 0xd5, + 0x84, 0x04, 0x40, 0x91, 0x9f, 0x00, 0x01, 0xeb, 0x4b, 0xff, 0xff, 0x54, + 0xa5, 0x04, 0x00, 0x11, 0xa5, 0x10, 0x00, 0x12, 0xbf, 0x00, 0x00, 0x71, + 0xa1, 0xfe, 0xff, 0x54, 0x43, 0x08, 0x80, 0x52, 0x43, 0x00, 0x00, 0x39, + 0xf2, 0xff, 0xff, 0x17 }; diff --git a/tests/migration/i386/a-b-bootblock.S b/tests/migration/i386/a-b-bootblock.S index 3f97f28023..3d464c7568 100644 --- a/tests/migration/i386/a-b-bootblock.S +++ b/tests/migration/i386/a-b-bootblock.S @@ -50,6 +50,7 @@ innerloop: jl innerloop inc %bl + andb $0x3f,%bl jnz mainloop mov $66,%ax diff --git a/tests/migration/i386/a-b-bootblock.h b/tests/migration/i386/a-b-bootblock.h index 7d459d4fde..b7b0fce2ee 100644 --- a/tests/migration/i386/a-b-bootblock.h +++ b/tests/migration/i386/a-b-bootblock.h @@ -4,17 +4,17 @@ * the header and the assembler differences in your patch submission. */ unsigned char x86_bootsect[] = { - 0xfa, 0x0f, 0x01, 0x16, 0x74, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00, + 0xfa, 0x0f, 0x01, 0x16, 0x78, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02, 0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41, 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10, 0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40, - 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x75, 0xe9, 0x66, 0xb8, 0x42, 0x00, 0x66, - 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xde, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x5c, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x80, 0xe3, 0x3f, 0x75, 0xe6, 0x66, 0xb8, + 0x42, 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xdb, 0x8d, 0x76, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x9a, 0xcf, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, + 0x27, 0x00, 0x60, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/tests/migration/stress.c b/tests/migration/stress.c index b7240a15c8..88acf8dc25 100644 --- a/tests/migration/stress.c +++ b/tests/migration/stress.c @@ -232,7 +232,7 @@ static void stress(unsigned long long ramsizeGB, int ncpus) static int mount_misc(const char *fstype, const char *dir) { - if (mkdir(dir, 0755) < 0 && errno != EEXIST) { + if (g_mkdir_with_parents(dir, 0755) < 0 && errno != EEXIST) { fprintf(stderr, "%s (%05d): ERROR: cannot create %s: %s\n", argv0, gettid(), dir, strerror(errno)); return -1; diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index c18dd7d02f..406bc7255d 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -215,18 +215,18 @@ test('QAPI schema regression tests', python, diff = find_program('diff') -qapi_doc = custom_target('QAPI doc', - output: ['doc-good-qapi-commands.c', 'doc-good-qapi-commands.h', - 'doc-good-qapi-emit-events.c', 'doc-good-qapi-emit-events.h', - 'doc-good-qapi-events.c', 'doc-good-qapi-events.h', - 'doc-good-qapi-init-commands.c', 'doc-good-qapi-init-commands.h', - 'doc-good-qapi-introspect.c', 'doc-good-qapi-introspect.h', - 'doc-good-qapi-types.c', 'doc-good-qapi-types.h', - 'doc-good-qapi-visit.c', 'doc-good-qapi-visit.h' ], - input: files('doc-good.json'), - command: [ qapi_gen, '-o', meson.current_build_dir(), - '-p', 'doc-good-', '@INPUT0@' ], - depend_files: qapi_gen_depends) +custom_target('QAPI doc', + output: ['doc-good-qapi-commands.c', 'doc-good-qapi-commands.h', + 'doc-good-qapi-emit-events.c', 'doc-good-qapi-emit-events.h', + 'doc-good-qapi-events.c', 'doc-good-qapi-events.h', + 'doc-good-qapi-init-commands.c', 'doc-good-qapi-init-commands.h', + 'doc-good-qapi-introspect.c', 'doc-good-qapi-introspect.h', + 'doc-good-qapi-types.c', 'doc-good-qapi-types.h', + 'doc-good-qapi-visit.c', 'doc-good-qapi-visit.h' ], + input: files('doc-good.json'), + command: [ qapi_gen, '-o', meson.current_build_dir(), + '-p', 'doc-good-', '@INPUT0@' ], + depend_files: qapi_gen_depends) if build_docs # Test the document-comment document generation code by running a test schema diff --git a/tests/qemu-iotests/131 b/tests/qemu-iotests/131 index d7456cae5b..a847692b4c 100755 --- a/tests/qemu-iotests/131 +++ b/tests/qemu-iotests/131 @@ -43,7 +43,7 @@ _supported_os Linux inuse_offset=$((0x2c)) -size=64M +size=$((64 * 1024 * 1024)) CLUSTER_SIZE=64k IMGFMT=parallels _make_test_img $size @@ -70,6 +70,39 @@ _check_test_img _check_test_img -r all { $QEMU_IO -c "read -P 0x11 64k 64k" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir +echo "== allocate with backing ==" +# Verify that allocating clusters works fine even when there is a backing image. +# Regression test for a bug where we would pass a buffer read from the backing +# node as a QEMUIOVector object, which could cause anything from I/O errors over +# assertion failures to invalid reads from memory. + +# Clear image +_make_test_img $size +# Create base image +TEST_IMG="$TEST_IMG.base" _make_test_img $size + +# Write some data to the base image (which would trigger an assertion failure if +# interpreted as a QEMUIOVector) +$QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG.base" | _filter_qemu_io + +# Parallels does not seem to support storing a backing filename in the image +# itself, so we need to build our backing chain on the command line +imgopts="driver=$IMGFMT,file.driver=$IMGPROTO,file.filename=$TEST_IMG" +imgopts+=",backing.driver=$IMGFMT" +imgopts+=",backing.file.driver=$IMGPROTO,backing.file.filename=$TEST_IMG.base" + +# Cause allocation in the top image +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \ + $QEMU_IO --image-opts "$imgopts" -c 'write -P 1 0 64' | _filter_qemu_io + +# Verify +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \ + $QEMU_IO --image-opts "$imgopts" \ + -c 'read -P 1 0 64' \ + -c "read -P 42 64 $((64 * 1024 - 64))" \ + -c "read -P 0 64k $((size - 64 * 1024))" \ + | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/131.out b/tests/qemu-iotests/131.out index 70da03dee5..de5ef7a8f5 100644 --- a/tests/qemu-iotests/131.out +++ b/tests/qemu-iotests/131.out @@ -37,4 +37,17 @@ Double checking the fixed image now... No errors were found on the image. read 65536/65536 bytes at offset 65536 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +== allocate with backing == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 64/64 bytes at offset 0 +64 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 64/64 bytes at offset 0 +64 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65472/65472 bytes at offset 64 +63.938 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 67043328/67043328 bytes at offset 65536 +63.938 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 9479b92185..07eebf3583 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -28,6 +28,8 @@ Testing: discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "288" @@ -55,6 +57,8 @@ Testing: -fda TEST_DIR/t.qcow2 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -92,6 +96,8 @@ Testing: -fdb TEST_DIR/t.qcow2 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -104,6 +110,8 @@ Testing: -fdb TEST_DIR/t.qcow2 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "288" floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -145,6 +153,8 @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -157,6 +167,8 @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -199,6 +211,8 @@ Testing: -fdb discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "288" dev: floppy, id "" unit = 0 (0x0) @@ -211,6 +225,8 @@ Testing: -fdb discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "288" @@ -238,6 +254,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -275,6 +293,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -287,6 +307,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "288" floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -328,6 +350,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -340,6 +364,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -385,6 +411,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/peripheral-anon/device[N] @@ -422,6 +450,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/peripheral-anon/device[N] @@ -459,6 +489,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -471,6 +503,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/peripheral-anon/device[N] @@ -522,6 +556,8 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -534,6 +570,8 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -576,6 +614,8 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -588,6 +628,8 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -630,6 +672,8 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 1 (0x1) @@ -642,6 +686,8 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -684,6 +730,8 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 1 (0x1) @@ -696,6 +744,8 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy1 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -747,6 +797,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -759,6 +811,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -801,6 +855,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" dev: floppy, id "" unit = 0 (0x0) @@ -813,6 +869,8 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" floppy0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/unattached/device[N] @@ -861,6 +919,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global floppy.drive=none0 -device discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/peripheral-anon/device[N] @@ -928,6 +988,8 @@ Testing: -device floppy discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "288" Testing: -device floppy,drive-type=120 @@ -952,6 +1014,8 @@ Testing: -device floppy,drive-type=120 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "120" Testing: -device floppy,drive-type=144 @@ -976,6 +1040,8 @@ Testing: -device floppy,drive-type=144 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" Testing: -device floppy,drive-type=288 @@ -1000,6 +1066,8 @@ Testing: -device floppy,drive-type=288 discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "288" @@ -1027,6 +1095,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "120" none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/peripheral-anon/device[N] @@ -1064,6 +1134,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "288" none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/peripheral-anon/device[N] @@ -1104,6 +1176,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/peripheral-anon/device[N] @@ -1141,6 +1215,8 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica discard_granularity = 4294967295 (4 GiB) write-cache = "auto" share-rw = false + account-invalid = "auto" + account-failed = "auto" drive-type = "144" none0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Attached to: /machine/peripheral-anon/device[N] diff --git a/tests/qemu-iotests/227.out b/tests/qemu-iotests/227.out index 9c09ee3917..378c1b8fb1 100644 --- a/tests/qemu-iotests/227.out +++ b/tests/qemu-iotests/227.out @@ -188,7 +188,7 @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-b ], "failed_unmap_operations": 0, "failed_flush_operations": 0, - "account_invalid": false, + "account_invalid": true, "rd_total_time_ns": 0, "invalid_unmap_operations": 0, "flush_operations": 0, @@ -198,7 +198,7 @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-b "rd_bytes": 0, "unmap_total_time_ns": 0, "invalid_flush_operations": 0, - "account_failed": false, + "account_failed": true, "rd_operations": 0, "invalid_wr_operations": 0, "invalid_rd_operations": 0 diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264 index bc431d1a19..289381e315 100755 --- a/tests/qemu-iotests/264 +++ b/tests/qemu-iotests/264 @@ -101,7 +101,7 @@ class TestNbdReconnect(iotests.QMPTestCase): start_t = time.time() self.vm.event_wait('BLOCK_JOB_CANCELLED') delta_t = time.time() - start_t - self.assertTrue(delta_t < 2.0) + self.assertTrue(delta_t < 5.0) def test_mirror_cancel(self): # Mirror speed limit doesn't work well enough, it seems that mirror diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 165b54a61e..db757025cb 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -982,7 +982,7 @@ _require_large_file() # _require_devices() { - available=$($QEMU -M none -device help | \ + available=$($QEMU -M none -device help 2> /dev/null | \ grep ^name | sed -e 's/^name "//' -e 's/".*$//') for device do @@ -994,7 +994,7 @@ _require_devices() _require_one_device_of() { - available=$($QEMU -M none -device help | \ + available=$($QEMU -M none -device help 2> /dev/null | \ grep ^name | sed -e 's/^name "//' -e 's/".*$//') for device do diff --git a/tests/qemu-iotests/tests/backing-file-invalidation b/tests/qemu-iotests/tests/backing-file-invalidation new file mode 100755 index 0000000000..4eccc80153 --- /dev/null +++ b/tests/qemu-iotests/tests/backing-file-invalidation @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +# group: rw migration +# +# Migrate a VM with a BDS with backing nodes, which runs +# bdrv_invalidate_cache(), which for qcow2 and qed triggers reading the +# backing file string from the image header. Check whether this +# interferes with bdrv_backing_overridden(). +# +# Copyright (C) 2022 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 . +# + +import json +import os +from typing import Optional + +import iotests +from iotests import qemu_img_create, qemu_img_info + + +image_size = 1 * 1024 * 1024 +imgs = [os.path.join(iotests.test_dir, f'{i}.img') for i in range(0, 4)] + +mig_sock = os.path.join(iotests.sock_dir, 'mig.sock') + + +class TestPostMigrateFilename(iotests.QMPTestCase): + vm_s: Optional[iotests.VM] = None + vm_d: Optional[iotests.VM] = None + + def setUp(self) -> None: + # Create backing chain of three images, where the backing file strings + # are json:{} filenames + qemu_img_create('-f', iotests.imgfmt, imgs[0], str(image_size)) + for i in range(1, 3): + backing = { + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': imgs[i - 1] + } + } + qemu_img_create('-f', iotests.imgfmt, '-F', iotests.imgfmt, + '-b', 'json:' + json.dumps(backing), + imgs[i], str(image_size)) + + def tearDown(self) -> None: + if self.vm_s is not None: + self.vm_s.shutdown() + if self.vm_d is not None: + self.vm_d.shutdown() + + for img in imgs: + try: + os.remove(img) + except OSError: + pass + try: + os.remove(mig_sock) + except OSError: + pass + + def test_migration(self) -> None: + """ + Migrate a VM with the backing chain created in setUp() attached. At + the end of the migration process, the destination will run + bdrv_invalidate_cache(), which for some image formats (qcow2 and qed) + means the backing file string is re-read from the image header. If + this overwrites bs->auto_backing_file, doing so may cause + bdrv_backing_overridden() to become true: The image header reports a + json:{} filename, but when opening it, bdrv_refresh_filename() will + simplify it to a plain simple filename; and when bs->auto_backing_file + and bs->backing->bs->filename differ, bdrv_backing_overridden() becomes + true. + If bdrv_backing_overridden() is true, the BDS will be forced to get a + json:{} filename, which in general is not the end of the world, but not + great. Check whether that happens, i.e. whether migration changes the + node's filename. + """ + + blockdev = { + 'node-name': 'node0', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': imgs[2] + } + } + + self.vm_s = iotests.VM(path_suffix='a') \ + .add_blockdev(json.dumps(blockdev)) + self.vm_d = iotests.VM(path_suffix='b') \ + .add_blockdev(json.dumps(blockdev)) \ + .add_incoming(f'unix:{mig_sock}') + + assert self.vm_s is not None + assert self.vm_d is not None + + self.vm_s.launch() + self.vm_d.launch() + + pre_mig_filename = self.vm_s.node_info('node0')['file'] + + self.vm_s.qmp('migrate', uri=f'unix:{mig_sock}') + + # Wait for migration to be done + self.vm_s.event_wait('STOP') + self.vm_d.event_wait('RESUME') + + post_mig_filename = self.vm_d.node_info('node0')['file'] + + # Verify that the filename hasn't changed from before the migration + self.assertEqual(pre_mig_filename, post_mig_filename) + + self.vm_s.shutdown() + self.vm_s = None + + # For good measure, try creating an overlay and check its backing + # chain below. This is how the issue was originally found. + result = self.vm_d.qmp('blockdev-snapshot-sync', + format=iotests.imgfmt, + snapshot_file=imgs[3], + node_name='node0', + snapshot_node_name='node0-overlay') + self.assert_qmp(result, 'return', {}) + + self.vm_d.shutdown() + self.vm_d = None + + # Check the newly created overlay's backing chain + chain = qemu_img_info('--backing-chain', imgs[3]) + for index, image in enumerate(chain): + self.assertEqual(image['filename'], imgs[3 - index]) + + +if __name__ == '__main__': + # These are the image formats that run their open() function from their + # .bdrv_co_invaliate_cache() implementations, so test them + iotests.main(supported_fmts=['qcow2', 'qed'], + supported_protocols=['file']) diff --git a/tests/qemu-iotests/tests/backing-file-invalidation.out b/tests/qemu-iotests/tests/backing-file-invalidation.out new file mode 100644 index 0000000000..ae1213e6f8 --- /dev/null +++ b/tests/qemu-iotests/tests/backing-file-invalidation.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qtest/ac97-test.c b/tests/qtest/ac97-test.c index b084e31bff..74103efdfa 100644 --- a/tests/qtest/ac97-test.c +++ b/tests/qtest/ac97-test.c @@ -28,7 +28,7 @@ static void *ac97_get_driver(void *obj, const char *interface) return &ac97->dev; } - fprintf(stderr, "%s not present in e1000e\n", interface); + fprintf(stderr, "%s not present in ac97\n", interface); g_assert_not_reached(); } diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index f1e510b0ac..66652fed04 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -44,9 +44,9 @@ #define TEST_IMAGE_SIZE_MB_SMALL 64 /*** Globals ***/ -static char tmp_path[] = "/tmp/qtest.XXXXXX"; -static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX"; -static char mig_socket[] = "/tmp/qtest-migration.XXXXXX"; +static char *tmp_path; +static char *debug_path; +static char *mig_socket; static bool ahci_pedantic; static const char *imgfmt; static unsigned test_image_size_mb; @@ -1437,10 +1437,10 @@ static void test_ncq_simple(void) static int prepare_iso(size_t size, unsigned char **buf, char **name) { - char cdrom_path[] = "/tmp/qtest.iso.XXXXXX"; + g_autofree char *cdrom_path = NULL; unsigned char *patt; ssize_t ret; - int fd = mkstemp(cdrom_path); + int fd = g_file_open_tmp("qtest.iso.XXXXXX", &cdrom_path, NULL); g_assert(fd != -1); g_assert(buf); @@ -1833,7 +1833,7 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, int main(int argc, char **argv) { - const char *arch; + const char *arch, *base; int ret; int fd; int c; @@ -1871,8 +1871,22 @@ int main(int argc, char **argv) return 0; } + /* + * "base" stores the starting point where we create temporary files. + * + * On Windows, this is set to the relative path of current working + * directory, because the absolute path causes the blkdebug filename + * parser fail to parse "blkdebug:path/to/config:path/to/image". + */ +#ifndef _WIN32 + base = g_get_tmp_dir(); +#else + base = "."; +#endif + /* Create a temporary image */ - fd = mkstemp(tmp_path); + tmp_path = g_strdup_printf("%s/qtest.XXXXXX", base); + fd = g_mkstemp(tmp_path); g_assert(fd >= 0); if (have_qemu_img()) { imgfmt = "qcow2"; @@ -1889,12 +1903,13 @@ int main(int argc, char **argv) close(fd); /* Create temporary blkdebug instructions */ - fd = mkstemp(debug_path); + debug_path = g_strdup_printf("%s/qtest-blkdebug.XXXXXX", base); + fd = g_mkstemp(debug_path); g_assert(fd >= 0); close(fd); /* Reserve a hollow file to use as a socket for migration tests */ - fd = mkstemp(mig_socket); + fd = g_file_open_tmp("qtest-migration.XXXXXX", &mig_socket, NULL); g_assert(fd >= 0); close(fd); @@ -1947,8 +1962,11 @@ int main(int argc, char **argv) /* Cleanup */ unlink(tmp_path); + g_free(tmp_path); unlink(debug_path); + g_free(debug_path); unlink(mig_socket); + g_free(mig_socket); return ret; } diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c index 05ce941566..c713a3700b 100644 --- a/tests/qtest/aspeed_smc-test.c +++ b/tests/qtest/aspeed_smc-test.c @@ -608,16 +608,15 @@ static void test_write_block_protect_bottom_bit(void) flash_reset(); } -static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX"; - int main(int argc, char **argv) { + g_autofree char *tmp_path = NULL; int ret; int fd; g_test_init(&argc, &argv, NULL); - fd = mkstemp(tmp_path); + fd = g_file_open_tmp("qtest.m25p80.XXXXXX", &tmp_path, NULL); g_assert(fd >= 0); ret = ftruncate(fd, FLASH_SIZE); g_assert(ret == 0); diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 359916c228..2ebeb530b2 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1461,6 +1461,7 @@ static void test_acpi_piix4_tcg_acpi_hmat(void) test_acpi_tcg_acpi_hmat(MACHINE_PC); } +#ifdef CONFIG_POSIX static void test_acpi_erst(const char *machine) { gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XXXXXX", NULL); @@ -1511,6 +1512,7 @@ static void test_acpi_microvm_acpi_erst(void) g_free(tmp_path); free_test_data(&data); } +#endif /* CONFIG_POSIX */ static void test_acpi_virt_tcg(void) { @@ -1551,6 +1553,7 @@ static void test_acpi_q35_viot(void) free_test_data(&data); } +#ifdef CONFIG_POSIX static void test_acpi_q35_cxl(void) { gchar *tmp_path = g_dir_make_tmp("qemu-test-cxl.XXXXXX", NULL); @@ -1593,6 +1596,7 @@ static void test_acpi_q35_cxl(void) g_free(tmp_path); free_test_data(&data); } +#endif /* CONFIG_POSIX */ static void test_acpi_virt_viot(void) { @@ -1611,6 +1615,12 @@ static void test_acpi_virt_viot(void) free_test_data(&data); } +#ifndef _WIN32 +# define DEV_NULL "/dev/null" +#else +# define DEV_NULL "nul" +#endif + static void test_acpi_q35_slic(void) { test_data data = { @@ -1618,9 +1628,9 @@ static void test_acpi_q35_slic(void) .variant = ".slic", }; - test_acpi_one("-acpitable sig=SLIC,oem_id='CRASH ',oem_table_id='ME'," - "oem_rev=00002210,asl_compiler_id='qemu'," - "asl_compiler_rev=00000000,data=/dev/null", + test_acpi_one("-acpitable sig=SLIC,oem_id=\"CRASH \",oem_table_id=ME," + "oem_rev=00002210,asl_compiler_id=qemu," + "asl_compiler_rev=00000000,data=" DEV_NULL, &data); free_test_data(&data); } @@ -1632,7 +1642,9 @@ static void test_acpi_q35_applesmc(void) .variant = ".applesmc", }; - test_acpi_one("-device isa-applesmc", &data); + /* supply fake 64-byte OSK to silence missing key warning */ + test_acpi_one("-device isa-applesmc,osk=any64characterfakeoskisenough" + "topreventinvalidkeywarningsonstderr", &data); free_test_data(&data); } @@ -1665,7 +1677,7 @@ static void test_oem_fields(test_data *data) } } -static void test_acpi_oem_fields_pc(void) +static void test_acpi_piix4_oem_fields(void) { test_data data; char *args; @@ -1685,7 +1697,7 @@ static void test_acpi_oem_fields_pc(void) g_free(args); } -static void test_acpi_oem_fields_q35(void) +static void test_acpi_q35_oem_fields(void) { test_data data; char *args; @@ -1705,7 +1717,7 @@ static void test_acpi_oem_fields_q35(void) g_free(args); } -static void test_acpi_oem_fields_microvm(void) +static void test_acpi_microvm_oem_fields(void) { test_data data; char *args; @@ -1722,7 +1734,7 @@ static void test_acpi_oem_fields_microvm(void) g_free(args); } -static void test_acpi_oem_fields_virt(void) +static void test_acpi_virt_oem_fields(void) { test_data data = { .machine = "virt", @@ -1760,79 +1772,102 @@ int main(int argc, char *argv[]) if (ret) { return ret; } - qtest_add_func("acpi/q35/oem-fields", test_acpi_oem_fields_q35); - if (tpm_model_is_available("-machine q35", "tpm-tis")) { - qtest_add_func("acpi/q35/tpm2-tis", test_acpi_q35_tcg_tpm2_tis); - qtest_add_func("acpi/q35/tpm12-tis", test_acpi_q35_tcg_tpm12_tis); + if (qtest_has_machine(MACHINE_PC)) { + qtest_add_func("acpi/piix4", test_acpi_piix4_tcg); + qtest_add_func("acpi/piix4/oem-fields", test_acpi_piix4_oem_fields); + qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge); + qtest_add_func("acpi/piix4/pci-hotplug/no_root_hotplug", + test_acpi_piix4_no_root_hotplug); + qtest_add_func("acpi/piix4/pci-hotplug/no_bridge_hotplug", + test_acpi_piix4_no_bridge_hotplug); + qtest_add_func("acpi/piix4/pci-hotplug/off", + test_acpi_piix4_no_acpi_pci_hotplug); + qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi); + qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp); + qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp); + qtest_add_func("acpi/piix4/numamem", test_acpi_piix4_tcg_numamem); + qtest_add_func("acpi/piix4/nosmm", test_acpi_piix4_tcg_nosmm); + qtest_add_func("acpi/piix4/smm-compat", + test_acpi_piix4_tcg_smm_compat); + qtest_add_func("acpi/piix4/smm-compat-nosmm", + test_acpi_piix4_tcg_smm_compat_nosmm); + qtest_add_func("acpi/piix4/nohpet", test_acpi_piix4_tcg_nohpet); + qtest_add_func("acpi/piix4/dimmpxm", test_acpi_piix4_tcg_dimm_pxm); + qtest_add_func("acpi/piix4/acpihmat", + test_acpi_piix4_tcg_acpi_hmat); +#ifdef CONFIG_POSIX + qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst); +#endif } - qtest_add_func("acpi/piix4", test_acpi_piix4_tcg); - qtest_add_func("acpi/oem-fields", test_acpi_oem_fields_pc); - qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge); - qtest_add_func("acpi/piix4/pci-hotplug/no_root_hotplug", - test_acpi_piix4_no_root_hotplug); - qtest_add_func("acpi/piix4/pci-hotplug/no_bridge_hotplug", - test_acpi_piix4_no_bridge_hotplug); - qtest_add_func("acpi/piix4/pci-hotplug/off", - test_acpi_piix4_no_acpi_pci_hotplug); - qtest_add_func("acpi/q35", test_acpi_q35_tcg); - qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge); - qtest_add_func("acpi/q35/multif-bridge", test_acpi_q35_multif_bridge); - qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64); - qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi); - qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi); - qtest_add_func("acpi/q35/smbus/ipmi", test_acpi_q35_tcg_smbus_ipmi); - qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp); - qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp); - qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp); - qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp); - qtest_add_func("acpi/piix4/numamem", test_acpi_piix4_tcg_numamem); - qtest_add_func("acpi/q35/numamem", test_acpi_q35_tcg_numamem); - qtest_add_func("acpi/piix4/nosmm", test_acpi_piix4_tcg_nosmm); - qtest_add_func("acpi/piix4/smm-compat", - test_acpi_piix4_tcg_smm_compat); - qtest_add_func("acpi/piix4/smm-compat-nosmm", - test_acpi_piix4_tcg_smm_compat_nosmm); - qtest_add_func("acpi/piix4/nohpet", test_acpi_piix4_tcg_nohpet); - qtest_add_func("acpi/q35/nosmm", test_acpi_q35_tcg_nosmm); - qtest_add_func("acpi/q35/smm-compat", - test_acpi_q35_tcg_smm_compat); - qtest_add_func("acpi/q35/smm-compat-nosmm", - test_acpi_q35_tcg_smm_compat_nosmm); - qtest_add_func("acpi/q35/nohpet", test_acpi_q35_tcg_nohpet); - qtest_add_func("acpi/piix4/dimmpxm", test_acpi_piix4_tcg_dimm_pxm); - qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); - qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat); - qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); - qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst); - qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst); - qtest_add_func("acpi/q35/applesmc", test_acpi_q35_applesmc); - qtest_add_func("acpi/q35/pvpanic-isa", test_acpi_q35_pvpanic_isa); - qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); - qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg); - qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg); - qtest_add_func("acpi/microvm/ioapic2", test_acpi_microvm_ioapic2_tcg); - qtest_add_func("acpi/microvm/oem-fields", test_acpi_oem_fields_microvm); - if (has_tcg) { - qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs); - if (strcmp(arch, "x86_64") == 0) { - qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg); - qtest_add_func("acpi/microvm/acpierst", test_acpi_microvm_acpi_erst); + if (qtest_has_machine(MACHINE_Q35)) { + qtest_add_func("acpi/q35", test_acpi_q35_tcg); + qtest_add_func("acpi/q35/oem-fields", test_acpi_q35_oem_fields); + if (tpm_model_is_available("-machine q35", "tpm-tis")) { + qtest_add_func("acpi/q35/tpm2-tis", test_acpi_q35_tcg_tpm2_tis); + qtest_add_func("acpi/q35/tpm12-tis", + test_acpi_q35_tcg_tpm12_tis); + } + qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge); + qtest_add_func("acpi/q35/multif-bridge", + test_acpi_q35_multif_bridge); + qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64); + qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi); + qtest_add_func("acpi/q35/smbus/ipmi", test_acpi_q35_tcg_smbus_ipmi); + qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp); + qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp); + qtest_add_func("acpi/q35/numamem", test_acpi_q35_tcg_numamem); + qtest_add_func("acpi/q35/nosmm", test_acpi_q35_tcg_nosmm); + qtest_add_func("acpi/q35/smm-compat", + test_acpi_q35_tcg_smm_compat); + qtest_add_func("acpi/q35/smm-compat-nosmm", + test_acpi_q35_tcg_smm_compat_nosmm); + qtest_add_func("acpi/q35/nohpet", test_acpi_q35_tcg_nohpet); + qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); + qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); +#ifdef CONFIG_POSIX + qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst); +#endif + qtest_add_func("acpi/q35/applesmc", test_acpi_q35_applesmc); + qtest_add_func("acpi/q35/pvpanic-isa", test_acpi_q35_pvpanic_isa); + if (has_tcg) { + qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs); + } + if (has_kvm) { + qtest_add_func("acpi/q35/kvm/xapic", test_acpi_q35_kvm_xapic); + qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar); + } + qtest_add_func("acpi/q35/viot", test_acpi_q35_viot); +#ifdef CONFIG_POSIX + qtest_add_func("acpi/q35/cxl", test_acpi_q35_cxl); +#endif + qtest_add_func("acpi/q35/slic", test_acpi_q35_slic); + } + if (qtest_has_machine("microvm")) { + qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); + qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg); + qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg); + qtest_add_func("acpi/microvm/ioapic2", + test_acpi_microvm_ioapic2_tcg); + qtest_add_func("acpi/microvm/oem-fields", + test_acpi_microvm_oem_fields); + if (has_tcg) { + if (strcmp(arch, "x86_64") == 0) { + qtest_add_func("acpi/microvm/pcie", + test_acpi_microvm_pcie_tcg); +#ifdef CONFIG_POSIX + qtest_add_func("acpi/microvm/acpierst", + test_acpi_microvm_acpi_erst); +#endif + } } } - if (has_kvm) { - qtest_add_func("acpi/q35/kvm/xapic", test_acpi_q35_kvm_xapic); - qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar); - } - qtest_add_func("acpi/q35/viot", test_acpi_q35_viot); - qtest_add_func("acpi/q35/cxl", test_acpi_q35_cxl); - qtest_add_func("acpi/q35/slic", test_acpi_q35_slic); } else if (strcmp(arch, "aarch64") == 0) { if (has_tcg) { qtest_add_func("acpi/virt", test_acpi_virt_tcg); qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem); qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp); qtest_add_func("acpi/virt/pxb", test_acpi_virt_tcg_pxb); - qtest_add_func("acpi/virt/oem-fields", test_acpi_oem_fields_virt); + qtest_add_func("acpi/virt/oem-fields", test_acpi_virt_oem_fields); qtest_add_func("acpi/virt/viot", test_acpi_virt_viot); } } diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c index 2f99d71cab..b216519b62 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -224,15 +224,16 @@ static bool check_guest_output(QTestState *qts, const testdef_t *test, int fd) static void test_machine(const void *data) { const testdef_t *test = data; - char serialtmp[] = "/tmp/qtest-boot-serial-sXXXXXX"; - char codetmp[] = "/tmp/qtest-boot-serial-cXXXXXX"; + g_autofree char *serialtmp = NULL; + g_autofree char *codetmp = NULL; const char *codeparam = ""; const uint8_t *code = NULL; QTestState *qts; int ser_fd; - ser_fd = mkstemp(serialtmp); + ser_fd = g_file_open_tmp("qtest-boot-serial-sXXXXXX", &serialtmp, NULL); g_assert(ser_fd != -1); + close(ser_fd); if (test->kernel) { code = test->kernel; @@ -246,7 +247,7 @@ static void test_machine(const void *data) ssize_t wlen; int code_fd; - code_fd = mkstemp(codetmp); + code_fd = g_file_open_tmp("qtest-boot-serial-cXXXXXX", &codetmp, NULL); g_assert(code_fd != -1); wlen = write(code_fd, code, test->codesize); g_assert(wlen == test->codesize); @@ -266,6 +267,8 @@ static void test_machine(const void *data) unlink(codetmp); } + ser_fd = open(serialtmp, O_RDONLY); + g_assert(ser_fd != -1); if (!check_guest_output(qts, test, ser_fd)) { g_error("Failed to find expected string. Please check '%s'", serialtmp); diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c index a7766a9e65..26a2400181 100644 --- a/tests/qtest/cdrom-test.c +++ b/tests/qtest/cdrom-test.c @@ -52,7 +52,7 @@ static int prepare_image(const char *arch, char *isoimage) perror("Error creating temporary iso image file"); return -1; } - if (!mkdtemp(srcdir)) { + if (!g_mkdtemp(srcdir)) { perror("Error creating temporary directory"); goto cleanup; } diff --git a/tests/qtest/cxl-test.c b/tests/qtest/cxl-test.c index 2133e973f4..cbe0fb549b 100644 --- a/tests/qtest/cxl-test.c +++ b/tests/qtest/cxl-test.c @@ -89,13 +89,13 @@ static void cxl_2root_port(void) qtest_end(); } +#ifdef CONFIG_POSIX static void cxl_t3d(void) { g_autoptr(GString) cmdline = g_string_new(NULL); - char template[] = "/tmp/cxl-test-XXXXXX"; - const char *tmpfs; + g_autofree const char *tmpfs = NULL; - tmpfs = mkdtemp(template); + tmpfs = g_dir_make_tmp("cxl-test-XXXXXX", NULL); g_string_printf(cmdline, QEMU_PXB_CMD QEMU_RP QEMU_T3D, tmpfs, tmpfs); @@ -106,10 +106,9 @@ static void cxl_t3d(void) static void cxl_1pxb_2rp_2t3d(void) { g_autoptr(GString) cmdline = g_string_new(NULL); - char template[] = "/tmp/cxl-test-XXXXXX"; - const char *tmpfs; + g_autofree const char *tmpfs = NULL; - tmpfs = mkdtemp(template); + tmpfs = g_dir_make_tmp("cxl-test-XXXXXX", NULL); g_string_printf(cmdline, QEMU_PXB_CMD QEMU_2RP QEMU_2T3D, tmpfs, tmpfs, tmpfs, tmpfs); @@ -121,10 +120,9 @@ static void cxl_1pxb_2rp_2t3d(void) static void cxl_2pxb_4rp_4t3d(void) { g_autoptr(GString) cmdline = g_string_new(NULL); - char template[] = "/tmp/cxl-test-XXXXXX"; - const char *tmpfs; + g_autofree const char *tmpfs = NULL; - tmpfs = mkdtemp(template); + tmpfs = g_dir_make_tmp("cxl-test-XXXXXX", NULL); g_string_printf(cmdline, QEMU_2PXB_CMD QEMU_4RP QEMU_4T3D, tmpfs, tmpfs, tmpfs, tmpfs, tmpfs, tmpfs, @@ -133,6 +131,7 @@ static void cxl_2pxb_4rp_4t3d(void) qtest_start(cmdline->str); qtest_end(); } +#endif /* CONFIG_POSIX */ int main(int argc, char **argv) { @@ -144,8 +143,10 @@ int main(int argc, char **argv) qtest_add_func("/pci/cxl/pxb_x2_with_window", cxl_2pxb_with_window); qtest_add_func("/pci/cxl/rp", cxl_root_port); qtest_add_func("/pci/cxl/rp_x2", cxl_2root_port); +#ifdef CONFIG_POSIX qtest_add_func("/pci/cxl/type3_device", cxl_t3d); qtest_add_func("/pci/cxl/rp_x2_type3_x2", cxl_1pxb_2rp_2t3d); qtest_add_func("/pci/cxl/pxb_x2_root_port_x4_type3_x4", cxl_2pxb_4rp_4t3d); +#endif return g_test_run(); } diff --git a/tests/qtest/dbus-display-test.c b/tests/qtest/dbus-display-test.c index 8be5974763..cb1b62d1d1 100644 --- a/tests/qtest/dbus-display-test.c +++ b/tests/qtest/dbus-display-test.c @@ -3,7 +3,7 @@ #include #include #include "libqtest.h" -#include "dbus-display1.h" +#include "ui/dbus-display1.h" static GDBusConnection* test_dbus_p2p_from_fd(int fd) diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c index 2e3137843e..e595b45b66 100644 --- a/tests/qtest/device-plug-test.c +++ b/tests/qtest/device-plug-test.c @@ -61,6 +61,18 @@ static void wait_device_deleted_event(QTestState *qtest, const char *id) } } +static void process_device_remove(QTestState *qtest, const char *id) +{ + /* + * Request device removal. As the guest is not running, the request won't + * be processed. However during system reset, the removal will be + * handled, removing the device. + */ + device_del(qtest, id); + system_reset(qtest); + wait_device_deleted_event(qtest, id); +} + static void test_pci_unplug_request(void) { const char *arch = qtest_get_arch(); @@ -73,14 +85,7 @@ static void test_pci_unplug_request(void) QTestState *qtest = qtest_initf("%s -device virtio-mouse-pci,id=dev0", machine_addition); - /* - * Request device removal. As the guest is not running, the request won't - * be processed. However during system reset, the removal will be - * handled, removing the device. - */ - device_del(qtest, "dev0"); - system_reset(qtest); - wait_device_deleted_event(qtest, "dev0"); + process_device_remove(qtest, "dev0"); qtest_quit(qtest); } @@ -95,17 +100,10 @@ static void test_pci_unplug_json_request(void) } QTestState *qtest = qtest_initf( - "%s -device '{\"driver\": \"virtio-mouse-pci\", \"id\": \"dev0\"}'", + "%s -device \"{'driver': 'virtio-mouse-pci', 'id': 'dev0'}\"", machine_addition); - /* - * Request device removal. As the guest is not running, the request won't - * be processed. However during system reset, the removal will be - * handled, removing the device. - */ - device_del(qtest, "dev0"); - system_reset(qtest); - wait_device_deleted_event(qtest, "dev0"); + process_device_remove(qtest, "dev0"); qtest_quit(qtest); } @@ -128,9 +126,7 @@ static void test_spapr_cpu_unplug_request(void) "-device power9_v2.0-spapr-cpu-core,core-id=1,id=dev0"); /* similar to test_pci_unplug_request */ - device_del(qtest, "dev0"); - system_reset(qtest); - wait_device_deleted_event(qtest, "dev0"); + process_device_remove(qtest, "dev0"); qtest_quit(qtest); } @@ -144,9 +140,7 @@ static void test_spapr_memory_unplug_request(void) "-device pc-dimm,id=dev0,memdev=mem0"); /* similar to test_pci_unplug_request */ - device_del(qtest, "dev0"); - system_reset(qtest); - wait_device_deleted_event(qtest, "dev0"); + process_device_remove(qtest, "dev0"); qtest_quit(qtest); } @@ -158,9 +152,7 @@ static void test_spapr_phb_unplug_request(void) qtest = qtest_initf("-device spapr-pci-host-bridge,index=1,id=dev0"); /* similar to test_pci_unplug_request */ - device_del(qtest, "dev0"); - system_reset(qtest); - wait_device_deleted_event(qtest, "dev0"); + process_device_remove(qtest, "dev0"); qtest_quit(qtest); } diff --git a/tests/qtest/e1000-test.c b/tests/qtest/e1000-test.c index c387984ef6..4e0d7a5607 100644 --- a/tests/qtest/e1000-test.c +++ b/tests/qtest/e1000-test.c @@ -35,7 +35,7 @@ static void *e1000_get_driver(void *obj, const char *interface) return &e1000->dev; } - fprintf(stderr, "%s not present in e1000e\n", interface); + fprintf(stderr, "%s not present in e1000\n", interface); g_assert_not_reached(); } diff --git a/tests/qtest/e1000e-test.c b/tests/qtest/e1000e-test.c index c98779c7c0..4cdd8238f2 100644 --- a/tests/qtest/e1000e-test.c +++ b/tests/qtest/e1000e-test.c @@ -31,7 +31,7 @@ #include "qemu/iov.h" #include "qemu/module.h" #include "qemu/bitops.h" -#include "libqos/malloc.h" +#include "libqos/libqos-malloc.h" #include "libqos/e1000e.h" static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc) diff --git a/tests/qtest/es1370-test.c b/tests/qtest/es1370-test.c index adccdac1be..97ab65c435 100644 --- a/tests/qtest/es1370-test.c +++ b/tests/qtest/es1370-test.c @@ -28,7 +28,7 @@ static void *es1370_get_driver(void *obj, const char *interface) return &es1370->dev; } - fprintf(stderr, "%s not present in e1000e\n", interface); + fprintf(stderr, "%s not present in es1370\n", interface); g_assert_not_reached(); } diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c index 52ade90a7d..1f9b99ad6d 100644 --- a/tests/qtest/fdc-test.c +++ b/tests/qtest/fdc-test.c @@ -68,7 +68,7 @@ enum { DSKCHG = 0x80, }; -static char test_image[] = "/tmp/qtest.XXXXXX"; +static char *test_image; #define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) #define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0) @@ -608,7 +608,7 @@ int main(int argc, char **argv) int ret; /* Create a temporary raw image */ - fd = mkstemp(test_image); + fd = g_file_open_tmp("qtest.XXXXXX", &test_image, NULL); g_assert(fd >= 0); ret = ftruncate(fd, TEST_IMAGE_SIZE); g_assert(ret == 0); @@ -640,6 +640,7 @@ int main(int argc, char **argv) /* Cleanup */ qtest_end(); unlink(test_image); + g_free(test_image); return ret; } diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c index b23d3ecf45..434c16bf42 100644 --- a/tests/qtest/fuzz-lsi53c895a-test.c +++ b/tests/qtest/fuzz-lsi53c895a-test.c @@ -21,7 +21,7 @@ static void test_lsi_do_msgout_cancel_req(void) return; } - s = qtest_init("-M q35 -m 4G -display none -nodefaults " + s = qtest_init("-M q35 -m 2G -display none -nodefaults " "-device lsi53c895a,id=scsi " "-device scsi-hd,drive=disk0 " "-drive file=null-co://,id=disk0,if=none,format=raw"); diff --git a/tests/qtest/fuzz-sb16-test.c b/tests/qtest/fuzz-sb16-test.c index a65826b943..add2a2ad39 100644 --- a/tests/qtest/fuzz-sb16-test.c +++ b/tests/qtest/fuzz-sb16-test.c @@ -57,9 +57,13 @@ int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); - qtest_add_func("fuzz/test_fuzz_sb16/1c", test_fuzz_sb16_0x1c); - qtest_add_func("fuzz/test_fuzz_sb16/91", test_fuzz_sb16_0x91); - qtest_add_func("fuzz/test_fuzz_sb16/d4", test_fuzz_sb16_0xd4); + if (qtest_has_machine("q35")) { + qtest_add_func("fuzz/test_fuzz_sb16/1c", test_fuzz_sb16_0x1c); + } + if (qtest_has_machine("pc")) { + qtest_add_func("fuzz/test_fuzz_sb16/91", test_fuzz_sb16_0x91); + qtest_add_func("fuzz/test_fuzz_sb16/d4", test_fuzz_sb16_0xd4); + } return g_test_run(); } diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 2b3bc1fb9d..eb7520544b 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -218,7 +218,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) g_free(pretty_cmd_line); } - qemu_init(result.we_wordc, result.we_wordv, NULL); + qemu_init(result.we_wordc, result.we_wordv); /* re-enable the rcu atfork, which was previously disabled in qemu_init */ rcu_enable_atfork(); diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index 447ffe8178..afc1d20355 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -994,16 +994,16 @@ static GString *generic_fuzz_predefined_config_cmdline(FuzzTarget *t) g_assert(t->opaque); config = t->opaque; - setenv("QEMU_AVOID_DOUBLE_FETCH", "1", 1); + g_setenv("QEMU_AVOID_DOUBLE_FETCH", "1", 1); if (config->argfunc) { args = config->argfunc(); - setenv("QEMU_FUZZ_ARGS", args, 1); + g_setenv("QEMU_FUZZ_ARGS", args, 1); g_free(args); } else { g_assert_nonnull(config->args); - setenv("QEMU_FUZZ_ARGS", config->args, 1); + g_setenv("QEMU_FUZZ_ARGS", config->args, 1); } - setenv("QEMU_FUZZ_OBJECTS", config->objects, 1); + g_setenv("QEMU_FUZZ_OBJECTS", config->objects, 1); return generic_fuzz_cmdline(t); } diff --git a/tests/qtest/fuzz/generic_fuzz_configs.h b/tests/qtest/fuzz/generic_fuzz_configs.h index 004c701915..a825b78c14 100644 --- a/tests/qtest/fuzz/generic_fuzz_configs.h +++ b/tests/qtest/fuzz/generic_fuzz_configs.h @@ -20,8 +20,8 @@ typedef struct generic_fuzz_config { } generic_fuzz_config; static inline gchar *generic_fuzzer_virtio_9p_args(void){ - char tmpdir[] = "/tmp/qemu-fuzz.XXXXXX"; - g_assert_nonnull(mkdtemp(tmpdir)); + g_autofree char *tmpdir = g_dir_make_tmp("qemu-fuzz.XXXXXX", NULL); + g_assert_nonnull(tmpdir); return g_strdup_printf("-machine q35 -nodefaults " "-device virtio-9p,fsdev=hshare,mount_tag=hshare " diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index c856d3d500..3a3d9c16dd 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -23,7 +23,7 @@ #include "qemu/main-loop.h" #include "tests/qtest/libqtest.h" -#include "tests/qtest/libqos/malloc.h" +#include "tests/qtest/libqos/libqos-malloc.h" #include "tests/qtest/libqos/qgraph.h" #include "tests/qtest/libqos/qgraph_internal.h" #include "tests/qtest/libqos/qos_external.h" diff --git a/tests/qtest/fuzz/virtio_blk_fuzz.c b/tests/qtest/fuzz/virtio_blk_fuzz.c index 236d078cc8..a9fb9ecf6c 100644 --- a/tests/qtest/fuzz/virtio_blk_fuzz.c +++ b/tests/qtest/fuzz/virtio_blk_fuzz.c @@ -181,10 +181,10 @@ static void drive_destroy(void *path) static char *drive_create(void) { int fd, ret; - char *t_path = g_strdup("/tmp/qtest.XXXXXX"); + char *t_path; /* Create a temporary raw image */ - fd = mkstemp(t_path); + fd = g_file_open_tmp("qtest.XXXXXX", &t_path, NULL); g_assert_cmpint(fd, >=, 0); ret = ftruncate(fd, TEST_IMAGE_SIZE); g_assert_cmpint(ret, ==, 0); diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c index 413cf964c0..ba772f4d7a 100644 --- a/tests/qtest/hd-geo-test.c +++ b/tests/qtest/hd-geo-test.c @@ -27,16 +27,16 @@ static char *create_test_img(int secs) { - char *template = strdup("/tmp/qtest.XXXXXX"); + char *template; int fd, ret; - fd = mkstemp(template); + fd = g_file_open_tmp("qtest.XXXXXX", &template, NULL); g_assert(fd >= 0); ret = ftruncate(fd, (off_t)secs * 512); close(fd); if (ret) { - free(template); + g_free(template); template = NULL; } @@ -422,9 +422,8 @@ static MBRpartitions empty_mbr = { {false, 0, 0, 0, 0, 0, 0, 0, 0}, static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors) { - const char *template = "/tmp/qtest.XXXXXX"; - char *raw_path = strdup(template); - char *qcow2_path = strdup(template); + g_autofree char *raw_path = NULL; + char *qcow2_path; char cmd[100 + 2 * PATH_MAX]; uint8_t buf[512] = {}; int i, ret, fd, offset; @@ -468,7 +467,7 @@ static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors) offset += 0x10; } - fd = mkstemp(raw_path); + fd = g_file_open_tmp("qtest.XXXXXX", &raw_path, NULL); g_assert(fd >= 0); close(fd); @@ -478,7 +477,7 @@ static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors) g_assert(ret == sizeof(buf)); close(fd); - fd = mkstemp(qcow2_path); + fd = g_file_open_tmp("qtest.XXXXXX", &qcow2_path, NULL); g_assert(fd >= 0); close(fd); @@ -506,7 +505,6 @@ static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors) free(qemu_img_abs_path); unlink(raw_path); - free(raw_path); return qcow2_path; } @@ -714,7 +712,7 @@ static void test_override(TestArgs *args, CHSResult expected[]) for (i = 0; i < args->n_drives; i++) { unlink(args->drives[i]); - free(args->drives[i]); + g_free(args->drives[i]); } g_free(args->drives); g_strfreev(args->argv); @@ -867,7 +865,7 @@ static void test_override_scsi_hot_unplug(void) for (i = 0; i < args->n_drives; i++) { unlink(args->drives[i]); - free(args->drives[i]); + g_free(args->drives[i]); } g_free(args->drives); g_strfreev(args->argv); @@ -927,7 +925,7 @@ static void test_override_virtio_hot_unplug(void) for (i = 0; i < args->n_drives; i++) { unlink(args->drives[i]); - free(args->drives[i]); + g_free(args->drives[i]); } g_free(args->drives); g_strfreev(args->argv); @@ -987,7 +985,7 @@ test_add_done: for (i = 0; i < backend_last; i++) { if (img_file_name[i]) { unlink(img_file_name[i]); - free(img_file_name[i]); + g_free(img_file_name[i]); } } diff --git a/tests/qtest/i440fx-test.c b/tests/qtest/i440fx-test.c index 6d7d4d8d8f..795fd85343 100644 --- a/tests/qtest/i440fx-test.c +++ b/tests/qtest/i440fx-test.c @@ -281,51 +281,31 @@ static void test_i440fx_pam(gconstpointer opaque) #define BLOB_SIZE ((size_t)65536) #define ISA_BIOS_MAXSZ ((size_t)(128 * 1024)) -/* Create a blob file, and return its absolute pathname as a dynamically +/* + * Create a blob file, and return its absolute pathname as a dynamically * allocated string. * The file is closed before the function returns. - * In case of error, NULL is returned. The function prints the error message. + * In case of error, the function aborts and prints the error message. */ static char *create_blob_file(void) { - int ret, fd; + int i, fd; char *pathname; GError *error = NULL; + g_autofree uint8_t *buf = g_malloc(BLOB_SIZE); - ret = -1; fd = g_file_open_tmp("blob_XXXXXX", &pathname, &error); - if (fd == -1) { - fprintf(stderr, "unable to create blob file: %s\n", error->message); - g_error_free(error); - } else { - if (ftruncate(fd, BLOB_SIZE) == -1) { - fprintf(stderr, "ftruncate(\"%s\", %zu): %s\n", pathname, - BLOB_SIZE, strerror(errno)); - } else { - void *buf; + g_assert_no_error(error); + close(fd); - buf = mmap(NULL, BLOB_SIZE, PROT_WRITE, MAP_SHARED, fd, 0); - if (buf == MAP_FAILED) { - fprintf(stderr, "mmap(\"%s\", %zu): %s\n", pathname, BLOB_SIZE, - strerror(errno)); - } else { - size_t i; - - for (i = 0; i < BLOB_SIZE; ++i) { - ((uint8_t *)buf)[i] = i; - } - munmap(buf, BLOB_SIZE); - ret = 0; - } - } - close(fd); - if (ret == -1) { - unlink(pathname); - g_free(pathname); - } + for (i = 0; i < BLOB_SIZE; i++) { + buf[i] = i; } - return ret == -1 ? NULL : pathname; + g_file_set_contents(pathname, (char *)buf, BLOB_SIZE, &error); + g_assert_no_error(error); + + return pathname; } static void test_i440fx_firmware(FirmwareTestFixture *fixture, diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index 5bcb75a7e5..dbe1563b23 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -90,6 +90,7 @@ enum { enum { CMD_DSM = 0x06, + CMD_DIAGNOSE = 0x90, CMD_READ_DMA = 0xc8, CMD_WRITE_DMA = 0xca, CMD_FLUSH_CACHE = 0xe7, @@ -121,8 +122,8 @@ enum { static QPCIBus *pcibus = NULL; static QGuestAllocator guest_malloc; -static char tmp_path[] = "/tmp/qtest.XXXXXX"; -static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX"; +static char *tmp_path[2]; +static char *debug_path; static QTestState *ide_test_start(const char *cmdline_fmt, ...) { @@ -310,7 +311,7 @@ static QTestState *test_bmdma_setup(void) qts = ide_test_start( "-drive file=%s,if=ide,cache=writeback,format=raw " "-global ide-hd.serial=%s -global ide-hd.ver=%s", - tmp_path, "testdisk", "version"); + tmp_path[0], "testdisk", "version"); qtest_irq_intercept_in(qts, "ioapic"); return qts; @@ -574,7 +575,7 @@ static void test_identify(void) qts = ide_test_start( "-drive file=%s,if=ide,cache=writeback,format=raw " "-global ide-hd.serial=%s -global ide-hd.ver=%s", - tmp_path, "testdisk", "version"); + tmp_path[0], "testdisk", "version"); dev = get_pci_device(qts, &bmdma_bar, &ide_bar); @@ -614,6 +615,36 @@ static void test_identify(void) free_pci_device(dev); } +static void test_diagnostic(void) +{ + QTestState *qts; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + uint8_t data; + + qts = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s " + "-blockdev driver=file,node-name=hdb,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 " + "-device ide-hd,drive=hdb,bus=ide.0,unit=1 ", + tmp_path[0], tmp_path[1]); + + dev = get_pci_device(qts, &bmdma_bar, &ide_bar); + + /* DIAGNOSE command on device 1 */ + qpci_io_writeb(dev, ide_bar, reg_device, DEV); + data = qpci_io_readb(dev, ide_bar, reg_device); + g_assert_cmphex(data & DEV, ==, DEV); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_DIAGNOSE); + + /* Verify that DEVICE is now 0 */ + data = qpci_io_readb(dev, ide_bar, reg_device); + g_assert_cmphex(data & DEV, ==, 0); + + ide_test_quit(qts); + free_pci_device(dev); +} + /* * Write sector 1 with random data to make IDE storage dirty * Needed for flush tests so that flushes actually go though the block layer @@ -662,7 +693,7 @@ static void test_flush(void) qts = ide_test_start( "-drive file=blkdebug::%s,if=ide,cache=writeback,format=raw", - tmp_path); + tmp_path[0]); dev = get_pci_device(qts, &bmdma_bar, &ide_bar); @@ -713,7 +744,7 @@ static void test_pci_retry_flush(void) qts = ide_test_start( "-drive file=blkdebug:%s:%s,if=ide,cache=writeback,format=raw," "rerror=stop,werror=stop", - debug_path, tmp_path); + debug_path, tmp_path[0]); dev = get_pci_device(qts, &bmdma_bar, &ide_bar); @@ -892,14 +923,14 @@ static void cdrom_pio_impl(int nblocks) /* Prepopulate the CDROM with an interesting pattern */ generate_pattern(pattern, patt_len, ATAPI_BLOCK_SIZE); - fh = fopen(tmp_path, "w+"); + fh = fopen(tmp_path[0], "wb+"); ret = fwrite(pattern, ATAPI_BLOCK_SIZE, patt_blocks, fh); g_assert_cmpint(ret, ==, patt_blocks); fclose(fh); qts = ide_test_start( "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 " - "-device ide-cd,drive=sr0,bus=ide.0", tmp_path); + "-device ide-cd,drive=sr0,bus=ide.0", tmp_path[0]); dev = get_pci_device(qts, &bmdma_bar, &ide_bar); qtest_irq_intercept_in(qts, "ioapic"); @@ -985,7 +1016,7 @@ static void test_cdrom_dma(void) qts = ide_test_start( "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 " - "-device ide-cd,drive=sr0,bus=ide.0", tmp_path); + "-device ide-cd,drive=sr0,bus=ide.0", tmp_path[0]); qtest_irq_intercept_in(qts, "ioapic"); guest_buf = guest_alloc(&guest_malloc, len); @@ -993,7 +1024,7 @@ static void test_cdrom_dma(void) prdt[0].size = cpu_to_le32(len | PRDT_EOT); generate_pattern(pattern, ATAPI_BLOCK_SIZE * 16, ATAPI_BLOCK_SIZE); - fh = fopen(tmp_path, "w+"); + fh = fopen(tmp_path[0], "wb+"); ret = fwrite(pattern, ATAPI_BLOCK_SIZE, 16, fh); g_assert_cmpint(ret, ==, 16); fclose(fh); @@ -1011,26 +1042,47 @@ static void test_cdrom_dma(void) int main(int argc, char **argv) { + const char *base; + int i; int fd; int ret; + /* + * "base" stores the starting point where we create temporary files. + * + * On Windows, this is set to the relative path of current working + * directory, because the absolute path causes the blkdebug filename + * parser fail to parse "blkdebug:path/to/config:path/to/image". + */ +#ifndef _WIN32 + base = g_get_tmp_dir(); +#else + base = "."; +#endif + /* Create temporary blkdebug instructions */ - fd = mkstemp(debug_path); + debug_path = g_strdup_printf("%s/qtest-blkdebug.XXXXXX", base); + fd = g_mkstemp(debug_path); g_assert(fd >= 0); close(fd); /* Create a temporary raw image */ - fd = mkstemp(tmp_path); - g_assert(fd >= 0); - ret = ftruncate(fd, TEST_IMAGE_SIZE); - g_assert(ret == 0); - close(fd); + for (i = 0; i < 2; ++i) { + tmp_path[i] = g_strdup_printf("%s/qtest.XXXXXX", base); + fd = g_mkstemp(tmp_path[i]); + g_assert(fd >= 0); + ret = ftruncate(fd, TEST_IMAGE_SIZE); + g_assert(ret == 0); + close(fd); + } /* Run the tests */ g_test_init(&argc, &argv, NULL); qtest_add_func("/ide/identify", test_identify); + qtest_add_func("/ide/diagnostic", test_diagnostic); + qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw); qtest_add_func("/ide/bmdma/trim", test_bmdma_trim); qtest_add_func("/ide/bmdma/various_prdts", test_bmdma_various_prdts); @@ -1048,8 +1100,12 @@ int main(int argc, char **argv) ret = g_test_run(); /* Cleanup */ - unlink(tmp_path); + for (i = 0; i < 2; ++i) { + unlink(tmp_path[i]); + g_free(tmp_path[i]); + } unlink(debug_path); + g_free(debug_path); return ret; } diff --git a/tests/qtest/intel-hda-test.c b/tests/qtest/intel-hda-test.c index a58c98e4d1..d4a8db6fd6 100644 --- a/tests/qtest/intel-hda-test.c +++ b/tests/qtest/intel-hda-test.c @@ -18,7 +18,7 @@ /* Tests only initialization so far. TODO: Replace with functional tests */ static void ich6_test(void) { - qtest_start("-device intel-hda,id=" HDA_ID CODEC_DEVICES); + qtest_start("-machine pc -device intel-hda,id=" HDA_ID CODEC_DEVICES); qtest_end(); } @@ -65,9 +65,12 @@ static void test_issue542_ich6(void) int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); - qtest_add_func("/intel-hda/ich6", ich6_test); - qtest_add_func("/intel-hda/ich9", ich9_test); - qtest_add_func("/intel-hda/fuzz/issue542", test_issue542_ich6); - + if (qtest_has_machine("pc")) { + qtest_add_func("/intel-hda/ich6", ich6_test); + } + if (qtest_has_machine("q35")) { + qtest_add_func("/intel-hda/ich9", ich9_test); + qtest_add_func("/intel-hda/fuzz/issue542", test_issue542_ich6); + } return g_test_run(); } diff --git a/tests/qtest/ivshmem-test.c b/tests/qtest/ivshmem-test.c index e23a97fa8e..9611d05eb5 100644 --- a/tests/qtest/ivshmem-test.c +++ b/tests/qtest/ivshmem-test.c @@ -481,8 +481,8 @@ int main(int argc, char **argv) tmpshmem = mmap(0, TMPSHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); g_assert(tmpshmem != MAP_FAILED); /* server */ - if (mkdtemp(dir) == NULL) { - g_error("mkdtemp: %s", g_strerror(errno)); + if (g_mkdtemp(dir) == NULL) { + g_error("g_mkdtemp: %s", g_strerror(errno)); } tmpdir = dir; tmpserver = g_strconcat(tmpdir, "/server", NULL); diff --git a/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c b/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c index c8a3ea11eb..ab24add8eb 100644 --- a/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c +++ b/tests/qtest/libqos/aarch64-xlnx-zcu102-machine.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "../libqtest.h" #include "qemu/module.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "sdhci.h" diff --git a/tests/qtest/libqos/arm-imx25-pdk-machine.c b/tests/qtest/libqos/arm-imx25-pdk-machine.c index 54d0c95330..8fe128fae8 100644 --- a/tests/qtest/libqos/arm-imx25-pdk-machine.c +++ b/tests/qtest/libqos/arm-imx25-pdk-machine.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "../libqtest.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "i2c.h" diff --git a/tests/qtest/libqos/arm-n800-machine.c b/tests/qtest/libqos/arm-n800-machine.c index ecd46b1daf..4e5afe0164 100644 --- a/tests/qtest/libqos/arm-n800-machine.c +++ b/tests/qtest/libqos/arm-n800-machine.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "../libqtest.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "i2c.h" diff --git a/tests/qtest/libqos/arm-raspi2-machine.c b/tests/qtest/libqos/arm-raspi2-machine.c index 0a2943440b..367c6c17a5 100644 --- a/tests/qtest/libqos/arm-raspi2-machine.c +++ b/tests/qtest/libqos/arm-raspi2-machine.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "../libqtest.h" #include "qemu/module.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "sdhci.h" diff --git a/tests/qtest/libqos/arm-sabrelite-machine.c b/tests/qtest/libqos/arm-sabrelite-machine.c index ec19a01660..94f6a20fc7 100644 --- a/tests/qtest/libqos/arm-sabrelite-machine.c +++ b/tests/qtest/libqos/arm-sabrelite-machine.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "../libqtest.h" #include "qemu/module.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "sdhci.h" diff --git a/tests/qtest/libqos/arm-smdkc210-machine.c b/tests/qtest/libqos/arm-smdkc210-machine.c index 4bff249ee8..9bbce924ea 100644 --- a/tests/qtest/libqos/arm-smdkc210-machine.c +++ b/tests/qtest/libqos/arm-smdkc210-machine.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "../libqtest.h" #include "qemu/module.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "sdhci.h" diff --git a/tests/qtest/libqos/arm-virt-machine.c b/tests/qtest/libqos/arm-virt-machine.c index 139eaba142..4e87405b58 100644 --- a/tests/qtest/libqos/arm-virt-machine.c +++ b/tests/qtest/libqos/arm-virt-machine.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "../libqtest.h" #include "qemu/module.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "virtio-mmio.h" #include "generic-pcihost.h" diff --git a/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c b/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c index 3be80020a6..daac762a06 100644 --- a/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c +++ b/tests/qtest/libqos/arm-xilinx-zynq-a9-machine.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "../libqtest.h" #include "qemu/module.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "sdhci.h" diff --git a/tests/qtest/libqos/e1000e.c b/tests/qtest/libqos/e1000e.c index f87e0e84b2..fc14b07884 100644 --- a/tests/qtest/libqos/e1000e.c +++ b/tests/qtest/libqos/e1000e.c @@ -23,7 +23,7 @@ #include "qemu/iov.h" #include "qemu/module.h" #include "qemu/bitops.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "e1000e.h" diff --git a/tests/qtest/libqos/generic-pcihost.h b/tests/qtest/libqos/generic-pcihost.h index c693c769df..6493a8712a 100644 --- a/tests/qtest/libqos/generic-pcihost.h +++ b/tests/qtest/libqos/generic-pcihost.h @@ -14,7 +14,7 @@ #define LIBQOS_GENERIC_PCIHOST_H #include "pci.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" typedef struct QGenericPCIBus { diff --git a/tests/qtest/libqos/malloc.c b/tests/qtest/libqos/libqos-malloc.c similarity index 99% rename from tests/qtest/libqos/malloc.c rename to tests/qtest/libqos/libqos-malloc.c index f0c8f950c8..d7566972c4 100644 --- a/tests/qtest/libqos/malloc.c +++ b/tests/qtest/libqos/libqos-malloc.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qemu/host-utils.h" typedef struct MemBlock { diff --git a/tests/qtest/libqos/malloc.h b/tests/qtest/libqos/libqos-malloc.h similarity index 100% rename from tests/qtest/libqos/malloc.h rename to tests/qtest/libqos/libqos-malloc.h diff --git a/tests/qtest/libqos/libqos.c b/tests/qtest/libqos/libqos.c index 85c7641add..5ffda080ec 100644 --- a/tests/qtest/libqos/libqos.c +++ b/tests/qtest/libqos/libqos.c @@ -1,6 +1,4 @@ #include "qemu/osdep.h" -#include - #include "../libqtest.h" #include "libqos.h" #include "pci.h" diff --git a/tests/qtest/libqos/libqos.h b/tests/qtest/libqos/libqos.h index ba7df448ca..9b4dd509f0 100644 --- a/tests/qtest/libqos/libqos.h +++ b/tests/qtest/libqos/libqos.h @@ -3,7 +3,7 @@ #include "../libqtest.h" #include "pci.h" -#include "malloc.h" +#include "libqos-malloc.h" typedef struct QOSState QOSState; diff --git a/tests/qtest/libqos/malloc-pc.h b/tests/qtest/libqos/malloc-pc.h index d8d79853c8..e531473601 100644 --- a/tests/qtest/libqos/malloc-pc.h +++ b/tests/qtest/libqos/malloc-pc.h @@ -13,7 +13,7 @@ #ifndef LIBQOS_MALLOC_PC_H #define LIBQOS_MALLOC_PC_H -#include "malloc.h" +#include "libqos-malloc.h" void pc_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags); diff --git a/tests/qtest/libqos/malloc-spapr.h b/tests/qtest/libqos/malloc-spapr.h index f99572fd71..f544c0d611 100644 --- a/tests/qtest/libqos/malloc-spapr.h +++ b/tests/qtest/libqos/malloc-spapr.h @@ -8,7 +8,7 @@ #ifndef LIBQOS_MALLOC_SPAPR_H #define LIBQOS_MALLOC_SPAPR_H -#include "malloc.h" +#include "libqos-malloc.h" void spapr_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags); diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build index fd5d6e5ae1..a5b6d5197a 100644 --- a/tests/qtest/libqos/meson.build +++ b/tests/qtest/libqos/meson.build @@ -6,7 +6,7 @@ libqos_srcs = files( 'qos_external.c', 'pci.c', 'fw_cfg.c', - 'malloc.c', + 'libqos-malloc.c', 'libqos.c', 'sdhci-cmd.c', @@ -45,6 +45,7 @@ libqos_srcs = files( 'virtio-scsi.c', 'virtio-serial.c', 'virtio-iommu.c', + 'virtio-gpio.c', 'generic-pcihost.c', # qgraph machines: diff --git a/tests/qtest/libqos/pci-pc.h b/tests/qtest/libqos/pci-pc.h index 49ec9507f2..849bd493de 100644 --- a/tests/qtest/libqos/pci-pc.h +++ b/tests/qtest/libqos/pci-pc.h @@ -14,7 +14,7 @@ #define LIBQOS_PCI_PC_H #include "pci.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" typedef struct QPCIBusPC { diff --git a/tests/qtest/libqos/pci-spapr.h b/tests/qtest/libqos/pci-spapr.h index 20a43718b7..3dbf1e58ae 100644 --- a/tests/qtest/libqos/pci-spapr.h +++ b/tests/qtest/libqos/pci-spapr.h @@ -8,7 +8,7 @@ #ifndef LIBQOS_PCI_SPAPR_H #define LIBQOS_PCI_SPAPR_H -#include "malloc.h" +#include "libqos-malloc.h" #include "pci.h" #include "qgraph.h" diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h index 871740c0dc..5c0046e989 100644 --- a/tests/qtest/libqos/qgraph.h +++ b/tests/qtest/libqos/qgraph.h @@ -21,10 +21,10 @@ #include #include "qemu/module.h" -#include "malloc.h" +#include "libqos-malloc.h" /* maximum path length */ -#define QOS_PATH_MAX_ELEMENT_SIZE 50 +#define QOS_PATH_MAX_ELEMENT_SIZE 64 typedef struct QOSGraphObject QOSGraphObject; typedef struct QOSGraphNode QOSGraphNode; diff --git a/tests/qtest/libqos/qos_external.c b/tests/qtest/libqos/qos_external.c index b7a0b873a3..c6bb8bff09 100644 --- a/tests/qtest/libqos/qos_external.c +++ b/tests/qtest/libqos/qos_external.c @@ -24,7 +24,7 @@ #include "qapi/qmp/qstring.h" #include "qemu/module.h" #include "qapi/qmp/qlist.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "qgraph_internal.h" #include "qos_external.h" diff --git a/tests/qtest/libqos/qos_external.h b/tests/qtest/libqos/qos_external.h index 8446e3df0b..ea37364887 100644 --- a/tests/qtest/libqos/qos_external.h +++ b/tests/qtest/libqos/qos_external.h @@ -21,7 +21,7 @@ #include "qgraph.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qapi/qapi-types-machine.h" #include "qapi/qapi-types-qom.h" diff --git a/tests/qtest/libqos/rtas.h b/tests/qtest/libqos/rtas.h index f38f99dfab..be8353d505 100644 --- a/tests/qtest/libqos/rtas.h +++ b/tests/qtest/libqos/rtas.h @@ -5,7 +5,7 @@ #ifndef LIBQOS_RTAS_H #define LIBQOS_RTAS_H -#include "malloc.h" +#include "libqos-malloc.h" int qrtas_get_time_of_day(QTestState *qts, QGuestAllocator *alloc, struct tm *tm, uint32_t *ns); diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c index 70aea8bf62..ae9b0a20e2 100644 --- a/tests/qtest/libqos/virtio-9p.c +++ b/tests/qtest/libqos/virtio-9p.c @@ -48,9 +48,9 @@ void virtio_9p_create_local_test_dir(void) */ char *template = concat_path(pwd, "qtest-9p-local-XXXXXX"); - local_test_path = mkdtemp(template); + local_test_path = g_mkdtemp(template); if (!local_test_path) { - g_test_message("mkdtemp('%s') failed: %s", template, strerror(errno)); + g_test_message("g_mkdtemp('%s') failed: %s", template, strerror(errno)); } g_assert(local_test_path != NULL); diff --git a/tests/qtest/libqos/virtio-gpio.c b/tests/qtest/libqos/virtio-gpio.c new file mode 100644 index 0000000000..762aa6695b --- /dev/null +++ b/tests/qtest/libqos/virtio-gpio.c @@ -0,0 +1,171 @@ +/* + * virtio-gpio nodes for testing + * + * Copyright (c) 2022 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "standard-headers/linux/virtio_config.h" +#include "../libqtest.h" +#include "qemu/module.h" +#include "qgraph.h" +#include "virtio-gpio.h" + +static QGuestAllocator *alloc; + +static void virtio_gpio_cleanup(QVhostUserGPIO *gpio) +{ + QVirtioDevice *vdev = gpio->vdev; + int i; + + for (i = 0; i < 2; i++) { + qvirtqueue_cleanup(vdev->bus, gpio->queues[i], alloc); + } + g_free(gpio->queues); +} + +/* + * This handles the VirtIO setup from the point of view of the driver + * frontend and therefor doesn't present any vhost specific features + * and in fact masks of the re-used bit. + */ +static void virtio_gpio_setup(QVhostUserGPIO *gpio) +{ + QVirtioDevice *vdev = gpio->vdev; + uint64_t features; + int i; + + features = qvirtio_get_features(vdev); + features &= ~QVIRTIO_F_BAD_FEATURE; + qvirtio_set_features(vdev, features); + + gpio->queues = g_new(QVirtQueue *, 2); + for (i = 0; i < 2; i++) { + gpio->queues[i] = qvirtqueue_setup(vdev, alloc, i); + } + qvirtio_set_driver_ok(vdev); +} + +static void *qvirtio_gpio_get_driver(QVhostUserGPIO *v_gpio, + const char *interface) +{ + if (!g_strcmp0(interface, "vhost-user-gpio")) { + return v_gpio; + } + if (!g_strcmp0(interface, "virtio")) { + return v_gpio->vdev; + } + + g_assert_not_reached(); +} + +static void *qvirtio_gpio_device_get_driver(void *object, + const char *interface) +{ + QVhostUserGPIODevice *v_gpio = object; + return qvirtio_gpio_get_driver(&v_gpio->gpio, interface); +} + +/* virtio-gpio (mmio) */ +static void qvirtio_gpio_device_destructor(QOSGraphObject *obj) +{ + QVhostUserGPIODevice *gpio_dev = (QVhostUserGPIODevice *) obj; + virtio_gpio_cleanup(&gpio_dev->gpio); +} + +static void qvirtio_gpio_device_start_hw(QOSGraphObject *obj) +{ + QVhostUserGPIODevice *gpio_dev = (QVhostUserGPIODevice *) obj; + virtio_gpio_setup(&gpio_dev->gpio); +} + +static void *virtio_gpio_device_create(void *virtio_dev, + QGuestAllocator *t_alloc, + void *addr) +{ + QVhostUserGPIODevice *virtio_device = g_new0(QVhostUserGPIODevice, 1); + QVhostUserGPIO *interface = &virtio_device->gpio; + + interface->vdev = virtio_dev; + alloc = t_alloc; + + virtio_device->obj.get_driver = qvirtio_gpio_device_get_driver; + virtio_device->obj.start_hw = qvirtio_gpio_device_start_hw; + virtio_device->obj.destructor = qvirtio_gpio_device_destructor; + + return &virtio_device->obj; +} + +/* virtio-gpio-pci */ +static void qvirtio_gpio_pci_destructor(QOSGraphObject *obj) +{ + QVhostUserGPIOPCI *gpio_pci = (QVhostUserGPIOPCI *) obj; + QOSGraphObject *pci_vobj = &gpio_pci->pci_vdev.obj; + + virtio_gpio_cleanup(&gpio_pci->gpio); + qvirtio_pci_destructor(pci_vobj); +} + +static void qvirtio_gpio_pci_start_hw(QOSGraphObject *obj) +{ + QVhostUserGPIOPCI *gpio_pci = (QVhostUserGPIOPCI *) obj; + QOSGraphObject *pci_vobj = &gpio_pci->pci_vdev.obj; + + qvirtio_pci_start_hw(pci_vobj); + virtio_gpio_setup(&gpio_pci->gpio); +} + +static void *qvirtio_gpio_pci_get_driver(void *object, const char *interface) +{ + QVhostUserGPIOPCI *v_gpio = object; + + if (!g_strcmp0(interface, "pci-device")) { + return v_gpio->pci_vdev.pdev; + } + return qvirtio_gpio_get_driver(&v_gpio->gpio, interface); +} + +static void *virtio_gpio_pci_create(void *pci_bus, QGuestAllocator *t_alloc, + void *addr) +{ + QVhostUserGPIOPCI *virtio_spci = g_new0(QVhostUserGPIOPCI, 1); + QVhostUserGPIO *interface = &virtio_spci->gpio; + QOSGraphObject *obj = &virtio_spci->pci_vdev.obj; + + virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr); + interface->vdev = &virtio_spci->pci_vdev.vdev; + alloc = t_alloc; + + obj->get_driver = qvirtio_gpio_pci_get_driver; + obj->start_hw = qvirtio_gpio_pci_start_hw; + obj->destructor = qvirtio_gpio_pci_destructor; + + return obj; +} + +static void virtio_gpio_register_nodes(void) +{ + QPCIAddress addr = { + .devfn = QPCI_DEVFN(4, 0), + }; + + QOSGraphEdgeOptions edge_opts = { }; + + /* vhost-user-gpio-device */ + edge_opts.extra_device_opts = "id=gpio0,chardev=chr-vhost-user-test"; + qos_node_create_driver("vhost-user-gpio-device", + virtio_gpio_device_create); + qos_node_consumes("vhost-user-gpio-device", "virtio-bus", &edge_opts); + qos_node_produces("vhost-user-gpio-device", "vhost-user-gpio"); + + /* virtio-gpio-pci */ + edge_opts.extra_device_opts = "id=gpio0,addr=04.0,chardev=chr-vhost-user-test"; + add_qpci_address(&edge_opts, &addr); + qos_node_create_driver("vhost-user-gpio-pci", virtio_gpio_pci_create); + qos_node_consumes("vhost-user-gpio-pci", "pci-bus", &edge_opts); + qos_node_produces("vhost-user-gpio-pci", "vhost-user-gpio"); +} + +libqos_init(virtio_gpio_register_nodes); diff --git a/tests/qtest/libqos/virtio-gpio.h b/tests/qtest/libqos/virtio-gpio.h new file mode 100644 index 0000000000..f11d41bd19 --- /dev/null +++ b/tests/qtest/libqos/virtio-gpio.h @@ -0,0 +1,35 @@ +/* + * virtio-gpio structures + * + * Copyright (c) 2022 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TESTS_LIBQOS_VIRTIO_GPIO_H +#define TESTS_LIBQOS_VIRTIO_GPIO_H + +#include "qgraph.h" +#include "virtio.h" +#include "virtio-pci.h" + +typedef struct QVhostUserGPIO QVhostUserGPIO; +typedef struct QVhostUserGPIOPCI QVhostUserGPIOPCI; +typedef struct QVhostUserGPIODevice QVhostUserGPIODevice; + +struct QVhostUserGPIO { + QVirtioDevice *vdev; + QVirtQueue **queues; +}; + +struct QVhostUserGPIOPCI { + QVirtioPCIDevice pci_vdev; + QVhostUserGPIO gpio; +}; + +struct QVhostUserGPIODevice { + QOSGraphObject obj; + QVhostUserGPIO gpio; +}; + +#endif diff --git a/tests/qtest/libqos/virtio-mmio.c b/tests/qtest/libqos/virtio-mmio.c index a6cca8613b..bd0b1d890b 100644 --- a/tests/qtest/libqos/virtio-mmio.c +++ b/tests/qtest/libqos/virtio-mmio.c @@ -12,7 +12,7 @@ #include "qemu/module.h" #include "virtio.h" #include "virtio-mmio.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "qgraph.h" #include "standard-headers/linux/virtio_ring.h" diff --git a/tests/qtest/libqos/virtio-pci.c b/tests/qtest/libqos/virtio-pci.c index 67c2498c84..485b8f6b7e 100644 --- a/tests/qtest/libqos/virtio-pci.c +++ b/tests/qtest/libqos/virtio-pci.c @@ -13,7 +13,7 @@ #include "virtio-pci.h" #include "pci.h" #include "pci-pc.h" -#include "malloc.h" +#include "libqos-malloc.h" #include "malloc-pc.h" #include "qgraph.h" #include "standard-headers/linux/virtio_ring.h" diff --git a/tests/qtest/libqos/virtio.c b/tests/qtest/libqos/virtio.c index 09ec09b655..410513225f 100644 --- a/tests/qtest/libqos/virtio.c +++ b/tests/qtest/libqos/virtio.c @@ -101,6 +101,8 @@ uint64_t qvirtio_get_features(QVirtioDevice *d) void qvirtio_set_features(QVirtioDevice *d, uint64_t features) { + g_assert(!(features & QVIRTIO_F_BAD_FEATURE)); + d->features = features; d->bus->set_features(d, features); @@ -108,7 +110,7 @@ void qvirtio_set_features(QVirtioDevice *d, uint64_t features) * This could be a separate function for drivers that want to access * configuration space before setting FEATURES_OK, but no existing users * need that and it's less code for callers if this is done implicitly. - */ + */ if (features & (1ull << VIRTIO_F_VERSION_1)) { uint8_t status = d->bus->get_status(d) | VIRTIO_CONFIG_S_FEATURES_OK; diff --git a/tests/qtest/libqos/virtio.h b/tests/qtest/libqos/virtio.h index b8bd06e1b8..7adc7cbd10 100644 --- a/tests/qtest/libqos/virtio.h +++ b/tests/qtest/libqos/virtio.h @@ -10,7 +10,7 @@ #ifndef LIBQOS_VIRTIO_H #define LIBQOS_VIRTIO_H -#include "malloc.h" +#include "libqos-malloc.h" #include "standard-headers/linux/virtio_ring.h" #define QVIRTIO_F_BAD_FEATURE 0x40000000ull diff --git a/tests/qtest/libqtest-single.h b/tests/qtest/libqtest-single.h index 4e7d0ae1dc..851724cbcb 100644 --- a/tests/qtest/libqtest-single.h +++ b/tests/qtest/libqtest-single.h @@ -13,7 +13,11 @@ #include "libqtest.h" +#ifndef _WIN32 QTestState *global_qtest __attribute__((common, weak)); +#else +__declspec(selectany) QTestState *global_qtest; +#endif /** * qtest_start: diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 8c159eacf5..4f4b2d6477 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -97,7 +97,7 @@ static int socket_accept(int sock) (void *)&timeout, sizeof(timeout))) { fprintf(stderr, "%s failed to set SO_RCVTIMEO: %s\n", __func__, strerror(errno)); - close(sock); + closesocket(sock); return -1; } @@ -108,7 +108,7 @@ static int socket_accept(int sock) if (ret == -1) { fprintf(stderr, "%s failed: %s\n", __func__, strerror(errno)); } - close(sock); + closesocket(sock); return ret; } @@ -265,8 +265,10 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) s = g_new(QTestState, 1); - socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid()); - qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid()); + socket_path = g_strdup_printf("%s/qtest-%d.sock", + g_get_tmp_dir(), getpid()); + qmp_socket_path = g_strdup_printf("%s/qtest-%d.qmp", + g_get_tmp_dir(), getpid()); /* It's possible that if an earlier test run crashed it might * have left a stale unix socket lying around. Delete any @@ -390,10 +392,12 @@ QTestState *qtest_initf(const char *fmt, ...) QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd) { int sock_fd_init; - char *sock_path, sock_dir[] = "/tmp/qtest-serial-XXXXXX"; + g_autofree char *sock_dir = NULL; + char *sock_path; QTestState *qts; - g_assert_true(mkdtemp(sock_dir) != NULL); + sock_dir = g_dir_make_tmp("qtest-serial-XXXXXX", NULL); + g_assert_true(sock_dir != NULL); sock_path = g_strdup_printf("%s/sock", sock_dir); sock_fd_init = init_socket(sock_path); @@ -417,8 +421,8 @@ void qtest_quit(QTestState *s) qtest_remove_abrt_handler(s); qtest_kill_qemu(s); - close(s->fd); - close(s->qmp_fd); + closesocket(s->fd); + closesocket(s->qmp_fd); g_string_free(s->rx, true); for (GList *it = s->pending_events; it != NULL; it = it->next) { @@ -588,17 +592,20 @@ int qtest_socket_server(const char *socket_path) return sock; } +#ifndef _WIN32 void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num, const char *fmt, va_list ap) { qmp_fd_vsend_fds(s->qmp_fd, fds, fds_num, fmt, ap); } +#endif void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap) { - qmp_fd_vsend_fds(s->qmp_fd, NULL, 0, fmt, ap); + qmp_fd_vsend(s->qmp_fd, fmt, ap); } +#ifndef _WIN32 QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num, const char *fmt, va_list ap) { @@ -607,6 +614,7 @@ QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num, /* Receive reply */ return qtest_qmp_receive(s); } +#endif QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap) { @@ -616,6 +624,7 @@ QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap) return qtest_qmp_receive(s); } +#ifndef _WIN32 QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num, const char *fmt, ...) { @@ -627,6 +636,7 @@ QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num, va_end(ap); return response; } +#endif QDict *qtest_qmp(QTestState *s, const char *fmt, ...) { @@ -1323,6 +1333,7 @@ void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id, qobject_unref(args); } +#ifndef _WIN32 void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd) { QDict *resp; @@ -1342,6 +1353,7 @@ void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd) g_assert(!qdict_haskey(resp, "error")); qobject_unref(resp); } +#endif /* * Generic hot-unplugging test via the device_del QMP command. @@ -1424,7 +1436,7 @@ QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch, * way, qtest_get_arch works for inproc qtest. */ gchar *bin_path = g_strconcat("/qemu-system-", arch, NULL); - setenv("QTEST_QEMU_BINARY", bin_path, 0); + g_setenv("QTEST_QEMU_BINARY", bin_path, 0); g_free(bin_path); return qts; diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index 94b187837d..3abc75964d 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -94,6 +94,7 @@ void qtest_kill_qemu(QTestState *s); */ void qtest_quit(QTestState *s); +#ifndef _WIN32 /** * qtest_qmp_fds: * @s: #QTestState instance to operate on. @@ -108,6 +109,7 @@ void qtest_quit(QTestState *s); QDict *qtest_qmp_fds(QTestState *s, int *fds, size_t fds_num, const char *fmt, ...) G_GNUC_PRINTF(4, 5); +#endif /* _WIN32 */ /** * qtest_qmp: @@ -152,6 +154,7 @@ void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...) */ int qtest_socket_server(const char *socket_path); +#ifndef _WIN32 /** * qtest_vqmp_fds: * @s: #QTestState instance to operate on. @@ -167,6 +170,7 @@ int qtest_socket_server(const char *socket_path); QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num, const char *fmt, va_list ap) G_GNUC_PRINTF(4, 0); +#endif /* _WIN32 */ /** * qtest_vqmp: @@ -181,6 +185,7 @@ QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num, QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); +#ifndef _WIN32 /** * qtest_qmp_vsend_fds: * @s: #QTestState instance to operate on. @@ -196,6 +201,7 @@ QDict *qtest_vqmp(QTestState *s, const char *fmt, va_list ap) void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num, const char *fmt, va_list ap) G_GNUC_PRINTF(4, 0); +#endif /* _WIN32 */ /** * qtest_qmp_vsend: @@ -743,6 +749,7 @@ void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv, void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id, const char *fmt, ...) G_GNUC_PRINTF(4, 5); +#ifndef _WIN32 /** * qtest_qmp_add_client: * @qts: QTestState instance to operate on @@ -752,6 +759,7 @@ void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id, * Call QMP ``getfd`` followed by ``add_client`` with the given @fd. */ void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd); +#endif /* _WIN32 */ /** * qtest_qmp_device_del: diff --git a/tests/qtest/m48t59-test.c b/tests/qtest/m48t59-test.c index b94a1230f7..843d2ced8e 100644 --- a/tests/qtest/m48t59-test.c +++ b/tests/qtest/m48t59-test.c @@ -137,7 +137,7 @@ static void cmos_get_date_time(QTestState *s, struct tm *date) date->tm_mday = mday; date->tm_mon = mon - 1; date->tm_year = base_year + year - 1900; -#ifndef __sun__ +#if !defined(__sun__) && !defined(_WIN32) date->tm_gmtoff = 0; #endif diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c index f92fab479f..31cc0bfb01 100644 --- a/tests/qtest/machine-none-test.c +++ b/tests/qtest/machine-none-test.c @@ -81,7 +81,7 @@ static void test_machine_cpu_cli(void) " add it to cpus_map\n", arch); return; /* TODO: die here to force all targets have a test */ } - qts = qtest_initf("-machine none -cpu '%s'", cpu_model); + qts = qtest_initf("-machine none -cpu \"%s\"", cpu_model); response = qtest_qmp(qts, "{ 'execute': 'quit' }"); g_assert(qdict_haskey(response, "return")); diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 3a474010e4..455f1bbb7e 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -26,6 +26,7 @@ qtests_generic = [ 'qom-test', 'test-hmp', 'qos-test', + 'readconfig-test', ] if config_host.has_key('CONFIG_MODULES') qtests_generic += [ 'modules-test' ] @@ -38,9 +39,14 @@ qtests_pci = \ qtests_cxl = \ (config_all_devices.has_key('CONFIG_CXL') ? ['cxl-test'] : []) +qtests_filter = \ + (slirp.found() ? ['test-netfilter'] : []) + \ + (config_host.has_key('CONFIG_POSIX') ? ['test-filter-mirror'] : []) + \ + (config_host.has_key('CONFIG_POSIX') ? ['test-filter-redirector'] : []) + qtests_i386 = \ - (slirp.found() ? ['pxe-test', 'test-netfilter'] : []) + \ - (config_host.has_key('CONFIG_POSIX') ? ['test-filter-mirror'] : []) + \ + (slirp.found() ? ['pxe-test'] : []) + \ + qtests_filter + \ (have_tools ? ['ahci-test'] : []) + \ (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ (config_all_devices.has_key('CONFIG_SGA') ? ['boot-serial-test'] : []) + \ @@ -70,7 +76,8 @@ qtests_i386 = \ (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \ (config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \ (config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \ - (config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \ + (config_host.has_key('CONFIG_POSIX') and \ + config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \ (config_all_devices.has_key('CONFIG_VIRTIO_NET') and \ config_all_devices.has_key('CONFIG_Q35') and \ config_all_devices.has_key('CONFIG_VIRTIO_PCI') and \ @@ -93,8 +100,7 @@ qtests_i386 = \ 'vmgenid-test', 'migration-test', 'test-x86-cpuid-compat', - 'numa-test', - 'test-filter-redirector' + 'numa-test' ] if dbus_display @@ -118,30 +124,25 @@ endif qtests_x86_64 = qtests_i386 qtests_alpha = ['boot-serial-test'] + \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + \ + qtests_filter + \ (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) qtests_avr = [ 'boot-serial-test' ] qtests_hppa = ['boot-serial-test'] + \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + \ + qtests_filter + \ (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) qtests_m68k = ['boot-serial-test'] + \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + qtests_filter qtests_microblaze = ['boot-serial-test'] + \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + qtests_filter qtests_microblazeel = qtests_microblaze qtests_mips = \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + \ + qtests_filter + \ (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) @@ -150,8 +151,7 @@ qtests_mips64 = qtests_mips qtests_mips64el = qtests_mips qtests_ppc = \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + \ + qtests_filter + \ (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ (config_all_devices.has_key('CONFIG_M48T59') ? ['m48t59-test'] : []) + \ (config_all_devices.has_key('CONFIG_TCG') ? ['prom-env-test'] : []) + \ @@ -172,13 +172,11 @@ qtests_sh4 = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-te qtests_sh4eb = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) qtests_sparc = ['prom-env-test', 'm48t59-test', 'boot-serial-test'] + \ - ['test-filter-mirror', 'test-filter-redirector'] + \ - (slirp.found() ? ['test-netfilter'] : []) + qtests_filter qtests_sparc64 = \ (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ - (slirp.found() ? ['test-netfilter'] : []) + \ - ['test-filter-mirror', 'test-filter-redirector'] + \ + qtests_filter + \ ['prom-env-test', 'boot-serial-test'] qtests_npcm7xx = \ @@ -238,7 +236,6 @@ qos_test_ss.add( 'adm1272-test.c', 'ds1338-test.c', 'e1000-test.c', - 'e1000e-test.c', 'eepro100-test.c', 'es1370-test.c', 'ipoctal232-test.c', @@ -266,6 +263,9 @@ qos_test_ss.add( 'virtio-iommu-test.c', 'vmxnet3-test.c', ) +if config_host.has_key('CONFIG_POSIX') + qos_test_ss.add(files('e1000e-test.c')) +endif if have_virtfs qos_test_ss.add(files('virtio-9p-test.c')) endif diff --git a/tests/qtest/microbit-test.c b/tests/qtest/microbit-test.c index 04e199ec33..4bc267020b 100644 --- a/tests/qtest/microbit-test.c +++ b/tests/qtest/microbit-test.c @@ -51,7 +51,7 @@ static void uart_rw_to_rxd(QTestState *qts, int sock_fd, const char *in, { int i, in_len = strlen(in); - g_assert_true(write(sock_fd, in, in_len) == in_len); + g_assert_true(send(sock_fd, in, in_len, 0) == in_len); for (i = 0; i < in_len; i++) { g_assert_true(uart_wait_for_event(qts, NRF51_UART_BASE + A_UART_RXDRDY)); @@ -77,7 +77,7 @@ static void test_nrf51_uart(void) char s[10]; QTestState *qts = qtest_init_with_serial("-M microbit", &sock_fd); - g_assert_true(write(sock_fd, "c", 1) == 1); + g_assert_true(send(sock_fd, "c", 1, 0) == 1); g_assert_cmphex(qtest_readl(qts, NRF51_UART_BASE + A_UART_RXD), ==, 0x00); qtest_writel(qts, NRF51_UART_BASE + A_UART_ENABLE, 0x04); @@ -97,17 +97,17 @@ static void test_nrf51_uart(void) qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTTX, 0x01); uart_w_to_txd(qts, "d"); - g_assert_true(read(sock_fd, s, 10) == 1); + g_assert_true(recv(sock_fd, s, 10, 0) == 1); g_assert_cmphex(s[0], ==, 'd'); qtest_writel(qts, NRF51_UART_BASE + A_UART_SUSPEND, 0x01); qtest_writel(qts, NRF51_UART_BASE + A_UART_TXD, 'h'); qtest_writel(qts, NRF51_UART_BASE + A_UART_STARTTX, 0x01); uart_w_to_txd(qts, "world"); - g_assert_true(read(sock_fd, s, 10) == 5); + g_assert_true(recv(sock_fd, s, 10, 0) == 5); g_assert_true(memcmp(s, "world", 5) == 0); - close(sock_fd); + closesocket(sock_fd); qtest_quit(qts); } @@ -447,11 +447,11 @@ static void test_nrf51_timer(void) timer_set_bitmode(qts, NRF51_TIMER_WIDTH_16); /* 16 MHz Timer */ timer_set_prescaler(qts, 0); - /* Swept over in first step */ + /* Swept over, during the first step */ timer_set_cc(qts, 0, 2); - /* Barely miss on first step */ + /* Barely miss, after the second step */ timer_set_cc(qts, 1, 162); - /* Spot on on third step */ + /* Spot on, after the third step */ timer_set_cc(qts, 2, 480); timer_assert_events(qts, 0, 0, 0, 0); diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index c6fbeb3974..f6f3c6680f 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -34,6 +34,7 @@ static void check_stop_event(QTestState *who) } } +#ifndef _WIN32 /* * Events can get in the way of responses we are actually waiting for. */ @@ -58,6 +59,7 @@ QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...) return ret; } +#endif /* * Events can get in the way of responses we are actually waiting for. diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index 59561898d0..db0684de48 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -17,8 +17,10 @@ extern bool got_stop; +#ifndef _WIN32 G_GNUC_PRINTF(3, 4) QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...); +#endif G_GNUC_PRINTF(2, 3) QDict *wait_command(QTestState *who, const char *command, ...); diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 71595a74fd..0d153d6b5e 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -647,7 +647,16 @@ static int test_migrate_start(QTestState **from, QTestState **to, } if (!getenv("QTEST_LOG") && args->hide_stderr) { +#ifndef _WIN32 ignore_stderr = "2>/dev/null"; +#else + /* + * On Windows the QEMU executable is created via CreateProcess() and + * IO redirection does not work, so don't bother adding IO redirection + * to the command line. + */ + ignore_stderr = ""; +#endif } else { ignore_stderr = ""; } @@ -761,14 +770,14 @@ test_migrate_tls_psk_start_common(QTestState *from, data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs); data->pskfile = g_strdup_printf("%s/%s", data->workdir, QCRYPTO_TLS_CREDS_PSKFILE); - mkdir(data->workdir, 0700); + g_mkdir_with_parents(data->workdir, 0700); test_tls_psk_init(data->pskfile); if (mismatch) { data->workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs); data->pskfilealt = g_strdup_printf("%s/%s", data->workdiralt, QCRYPTO_TLS_CREDS_PSKFILE); - mkdir(data->workdiralt, 0700); + g_mkdir_with_parents(data->workdiralt, 0700); test_tls_psk_init_alt(data->pskfilealt); } @@ -873,12 +882,20 @@ test_migrate_tls_x509_start_common(QTestState *from, data->clientcert = g_strdup_printf("%s/client-cert.pem", data->workdir); } - mkdir(data->workdir, 0700); + g_mkdir_with_parents(data->workdir, 0700); test_tls_init(data->keyfile); +#ifndef _WIN32 g_assert(link(data->keyfile, data->serverkey) == 0); +#else + g_assert(CreateHardLink(data->serverkey, data->keyfile, NULL) != 0); +#endif if (args->clientcert) { +#ifndef _WIN32 g_assert(link(data->keyfile, data->clientkey) == 0); +#else + g_assert(CreateHardLink(data->clientkey, data->keyfile, NULL) != 0); +#endif } TLS_ROOT_REQ_SIMPLE(cacertreq, data->cacert); @@ -1307,7 +1324,9 @@ static void test_precopy_common(MigrateCommon *args) } /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); + if (args->result == MIG_TEST_SUCCEED) { + wait_for_serial("src_serial"); + } if (!args->connect_uri) { g_autofree char *local_connect_uri = @@ -1383,6 +1402,7 @@ static void test_precopy_unix_dirty_ring(void) } #ifdef CONFIG_GNUTLS +#ifndef _WIN32 static void test_precopy_unix_tls_psk(void) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); @@ -1395,6 +1415,7 @@ static void test_precopy_unix_tls_psk(void) test_precopy_common(&args); } +#endif /* _WIN32 */ #ifdef CONFIG_TASN1 static void test_precopy_unix_tls_x509_default_host(void) @@ -1503,6 +1524,7 @@ static void test_precopy_tcp_plain(void) } #ifdef CONFIG_GNUTLS +#ifndef _WIN32 static void test_precopy_tcp_tls_psk_match(void) { MigrateCommon args = { @@ -1513,6 +1535,7 @@ static void test_precopy_tcp_tls_psk_match(void) test_precopy_common(&args); } +#endif /* _WIN32 */ static void test_precopy_tcp_tls_psk_mismatch(void) { @@ -1621,6 +1644,7 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(void) #endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ +#ifndef _WIN32 static void *test_migrate_fd_start_hook(QTestState *from, QTestState *to) { @@ -1689,6 +1713,7 @@ static void test_migrate_fd_proto(void) }; test_precopy_common(&args); } +#endif /* _WIN32 */ static void do_test_validate_uuid(MigrateStart *args, bool should_fail) { @@ -1768,7 +1793,7 @@ static void test_migrate_auto_converge(void) g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); MigrateStart args = {}; QTestState *from, *to; - int64_t remaining, percentage; + int64_t percentage; /* * We want the test to be stable and as fast as possible. @@ -1776,14 +1801,6 @@ static void test_migrate_auto_converge(void) * so we need to decrease a bandwidth. */ const int64_t init_pct = 5, inc_pct = 50, max_pct = 95; - const int64_t max_bandwidth = 400000000; /* ~400Mb/s */ - const int64_t downtime_limit = 250; /* 250ms */ - /* - * We migrate through unix-socket (> 500Mb/s). - * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s). - * So, we can predict expected_threshold - */ - const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000; if (test_migrate_start(&from, &to, uri, &args)) { return; @@ -1818,8 +1835,7 @@ static void test_migrate_auto_converge(void) /* The first percentage of throttling should be equal to init_pct */ g_assert_cmpint(percentage, ==, init_pct); /* Now, when we tested that throttling works, let it converge */ - migrate_set_parameter_int(from, "downtime-limit", downtime_limit); - migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth); + migrate_ensure_converge(from); /* * Wait for pre-switchover status to check last throttle percentage @@ -1830,11 +1846,6 @@ static void test_migrate_auto_converge(void) /* The final percentage of throttling shouldn't be greater than max_pct */ percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); g_assert_cmpint(percentage, <=, max_pct); - - remaining = read_ram_property_int(from, "remaining"); - g_assert_cmpint(remaining, <, - (expected_threshold + expected_threshold / 100)); - migrate_continue(from, "pre-switchover"); qtest_qmp_eventwait(to, "RESUME"); @@ -1842,7 +1853,6 @@ static void test_migrate_auto_converge(void) wait_for_serial("dest_serial"); wait_for_migration_complete(from); - test_migrate_end(from, to, true); } @@ -1923,6 +1933,7 @@ static void test_multifd_tcp_zstd(void) #endif #ifdef CONFIG_GNUTLS +#ifndef _WIN32 static void * test_migrate_multifd_tcp_tls_psk_start_match(QTestState *from, QTestState *to) @@ -1930,6 +1941,7 @@ test_migrate_multifd_tcp_tls_psk_start_match(QTestState *from, test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); return test_migrate_tls_psk_start_match(from, to); } +#endif /* _WIN32 */ static void * test_migrate_multifd_tcp_tls_psk_start_mismatch(QTestState *from, @@ -1981,6 +1993,7 @@ test_migrate_multifd_tls_x509_start_reject_anon_client(QTestState *from, } #endif /* CONFIG_TASN1 */ +#ifndef _WIN32 static void test_multifd_tcp_tls_psk_match(void) { MigrateCommon args = { @@ -1990,6 +2003,7 @@ static void test_multifd_tcp_tls_psk_match(void) }; test_precopy_common(&args); } +#endif /* _WIN32 */ static void test_multifd_tcp_tls_psk_mismatch(void) { @@ -2439,20 +2453,18 @@ int main(int argc, char **argv) { char template[] = "/tmp/migration-test-XXXXXX"; const bool has_kvm = qtest_has_accel("kvm"); + const bool has_uffd = ufd_version_check(); + const char *arch = qtest_get_arch(); int ret; g_test_init(&argc, &argv, NULL); - if (!ufd_version_check()) { - return g_test_run(); - } - /* * On ppc64, the test only works with kvm-hv, but not with kvm-pr and TCG * is touchy due to race conditions on dirty bits (especially on PPC for * some reason) */ - if (g_str_equal(qtest_get_arch(), "ppc64") && + if (g_str_equal(arch, "ppc64") && (!has_kvm || access("/sys/module/kvm_hv", F_OK))) { g_test_message("Skipping test: kvm_hv not available"); return g_test_run(); @@ -2462,45 +2474,51 @@ int main(int argc, char **argv) * Similar to ppc64, s390x seems to be touchy with TCG, so disable it * there until the problems are resolved */ - if (g_str_equal(qtest_get_arch(), "s390x") && !has_kvm) { + if (g_str_equal(arch, "s390x") && !has_kvm) { g_test_message("Skipping test: s390x host with KVM is required"); return g_test_run(); } - tmpfs = mkdtemp(template); + tmpfs = g_mkdtemp(template); if (!tmpfs) { - g_test_message("mkdtemp on path (%s): %s", template, strerror(errno)); + g_test_message("g_mkdtemp on path (%s): %s", template, strerror(errno)); } g_assert(tmpfs); module_call_init(MODULE_INIT_QOM); - qtest_add_func("/migration/postcopy/unix", test_postcopy); - qtest_add_func("/migration/postcopy/plain", test_postcopy); - qtest_add_func("/migration/postcopy/recovery/plain", - test_postcopy_recovery); - qtest_add_func("/migration/postcopy/preempt/plain", test_postcopy_preempt); - qtest_add_func("/migration/postcopy/preempt/recovery/plain", - test_postcopy_preempt_recovery); + if (has_uffd) { + qtest_add_func("/migration/postcopy/plain", test_postcopy); + qtest_add_func("/migration/postcopy/recovery/plain", + test_postcopy_recovery); + qtest_add_func("/migration/postcopy/preempt/plain", test_postcopy_preempt); + qtest_add_func("/migration/postcopy/preempt/recovery/plain", + test_postcopy_preempt_recovery); + } qtest_add_func("/migration/bad_dest", test_baddest); qtest_add_func("/migration/precopy/unix/plain", test_precopy_unix_plain); qtest_add_func("/migration/precopy/unix/xbzrle", test_precopy_unix_xbzrle); #ifdef CONFIG_GNUTLS +#ifndef _WIN32 qtest_add_func("/migration/precopy/unix/tls/psk", test_precopy_unix_tls_psk); - /* - * NOTE: psk test is enough for postcopy, as other types of TLS - * channels are tested under precopy. Here what we want to test is the - * general postcopy path that has TLS channel enabled. - */ - qtest_add_func("/migration/postcopy/tls/psk", test_postcopy_tls_psk); - qtest_add_func("/migration/postcopy/recovery/tls/psk", - test_postcopy_recovery_tls_psk); - qtest_add_func("/migration/postcopy/preempt/tls/psk", - test_postcopy_preempt_tls_psk); - qtest_add_func("/migration/postcopy/preempt/recovery/tls/psk", - test_postcopy_preempt_all); +#endif + + if (has_uffd) { + /* + * NOTE: psk test is enough for postcopy, as other types of TLS + * channels are tested under precopy. Here what we want to test is the + * general postcopy path that has TLS channel enabled. + */ + qtest_add_func("/migration/postcopy/tls/psk", test_postcopy_tls_psk); + qtest_add_func("/migration/postcopy/recovery/tls/psk", + test_postcopy_recovery_tls_psk); + qtest_add_func("/migration/postcopy/preempt/tls/psk", + test_postcopy_preempt_tls_psk); + qtest_add_func("/migration/postcopy/preempt/recovery/tls/psk", + test_postcopy_preempt_all); + } #ifdef CONFIG_TASN1 qtest_add_func("/migration/precopy/unix/tls/x509/default-host", test_precopy_unix_tls_x509_default_host); @@ -2511,8 +2529,10 @@ int main(int argc, char **argv) qtest_add_func("/migration/precopy/tcp/plain", test_precopy_tcp_plain); #ifdef CONFIG_GNUTLS +#ifndef _WIN32 qtest_add_func("/migration/precopy/tcp/tls/psk/match", test_precopy_tcp_tls_psk_match); +#endif qtest_add_func("/migration/precopy/tcp/tls/psk/mismatch", test_precopy_tcp_tls_psk_mismatch); #ifdef CONFIG_TASN1 @@ -2534,7 +2554,9 @@ int main(int argc, char **argv) #endif /* CONFIG_GNUTLS */ /* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */ +#ifndef _WIN32 qtest_add_func("/migration/fd_proto", test_migrate_fd_proto); +#endif qtest_add_func("/migration/validate_uuid", test_validate_uuid); qtest_add_func("/migration/validate_uuid_error", test_validate_uuid_error); qtest_add_func("/migration/validate_uuid_src_not_set", @@ -2554,8 +2576,10 @@ int main(int argc, char **argv) test_multifd_tcp_zstd); #endif #ifdef CONFIG_GNUTLS +#ifndef _WIN32 qtest_add_func("/migration/multifd/tcp/tls/psk/match", test_multifd_tcp_tls_psk_match); +#endif qtest_add_func("/migration/multifd/tcp/tls/psk/mismatch", test_multifd_tcp_tls_psk_mismatch); #ifdef CONFIG_TASN1 @@ -2572,7 +2596,7 @@ int main(int argc, char **argv) #endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ - if (kvm_dirty_ring_supported()) { + if (g_str_equal(arch, "x86_64") && has_kvm && kvm_dirty_ring_supported()) { qtest_add_func("/migration/dirty_ring", test_precopy_unix_dirty_ring); qtest_add_func("/migration/vcpu_dirty_limit", diff --git a/tests/qtest/npcm7xx_emc-test.c b/tests/qtest/npcm7xx_emc-test.c index a353fef0ca..b046f1d76a 100644 --- a/tests/qtest/npcm7xx_emc-test.c +++ b/tests/qtest/npcm7xx_emc-test.c @@ -209,6 +209,7 @@ static int emc_module_index(const EMCModule *mod) return diff; } +#ifndef _WIN32 static void packet_test_clear(void *sockets) { int *test_sockets = sockets; @@ -243,6 +244,7 @@ static int *packet_test_init(int module_num, GString *cmd_line) g_test_queue_destroy(packet_test_clear, test_sockets); return test_sockets; } +#endif /* _WIN32 */ static uint32_t emc_read(QTestState *qts, const EMCModule *mod, NPCM7xxPWMRegister regno) @@ -250,6 +252,7 @@ static uint32_t emc_read(QTestState *qts, const EMCModule *mod, return qtest_readl(qts, mod->base_addr + regno * sizeof(uint32_t)); } +#ifndef _WIN32 static void emc_write(QTestState *qts, const EMCModule *mod, NPCM7xxPWMRegister regno, uint32_t value) { @@ -339,6 +342,7 @@ static bool emc_soft_reset(QTestState *qts, const EMCModule *mod) g_message("%s: Timeout expired", __func__); return false; } +#endif /* _WIN32 */ /* Check emc registers are reset to default value. */ static void test_init(gconstpointer test_data) @@ -377,7 +381,8 @@ static void test_init(gconstpointer test_data) #undef CHECK_REG - for (i = 0; i < NUM_CAMML_REGS; ++i) { + /* Skip over the MAC address registers, which is BASE+0 */ + for (i = 1; i < NUM_CAMML_REGS; ++i) { g_assert_cmpuint(emc_read(qts, mod, REG_CAMM_BASE + i * 2), ==, 0); g_assert_cmpuint(emc_read(qts, mod, REG_CAML_BASE + i * 2), ==, @@ -387,6 +392,7 @@ static void test_init(gconstpointer test_data) qtest_quit(qts); } +#ifndef _WIN32 static bool emc_wait_irq(QTestState *qts, const EMCModule *mod, int step, bool is_tx) { @@ -843,6 +849,7 @@ static void test_rx(gconstpointer test_data) qtest_quit(qts); } +#endif /* _WIN32 */ static void emc_add_test(const char *name, const TestData* td, GTestDataFunc fn) @@ -865,8 +872,10 @@ int main(int argc, char **argv) td->module = &emc_module_list[i]; add_test(init, td); +#ifndef _WIN32 add_test(tx, td); add_test(rx, td); +#endif } return g_test_run(); diff --git a/tests/qtest/pflash-cfi02-test.c b/tests/qtest/pflash-cfi02-test.c index 7fce614b64..0b52c2ca5c 100644 --- a/tests/qtest/pflash-cfi02-test.c +++ b/tests/qtest/pflash-cfi02-test.c @@ -56,7 +56,7 @@ typedef struct { QTestState *qtest; } FlashConfig; -static char image_path[] = "/tmp/qtest.XXXXXX"; +static char *image_path; /* * The pflash implementation allows some parameters to be unspecified. We want @@ -608,6 +608,7 @@ static void test_cfi_in_autoselect(const void *opaque) static void cleanup(void *opaque) { unlink(image_path); + g_free(image_path); } /* @@ -635,16 +636,14 @@ static const FlashConfig configuration[] = { int main(int argc, char **argv) { - int fd = mkstemp(image_path); - if (fd == -1) { - g_printerr("Failed to create temporary file %s: %s\n", image_path, - strerror(errno)); - exit(EXIT_FAILURE); - } + GError *err = NULL; + int fd = g_file_open_tmp("qtest.XXXXXX", &image_path, &err); + g_assert_no_error(err); + if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) { int error_code = errno; close(fd); - unlink(image_path); + cleanup(NULL); g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path, UNIFORM_FLASH_SIZE, strerror(error_code)); exit(EXIT_FAILURE); diff --git a/tests/qtest/prom-env-test.c b/tests/qtest/prom-env-test.c index c2b0448e55..39ccb59797 100644 --- a/tests/qtest/prom-env-test.c +++ b/tests/qtest/prom-env-test.c @@ -58,8 +58,8 @@ static void test_machine(const void *machine) " -machine " PSERIES_DEFAULT_CAPABILITIES; } - qts = qtest_initf("-M %s -accel tcg %s -prom-env 'use-nvramrc?=true' " - "-prom-env 'nvramrc=%x %x l!' ", (const char *)machine, + qts = qtest_initf("-M %s -accel tcg %s -prom-env \"use-nvramrc?=true\" " + "-prom-env \"nvramrc=%x %x l!\" ", (const char *)machine, extra_args, MAGIC, ADDRESS); check_guest_memory(qts); qtest_quit(qts); diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index af00712458..897e4e937b 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -103,6 +103,7 @@ static bool query_is_ignored(const char *cmd) "query-gic-capabilities", /* arm */ /* Success depends on target-specific build configuration: */ "query-pci", /* CONFIG_PCI */ + "x-query-virtio", /* CONFIG_VIRTIO */ /* Success depends on launching SEV guest */ "query-sev-launch-measure", /* Success depends on Host or Hypervisor SEV support */ diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c index 9a42480cef..22957fa49c 100644 --- a/tests/qtest/qmp-test.c +++ b/tests/qtest/qmp-test.c @@ -159,16 +159,19 @@ static void test_qmp_protocol(void) qtest_quit(qts); } +#ifndef _WIN32 + /* Out-of-band tests */ -char tmpdir[] = "/tmp/qmp-test-XXXXXX"; +char *tmpdir; char *fifo_name; static void setup_blocking_cmd(void) { - if (!mkdtemp(tmpdir)) { - g_error("mkdtemp: %s", strerror(errno)); - } + GError *err = NULL; + tmpdir = g_dir_make_tmp("qmp-test-XXXXXX", &err); + g_assert_no_error(err); + fifo_name = g_strdup_printf("%s/fifo", tmpdir); if (mkfifo(fifo_name, 0666)) { g_error("mkfifo: %s", strerror(errno)); @@ -179,6 +182,7 @@ static void cleanup_blocking_cmd(void) { unlink(fifo_name); rmdir(tmpdir); + g_free(tmpdir); } static void send_cmd_that_blocks(QTestState *s, const char *id) @@ -277,6 +281,8 @@ static void test_qmp_oob(void) qtest_quit(qts); } +#endif /* _WIN32 */ + /* Preconfig tests */ static void test_qmp_preconfig(void) @@ -336,7 +342,10 @@ int main(int argc, char *argv[]) g_test_init(&argc, &argv, NULL); qtest_add_func("qmp/protocol", test_qmp_protocol); +#ifndef _WIN32 + /* This case calls mkfifo() which does not exist on win32 */ qtest_add_func("qmp/oob", test_qmp_oob); +#endif qtest_add_func("qmp/preconfig", test_qmp_preconfig); qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg); diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c index f97d0a08fd..5da4091ec3 100644 --- a/tests/qtest/qos-test.c +++ b/tests/qtest/qos-test.c @@ -25,7 +25,7 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-machine.h" #include "qapi/qapi-visit-qom.h" -#include "libqos/malloc.h" +#include "libqos/libqos-malloc.h" #include "libqos/qgraph.h" #include "libqos/qgraph_internal.h" #include "libqos/qos_external.h" @@ -185,7 +185,9 @@ static void run_one_test(const void *arg) static void subprocess_run_one_test(const void *arg) { const gchar *path = arg; - g_test_trap_subprocess(path, 0, 0); + g_test_trap_subprocess(path, 180 * G_USEC_PER_SEC, + G_TEST_SUBPROCESS_INHERIT_STDOUT | + G_TEST_SUBPROCESS_INHERIT_STDERR); g_test_trap_assert_passed(); } @@ -319,6 +321,11 @@ static void walk_path(QOSGraphNode *orig_path, int len) int main(int argc, char **argv, char** envp) { g_test_init(&argc, &argv, NULL); + + if (g_test_subprocess()) { + qos_printf("qos_test running single test in subprocess\n"); + } + if (g_test_verbose()) { qos_printf("ENVIRONMENT VARIABLES: {\n"); for (char **env = envp; *env != 0; env++) { diff --git a/tests/qtest/readconfig-test.c b/tests/qtest/readconfig-test.c new file mode 100644 index 0000000000..c7a9b0c7dd --- /dev/null +++ b/tests/qtest/readconfig-test.c @@ -0,0 +1,195 @@ +/* + * Validate -readconfig + * + * Copyright (c) 2022 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qapi/error.h" +#include "qapi/qapi-visit-machine.h" +#include "qapi/qapi-visit-qom.h" +#include "qapi/qapi-visit-ui.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qmp/qstring.h" +#include "qemu/units.h" + +static QTestState *qtest_init_with_config(const char *cfgdata) +{ + GError *error = NULL; + g_autofree char *args = NULL; + int cfgfd = -1; + g_autofree char *cfgpath = NULL; + QTestState *qts; + ssize_t ret; + + cfgfd = g_file_open_tmp("readconfig-test-XXXXXX", &cfgpath, &error); + g_assert_no_error(error); + g_assert_cmpint(cfgfd, >=, 0); + + ret = qemu_write_full(cfgfd, cfgdata, strlen(cfgdata)); + close(cfgfd); + if (ret < 0) { + unlink(cfgpath); + } + g_assert_cmpint(ret, ==, strlen(cfgdata)); + + args = g_strdup_printf("-nodefaults -machine none -readconfig %s", cfgpath); + + qts = qtest_init(args); + + unlink(cfgpath); + + return qts; +} + +static void test_x86_memdev_resp(QObject *res) +{ + Visitor *v; + g_autoptr(MemdevList) memdevs = NULL; + Memdev *memdev; + + g_assert(res); + v = qobject_input_visitor_new(res); + visit_type_MemdevList(v, NULL, &memdevs, &error_abort); + + g_assert(memdevs); + g_assert(memdevs->value); + g_assert(!memdevs->next); + + memdev = memdevs->value; + g_assert_cmpstr(memdev->id, ==, "ram"); + g_assert_cmpint(memdev->size, ==, 200 * MiB); + + visit_free(v); +} + +static void test_x86_memdev(void) +{ + QDict *resp; + QTestState *qts; + const char *cfgdata = + "[memory]\n" + "size = \"200\""; + + qts = qtest_init_with_config(cfgdata); + /* Test valid command */ + resp = qtest_qmp(qts, "{ 'execute': 'query-memdev' }"); + test_x86_memdev_resp(qdict_get(resp, "return")); + qobject_unref(resp); + + qtest_quit(qts); +} + + +#ifdef CONFIG_SPICE +static void test_spice_resp(QObject *res) +{ + Visitor *v; + g_autoptr(SpiceInfo) spice = NULL; + + g_assert(res); + v = qobject_input_visitor_new(res); + visit_type_SpiceInfo(v, "spice", &spice, &error_abort); + + g_assert(spice); + g_assert(spice->enabled); + + visit_free(v); +} + +static void test_spice(void) +{ + QDict *resp; + QTestState *qts; + const char *cfgdata = + "[spice]\n" + "disable-ticketing = \"on\"\n" + "unix = \"on\"\n"; + + qts = qtest_init_with_config(cfgdata); + /* Test valid command */ + resp = qtest_qmp(qts, "{ 'execute': 'query-spice' }"); + test_spice_resp(qdict_get(resp, "return")); + qobject_unref(resp); + + qtest_quit(qts); +} +#endif + +static void test_object_rng_resp(QObject *res) +{ + Visitor *v; + g_autoptr(ObjectPropertyInfoList) objs = NULL; + ObjectPropertyInfoList *tmp; + ObjectPropertyInfo *obj; + bool seen_rng = false; + + g_assert(res); + v = qobject_input_visitor_new(res); + visit_type_ObjectPropertyInfoList(v, NULL, &objs, &error_abort); + + g_assert(objs); + tmp = objs; + while (tmp) { + g_assert(tmp->value); + + obj = tmp->value; + if (g_str_equal(obj->name, "rng0") && + g_str_equal(obj->type, "child")) { + seen_rng = true; + break; + } + + tmp = tmp->next; + } + + g_assert(seen_rng); + + visit_free(v); +} + +static void test_object_rng(void) +{ + QDict *resp; + QTestState *qts; + const char *cfgdata = + "[object]\n" + "qom-type = \"rng-builtin\"\n" + "id = \"rng0\"\n"; + + qts = qtest_init_with_config(cfgdata); + /* Test valid command */ + resp = qtest_qmp(qts, + "{ 'execute': 'qom-list'," + " 'arguments': {'path': '/objects' }}"); + test_object_rng_resp(qdict_get(resp, "return")); + qobject_unref(resp); + + qtest_quit(qts); +} + +int main(int argc, char *argv[]) +{ + const char *arch; + g_test_init(&argc, &argv, NULL); + + arch = qtest_get_arch(); + + if (g_str_equal(arch, "i386") || + g_str_equal(arch, "x86_64")) { + qtest_add_func("readconfig/x86/memdev", test_x86_memdev); + } +#ifdef CONFIG_SPICE + qtest_add_func("readconfig/spice", test_spice); +#endif + + qtest_add_func("readconfig/object-rng", test_object_rng); + + return g_test_run(); +} diff --git a/tests/qtest/rtc-test.c b/tests/qtest/rtc-test.c index 8126ab1bdb..02ed4e1238 100644 --- a/tests/qtest/rtc-test.c +++ b/tests/qtest/rtc-test.c @@ -111,7 +111,7 @@ static void cmos_get_date_time(struct tm *date) date->tm_mday = mday; date->tm_mon = mon - 1; date->tm_year = base_year + year - 1900; -#ifndef __sun__ +#if !defined(__sun__) && !defined(_WIN32) date->tm_gmtoff = 0; #endif diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c index a81c2a2715..07a4c2d500 100644 --- a/tests/qtest/vhost-user-blk-test.c +++ b/tests/qtest/vhost-user-blk-test.c @@ -841,7 +841,8 @@ static char *create_listen_socket(int *fd) char *path; /* No race because our pid makes the path unique */ - path = g_strdup_printf("/tmp/qtest-%d-sock.XXXXXX", getpid()); + path = g_strdup_printf("%s/qtest-%d-sock.XXXXXX", + g_get_tmp_dir(), getpid()); tmp_fd = mkstemp(path); g_assert_cmpint(tmp_fd, >=, 0); close(tmp_fd); diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c index 8bf390be20..e8d2da7228 100644 --- a/tests/qtest/vhost-user-test.c +++ b/tests/qtest/vhost-user-test.c @@ -26,11 +26,13 @@ #include "libqos/virtio-pci.h" #include "libqos/malloc-pc.h" +#include "libqos/qgraph_internal.h" #include "hw/virtio/virtio-net.h" #include "standard-headers/linux/vhost_types.h" #include "standard-headers/linux/virtio_ids.h" #include "standard-headers/linux/virtio_net.h" +#include "standard-headers/linux/virtio_gpio.h" #ifdef CONFIG_LINUX #include @@ -52,9 +54,12 @@ #define VHOST_MAX_VIRTQUEUES 0x100 #define VHOST_USER_F_PROTOCOL_FEATURES 30 +#define VIRTIO_F_VERSION_1 32 + #define VHOST_USER_PROTOCOL_F_MQ 0 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1 #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6 +#define VHOST_USER_PROTOCOL_F_CONFIG 9 #define VHOST_LOG_PAGE 0x1000 @@ -78,6 +83,8 @@ typedef enum VhostUserRequest { VHOST_USER_SET_PROTOCOL_FEATURES = 16, VHOST_USER_GET_QUEUE_NUM = 17, VHOST_USER_SET_VRING_ENABLE = 18, + VHOST_USER_GET_CONFIG = 24, + VHOST_USER_SET_CONFIG = 25, VHOST_USER_MAX } VhostUserRequest; @@ -137,6 +144,7 @@ enum { enum { VHOST_USER_NET, + VHOST_USER_GPIO, }; typedef struct TestServer { @@ -168,10 +176,11 @@ struct vhost_user_ops { const char *chr_opts); /* VHOST-USER commands. */ + uint64_t (*get_features)(TestServer *s); void (*set_features)(TestServer *s, CharBackend *chr, - VhostUserMsg *msg); + VhostUserMsg *msg); void (*get_protocol_features)(TestServer *s, - CharBackend *chr, VhostUserMsg *msg); + CharBackend *chr, VhostUserMsg *msg); }; static const char *init_hugepagefs(void); @@ -194,6 +203,19 @@ static void append_vhost_net_opts(TestServer *s, GString *cmd_line, chr_opts, s->chr_name); } +/* + * For GPIO there are no other magic devices we need to add (like + * block or netdev) so all we need to worry about is the vhost-user + * chardev socket. + */ +static void append_vhost_gpio_opts(TestServer *s, GString *cmd_line, + const char *chr_opts) +{ + g_string_append_printf(cmd_line, QEMU_CMD_CHR, + s->chr_name, s->socket_path, + chr_opts); +} + static void append_mem_opts(TestServer *server, GString *cmd_line, int size, enum test_memfd memfd) { @@ -316,7 +338,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) } if (size != VHOST_USER_HDR_SIZE) { - g_test_message("Wrong message size received %d", size); + qos_printf("%s: Wrong message size received %d\n", __func__, size); return; } @@ -327,28 +349,30 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) p += VHOST_USER_HDR_SIZE; size = qemu_chr_fe_read_all(chr, p, msg.size); if (size != msg.size) { - g_test_message("Wrong message size received %d != %d", - size, msg.size); + qos_printf("%s: Wrong message size received %d != %d\n", + __func__, size, msg.size); return; } } switch (msg.request) { case VHOST_USER_GET_FEATURES: + /* Mandatory for tests to define get_features */ + g_assert(s->vu_ops->get_features); + /* send back features to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.u64); - msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL | - 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; - if (s->queues > 1) { - msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ; - } + if (s->test_flags >= TEST_FLAGS_BAD) { msg.payload.u64 = 0; s->test_flags = TEST_FLAGS_END; + } else { + msg.payload.u64 = s->vu_ops->get_features(s); } - p = (uint8_t *) &msg; - qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); + + qemu_chr_fe_write_all(chr, (uint8_t *) &msg, + VHOST_USER_HDR_SIZE + msg.size); break; case VHOST_USER_SET_FEATURES: @@ -357,12 +381,55 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) } break; + case VHOST_USER_SET_OWNER: + /* + * We don't need to do anything here, the remote is just + * letting us know it is in charge. Just log it. + */ + qos_printf("set_owner: start of session\n"); + break; + case VHOST_USER_GET_PROTOCOL_FEATURES: if (s->vu_ops->get_protocol_features) { s->vu_ops->get_protocol_features(s, chr, &msg); } break; + case VHOST_USER_GET_CONFIG: + /* + * Treat GET_CONFIG as a NOP and just reply and let the guest + * consider we have updated its memory. Tests currently don't + * require working configs. + */ + msg.flags |= VHOST_USER_REPLY_MASK; + p = (uint8_t *) &msg; + qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); + break; + + case VHOST_USER_SET_PROTOCOL_FEATURES: + /* + * We did set VHOST_USER_F_PROTOCOL_FEATURES so its valid for + * the remote end to send this. There is no handshake reply so + * just log the details for debugging. + */ + qos_printf("set_protocol_features: 0x%"PRIx64 "\n", msg.payload.u64); + break; + + /* + * A real vhost-user backend would actually set the size and + * address of the vrings but we can simply report them. + */ + case VHOST_USER_SET_VRING_NUM: + qos_printf("set_vring_num: %d/%d\n", + msg.payload.state.index, msg.payload.state.num); + break; + case VHOST_USER_SET_VRING_ADDR: + qos_printf("set_vring_addr: 0x%"PRIx64"/0x%"PRIx64"/0x%"PRIx64"\n", + msg.payload.addr.avail_user_addr, + msg.payload.addr.desc_user_addr, + msg.payload.addr.used_user_addr); + break; + case VHOST_USER_GET_VRING_BASE: /* send back vring base to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; @@ -427,7 +494,18 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; + case VHOST_USER_SET_VRING_ENABLE: + /* + * Another case we ignore as we don't need to respond. With a + * fully functioning vhost-user we would enable/disable the + * vring monitoring. + */ + qos_printf("set_vring(%d)=%s\n", msg.payload.state.index, + msg.payload.state.num ? "enabled" : "disabled"); + break; + default: + qos_printf("vhost-user: un-handled message: %d\n", msg.request); break; } @@ -450,7 +528,7 @@ static const char *init_hugepagefs(void) } if (access(path, R_OK | W_OK | X_OK)) { - g_test_message("access on path (%s): %s", path, strerror(errno)); + qos_printf("access on path (%s): %s", path, strerror(errno)); g_test_fail(); return NULL; } @@ -460,13 +538,13 @@ static const char *init_hugepagefs(void) } while (ret != 0 && errno == EINTR); if (ret != 0) { - g_test_message("statfs on path (%s): %s", path, strerror(errno)); + qos_printf("statfs on path (%s): %s", path, strerror(errno)); g_test_fail(); return NULL; } if (fs.f_type != HUGETLBFS_MAGIC) { - g_test_message("Warning: path not on HugeTLBFS: %s", path); + qos_printf("Warning: path not on HugeTLBFS: %s", path); g_test_fail(); return NULL; } @@ -482,8 +560,8 @@ static TestServer *test_server_new(const gchar *name, struct vhost_user_ops *ops) { TestServer *server = g_new0(TestServer, 1); - char template[] = "/tmp/vhost-test-XXXXXX"; - const char *tmpfs; + g_autofree const char *tmpfs = NULL; + GError *err = NULL; server->context = g_main_context_new(); server->loop = g_main_loop_new(server->context, FALSE); @@ -491,9 +569,11 @@ static TestServer *test_server_new(const gchar *name, /* run the main loop thread so the chardev may operate */ server->thread = g_thread_new(NULL, thread_function, server->loop); - tmpfs = mkdtemp(template); + tmpfs = g_dir_make_tmp("vhost-test-XXXXXX", &err); if (!tmpfs) { - g_test_message("mkdtemp on path (%s): %s", template, strerror(errno)); + g_test_message("g_dir_make_tmp on path (%s): %s", tmpfs, + err->message); + g_error_free(err); } g_assert(tmpfs); @@ -936,11 +1016,23 @@ static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc) wait_for_rings_started(s, s->queues * 2); } -static void vu_net_set_features(TestServer *s, CharBackend *chr, - VhostUserMsg *msg) + +static uint64_t vu_net_get_features(TestServer *s) { - g_assert_cmpint(msg->payload.u64 & - (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), !=, 0ULL); + uint64_t features = 0x1ULL << VHOST_F_LOG_ALL | + 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; + + if (s->queues > 1) { + features |= 0x1ULL << VIRTIO_NET_F_MQ; + } + + return features; +} + +static void vu_net_set_features(TestServer *s, CharBackend *chr, + VhostUserMsg *msg) +{ + g_assert(msg->payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES)); if (s->test_flags == TEST_FLAGS_DISCONNECT) { qemu_chr_fe_disconnect(chr); s->test_flags = TEST_FLAGS_BAD; @@ -967,6 +1059,7 @@ static struct vhost_user_ops g_vu_net_ops = { .append_opts = append_vhost_net_opts, + .get_features = vu_net_get_features, .set_features = vu_net_set_features, .get_protocol_features = vu_net_get_protocol_features, }; @@ -1015,3 +1108,51 @@ static void register_vhost_user_test(void) test_multiqueue, &opts); } libqos_init(register_vhost_user_test); + +static uint64_t vu_gpio_get_features(TestServer *s) +{ + return 0x1ULL << VIRTIO_F_VERSION_1 | + 0x1ULL << VIRTIO_GPIO_F_IRQ | + 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; +} + +/* + * This stub can't handle all the message types but we should reply + * that we support VHOST_USER_PROTOCOL_F_CONFIG as gpio would use it + * talking to a read vhost-user daemon. + */ +static void vu_gpio_get_protocol_features(TestServer *s, CharBackend *chr, + VhostUserMsg *msg) +{ + /* send back features to qemu */ + msg->flags |= VHOST_USER_REPLY_MASK; + msg->size = sizeof(m.payload.u64); + msg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_CONFIG; + + qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size); +} + +static struct vhost_user_ops g_vu_gpio_ops = { + .type = VHOST_USER_GPIO, + + .append_opts = append_vhost_gpio_opts, + + .get_features = vu_gpio_get_features, + .set_features = vu_net_set_features, + .get_protocol_features = vu_gpio_get_protocol_features, +}; + +static void register_vhost_gpio_test(void) +{ + QOSGraphTestOptions opts = { + .before = vhost_user_test_setup, + .subprocess = true, + .arg = &g_vu_gpio_ops, + }; + + qemu_add_opts(&qemu_chardev_opts); + + qos_add_test("read-guest-mem/memfile", + "vhost-user-gpio", test_read_guest_mem, &opts); +} +libqos_init(register_vhost_gpio_test); diff --git a/tests/qtest/virtio-blk-test.c b/tests/qtest/virtio-blk-test.c index dc5eed31c8..19c01f808b 100644 --- a/tests/qtest/virtio-blk-test.c +++ b/tests/qtest/virtio-blk-test.c @@ -49,10 +49,10 @@ static void drive_destroy(void *path) static char *drive_create(void) { int fd, ret; - char *t_path = g_strdup("/tmp/qtest.XXXXXX"); + char *t_path; /* Create a temporary raw image */ - fd = mkstemp(t_path); + fd = g_file_open_tmp("qtest.XXXXXX", &t_path, NULL); g_assert_cmpint(fd, >=, 0); ret = ftruncate(fd, TEST_IMAGE_SIZE); g_assert_cmpint(ret, ==, 0); diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c index 443ee56de9..4a809590bf 100644 --- a/tests/qtest/virtio-net-failover.c +++ b/tests/qtest/virtio-net-failover.c @@ -588,6 +588,7 @@ static void test_hotplug_2_reverse(void) machine_stop(qts); } +#ifndef _WIN32 static QDict *migrate_status(QTestState *qts) { QDict *resp, *ret; @@ -1827,6 +1828,7 @@ static void test_multi_in(gconstpointer opaque) machine_stop(qts); } +#endif /* _WIN32 */ int main(int argc, char **argv) { @@ -1857,7 +1859,11 @@ int main(int argc, char **argv) qtest_add_func("failover-virtio-net/hotplug/2_reverse", test_hotplug_2_reverse); - /* migration tests */ +#ifndef _WIN32 + /* + * These migration tests cases use the exec migration protocol, + * which is unsupported on Windows. + */ qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile, test_migrate_out); qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile, @@ -1886,6 +1892,7 @@ int main(int argc, char **argv) tmpfile, test_multi_out); qtest_add_data_func("failover-virtio-net/migrate/multi/in", tmpfile, test_multi_in); +#endif /* _WIN32 */ ret = g_test_run(); diff --git a/tests/qtest/virtio-net-test.c b/tests/qtest/virtio-net-test.c index 6ded252901..dff43f0f60 100644 --- a/tests/qtest/virtio-net-test.c +++ b/tests/qtest/virtio-net-test.c @@ -165,8 +165,6 @@ static void stop_cont_test(void *obj, void *data, QGuestAllocator *t_alloc) rx_stop_cont_test(dev, t_alloc, rx, sv[0]); } -#endif - static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtioPCIDevice *dev = obj; @@ -286,6 +284,8 @@ static void *virtio_net_test_setup(GString *cmd_line, void *arg) return sv; } +#endif /* _WIN32 */ + static void large_tx(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtioNet *dev = obj; @@ -319,16 +319,15 @@ static void *virtio_net_test_setup_nosocket(GString *cmd_line, void *arg) static void register_virtio_net_test(void) { - QOSGraphTestOptions opts = { - .before = virtio_net_test_setup, - }; + QOSGraphTestOptions opts = { 0 }; - qos_add_test("hotplug", "virtio-net-pci", hotplug, &opts); #ifndef _WIN32 + opts.before = virtio_net_test_setup; + qos_add_test("hotplug", "virtio-net-pci", hotplug, &opts); qos_add_test("basic", "virtio-net", send_recv_test, &opts); qos_add_test("rx_stop_cont", "virtio-net", stop_cont_test, &opts); -#endif qos_add_test("announce-self", "virtio-net", announce_self, &opts); +#endif /* These tests do not need a loopback backend. */ opts.before = virtio_net_test_setup_nosocket; diff --git a/tests/qtest/virtio-scsi-test.c b/tests/qtest/virtio-scsi-test.c index 8ceb12aacd..ceaa7f2415 100644 --- a/tests/qtest/virtio-scsi-test.c +++ b/tests/qtest/virtio-scsi-test.c @@ -268,7 +268,7 @@ static void test_iothread_attach_node(void *obj, void *data, QVirtioSCSIPCI *scsi_pci = obj; QVirtioSCSI *scsi = &scsi_pci->scsi; QVirtioSCSIQueues *vs; - char tmp_path[] = "/tmp/qtest.XXXXXX"; + g_autofree char *tmp_path = NULL; int fd; int ret; @@ -282,7 +282,7 @@ static void test_iothread_attach_node(void *obj, void *data, vs = qvirtio_scsi_init(scsi->vdev); /* Create a temporary qcow2 overlay*/ - fd = mkstemp(tmp_path); + fd = g_file_open_tmp("qtest.XXXXXX", &tmp_path, NULL); g_assert(fd >= 0); close(fd); diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index e68830af15..75257f2b29 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -31,7 +31,7 @@ all: -include ../config-host.mak --include ../config-$(TARGET).mak +-include config-target.mak # Get semihosting definitions for user-mode emulation ifeq ($(filter %-softmmu, $(TARGET)),) @@ -40,15 +40,25 @@ endif # for including , in command strings COMMA := , +NULL := +SPACE := $(NULL) # +TARGET_PREFIX=tests/tcg/$(TARGET):$(SPACE) -quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) +quiet-@ = $(if $(V),,@$(if $1,printf " %-7s %s\n" "$(strip $1)" "$(strip $2)" && )) +quiet-command = $(call quiet-@,$2,$3)$1 + +cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>&1 +cc-option = if $(call cc-test, $1); then \ + echo "$(TARGET_PREFIX)$1 detected" && echo "$(strip $2)=y" >&3; else \ + echo "$(TARGET_PREFIX)$1 not detected"; fi # $1 = test name, $2 = cmd, $3 = desc ifeq ($(filter %-softmmu, $(TARGET)),) run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2 > $1.out, \ - "TEST",$3) + TEST,$(or $3, $*, $<) on $(TARGET_NAME)) else -run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2,"TEST",$3) +run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2, \ + TEST,$(or $3, $*, $<) on $(TARGET_NAME)) endif # $1 = test name, $2 = reference @@ -56,7 +66,7 @@ endif # we know it failed and then force failure at the end. diff-out = $(call quiet-command, diff -q $1.out $2 || \ (diff -u $1.out $2 | head -n 10 && false), \ - "DIFF","$1.out with $2") + DIFF,$1.out with $2) # $1 = test name, $2 = reason skip-test = @printf " SKIPPED %s on $(TARGET_NAME) because %s\n" $1 $2 @@ -155,21 +165,19 @@ RUN_TESTS+=$(EXTRA_RUNS) ifeq ($(filter %-softmmu, $(TARGET)),) run-%: % - $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<, "$< on $(TARGET_NAME)") + $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<) run-plugin-%: $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ -d plugin -D $*.pout \ - $(call strip-plugin,$<), \ - "$* on $(TARGET_NAME)") + $(call strip-plugin,$<)) else run-%: % $(call run-test, $<, \ $(QEMU) -monitor none -display none \ -chardev file$(COMMA)path=$<.out$(COMMA)id=output \ - $(QEMU_OPTS) $<, \ - "$< on $(TARGET_NAME)") + $(QEMU_OPTS) $<) run-plugin-%: $(call run-test, $@, \ @@ -177,8 +185,7 @@ run-plugin-%: -chardev file$(COMMA)path=$@.out$(COMMA)id=output \ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ -d plugin -D $*.pout \ - $(QEMU_OPTS) $(call strip-plugin,$<), \ - "$* on $(TARGET_NAME)") + $(QEMU_OPTS) $(call strip-plugin,$<)) endif gdb-%: % @@ -188,4 +195,7 @@ gdb-%: % run: $(RUN_TESTS) clean: - rm -f $(TESTS) *.o + rm -f $(TESTS) *.o $(CLEANFILES) + +distclean: + rm -f config-cc.mak config-target.mak ../config-$(TARGET).mak diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target index f6fcd4829e..a1368905f5 100644 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ b/tests/tcg/aarch64/Makefile.softmmu-target @@ -19,6 +19,11 @@ EXTRA_RUNS+=$(MULTIARCH_RUNS) CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc +config-cc.mak: Makefile + $(quiet-@)( \ + $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3)) 3> config-cc.mak +-include config-cc.mak + # building head blobs .PRECIOUS: $(CRT_OBJS) @@ -50,8 +55,7 @@ run-memory-record: memory-record memory $(QEMU) -monitor none -display none \ -chardev file$(COMMA)path=$<.out$(COMMA)id=output \ -icount shift=5$(COMMA)rr=record$(COMMA)rrfile=record.bin \ - $(QEMU_OPTS) memory, \ - "$< on $(TARGET_NAME)") + $(QEMU_OPTS) memory) .PHONY: memory-replay run-memory-replay: memory-replay run-memory-record @@ -59,8 +63,7 @@ run-memory-replay: memory-replay run-memory-record $(QEMU) -monitor none -display none \ -chardev file$(COMMA)path=$<.out$(COMMA)id=output \ -icount shift=5$(COMMA)rr=replay$(COMMA)rrfile=record.bin \ - $(QEMU_OPTS) memory, \ - "$< on $(TARGET_NAME)") + $(QEMU_OPTS) memory) EXTRA_RUNS+=run-memory-replay diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index d6a74d24dc..fc8d90ed69 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -17,6 +17,15 @@ run-fcvt: fcvt $(call run-test,$<,$(QEMU) $<, "$< on $(TARGET_NAME)") $(call diff-out,$<,$(AARCH64_SRC)/fcvt.ref) +config-cc.mak: Makefile + $(quiet-@)( \ + $(call cc-option,-march=armv8.1-a+sve, CROSS_CC_HAS_SVE); \ + $(call cc-option,-march=armv8.1-a+sve2, CROSS_CC_HAS_SVE2); \ + $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \ + $(call cc-option,-mbranch-protection=standard, CROSS_CC_HAS_ARMV8_BTI); \ + $(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE)) 3> config-cc.mak +-include config-cc.mak + # Pauth Tests ifneq ($(CROSS_CC_HAS_ARMV8_3),) AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5 @@ -55,7 +64,7 @@ sha1-vector: CFLAGS=-O3 sha1-vector: sha1.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) run-sha1-vector: sha1-vector run-sha1 - $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<, "$< on $(TARGET_NAME)") + $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<) $(call diff-out, sha1-vector, sha1.out) TESTS += sha1-vector @@ -75,14 +84,14 @@ run-gdbstub-sysregs: sysregs --gdb $(HAVE_GDB_BIN) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve.py, \ - "basic gdbstub SVE support") + basic gdbstub SVE support) run-gdbstub-sve-ioctls: sve-ioctls $(call run-test, $@, $(GDB_SCRIPT) \ --gdb $(HAVE_GDB_BIN) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve-ioctl.py, \ - "basic gdbstub SVE ZLEN support") + basic gdbstub SVE ZLEN support) EXTRA_RUNS += run-gdbstub-sysregs run-gdbstub-sve-ioctls endif diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target index 2f815120a5..b3b1504a1c 100644 --- a/tests/tcg/arm/Makefile.target +++ b/tests/tcg/arm/Makefile.target @@ -26,7 +26,7 @@ ARM_TESTS += fcvt fcvt: LDFLAGS+=-lm # fcvt: CFLAGS+=-march=armv8.2-a+fp16 -mfpu=neon-fp-armv8 run-fcvt: fcvt - $(call run-test,fcvt,$(QEMU) $<,"$< on $(TARGET_NAME)") + $(call run-test,fcvt,$(QEMU) $<) $(call diff-out,fcvt,$(ARM_SRC)/fcvt.ref) # PC alignment test @@ -44,13 +44,12 @@ semihosting-arm: semihosting.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) run-semihosting-arm: semihosting-arm - $(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)") + $(call run-test,$<,$(QEMU) $< 2> $<.err) run-plugin-semihosting-arm-with-%: $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ - $(call strip-plugin,$<) 2> $<.err, \ - "$< on $(TARGET_NAME) with $*") + $(call strip-plugin,$<) 2> $<.err) ARM_TESTS += semiconsole-arm @@ -75,7 +74,7 @@ sha1-vector: CFLAGS=-O3 sha1-vector: sha1.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) run-sha1-vector: sha1-vector run-sha1 - $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<, "$< on $(TARGET_NAME)") + $(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<) $(call diff-out, sha1-vector, sha1.out) ARM_TESTS += sha1-vector diff --git a/tests/tcg/cris/Makefile.target b/tests/tcg/cris/Makefile.target index e72d3cbdb2..372287bd03 100644 --- a/tests/tcg/cris/Makefile.target +++ b/tests/tcg/cris/Makefile.target @@ -56,4 +56,4 @@ SIMG:=cris-axis-linux-gnu-run # e.g.: make -f ../../tests/tcg/Makefile run-check_orm-on-sim run-%-on-sim: - $(call run-test, $<, $(SIMG) $<, "$< on $(TARGET_NAME) with SIM") + $(call run-test, $<, $(SIMG) $<) diff --git a/tests/tcg/hexagon/float_convd.ref b/tests/tcg/hexagon/float_convd.ref new file mode 100644 index 0000000000..aba1e13e35 --- /dev/null +++ b/tests/tcg/hexagon/float_convd.ref @@ -0,0 +1,988 @@ +### Rounding to nearest +from double: f64(nan:0x007ff4000000000000) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(-nan:0x00fff8000000000000) + to single: f32(-nan:0xffffffff) (OK) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(-inf:0x00fff0000000000000) + to single: f32(-inf:0xff800000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffffffffff0000000p+1023:0x00ffefffffffffffff) + to single: f32(-inf:0xff800000) (OVERFLOW INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.1874b135ff6540000000p+103:0x00c661874b135ff654) + to single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) (INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.c0bab523323b90000000p+99:0x00c62c0bab523323b9) + to single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) (INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p+1:0x00c000000000000000) + to single: f32(-0x1.00000000000000000000p+1:0xc0000000) (OK) + to int32: -2 (OK) + to int64: -2 (OK) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p+0:0x00bff0000000000000) + to single: f32(-0x1.00000000000000000000p+0:0xbf800000) (OK) + to int32: -1 (OK) + to int64: -1 (OK) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p-1022:0x008010000000000000) + to single: f32(-0x0.00000000000000000000p+0:0x80000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) + to single: f32(-0x1.00000000000000000000p-126:0x80800000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(0x0.00000000000000000000p+0:00000000000000000000) + to single: f32(0x0.00000000000000000000p+0:0000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from double: f64(0x1.00000000000000000000p-126:0x003810000000000000) + to single: f32(0x1.00000000000000000000p-126:0x00800000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000001c5f680000000p-25:0x003e600000001c5f68) + to single: f32(0x1.00000000000000000000p-25:0x33000000) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.ffffe6cb2fa820000000p-25:0x003e6ffffe6cb2fa82) + to single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.ff801a9af58a10000000p-15:0x003f0ff801a9af58a1) + to single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000c06a1ef50000000p-14:0x003f100000c06a1ef5) + to single: f32(0x1.00000c00000000000000p-14:0x38800006) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) + to single: f32(0x1.00000000000000000000p+0:0x3f800000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) + to single: f32(0x1.00400000000000000000p+0:0x3f802000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from double: f64(0x1.00000000000000000000p-1022:0x000010000000000000) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.3d5054450ed000000000p-1023:0x000009ea82a2287680) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.5731f750864200000000p-1023:0x00000ab98fba843210) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) + to single: f32(0x1.00000000000000000000p+0:0x3f800000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from double: f64(0x1.00000000000000000000p+1:0x004000000000000000) + to single: f32(0x1.00000000000000000000p+1:0x40000000) (OK) + to int32: 2 (OK) + to int64: 2 (OK) + to uint32: 2 (OK) + to uint64: 2 (OK) +from double: f64(0x1.5bf0a8b1457690000000p+1:0x004005bf0a8b145769) + to single: f32(0x1.5bf0a800000000000000p+1:0x402df854) (INEXACT ) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from double: f64(0x1.921fb54442d180000000p+1:0x00400921fb54442d18) + to single: f32(0x1.921fb600000000000000p+1:0x40490fdb) (INEXACT ) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) + to single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) (OK) + to int32: 65503 (OK) + to int64: 65503 (OK) + to uint32: 65503 (OK) + to uint64: 65503 (OK) +from double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) + to single: f32(0x1.ffc00000000000000000p+15:0x477fe000) (OK) + to int32: 65504 (OK) + to int64: 65504 (OK) + to uint32: 65504 (OK) + to uint64: 65504 (OK) +from double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) + to single: f32(0x1.ffc20000000000000000p+15:0x477fe100) (OK) + to int32: 65505 (OK) + to int64: 65505 (OK) + to uint32: 65505 (OK) + to uint64: 65505 (OK) +from double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) + to single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) (OK) + to int32: 131007 (OK) + to int64: 131007 (OK) + to uint32: 131007 (OK) + to uint64: 131007 (OK) +from double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) + to single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) (OK) + to int32: 131008 (OK) + to int64: 131008 (OK) + to uint32: 131008 (OK) + to uint64: 131008 (OK) +from double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) + to single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) (OK) + to int32: 131009 (OK) + to int64: 131009 (OK) + to uint32: 131009 (OK) + to uint64: 131009 (OK) +from double: f64(0x1.fffffffc000000000000p+30:0x0041dfffffffc00000) + to single: f32(0x1.00000000000000000000p+31:0x4f000000) (INEXACT ) + to int32: 2147483647 (OK) + to int64: 2147483647 (OK) + to uint32: 2147483647 (OK) + to uint64: 2147483647 (OK) +from double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(0x1.fffffffffffff0000000p+1023:0x007fefffffffffffff) + to single: f32(inf:0x7f800000) (OVERFLOW INEXACT ) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(inf:0x007ff0000000000000) + to single: f32(inf:0x7f800000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff8000000000000) + to single: f32(-nan:0xffffffff) (OK) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff0000000000001) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff4000000000000) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +### Rounding upwards +from double: f64(nan:0x007ff4000000000000) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(-nan:0x00fff8000000000000) + to single: f32(-nan:0xffffffff) (OK) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(-inf:0x00fff0000000000000) + to single: f32(-inf:0xff800000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffffffffff0000000p+1023:0x00ffefffffffffffff) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OVERFLOW INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.1874b135ff6540000000p+103:0x00c661874b135ff654) + to single: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) (INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.c0bab523323b90000000p+99:0x00c62c0bab523323b9) + to single: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) (INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p+1:0x00c000000000000000) + to single: f32(-0x1.00000000000000000000p+1:0xc0000000) (OK) + to int32: -2 (OK) + to int64: -2 (OK) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p+0:0x00bff0000000000000) + to single: f32(-0x1.00000000000000000000p+0:0xbf800000) (OK) + to int32: -1 (OK) + to int64: -1 (OK) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p-1022:0x008010000000000000) + to single: f32(-0x0.00000000000000000000p+0:0x80000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) + to single: f32(-0x1.00000000000000000000p-126:0x80800000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(0x0.00000000000000000000p+0:00000000000000000000) + to single: f32(0x0.00000000000000000000p+0:0000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from double: f64(0x1.00000000000000000000p-126:0x003810000000000000) + to single: f32(0x1.00000000000000000000p-126:0x00800000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000001c5f680000000p-25:0x003e600000001c5f68) + to single: f32(0x1.00000200000000000000p-25:0x33000001) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.ffffe6cb2fa820000000p-25:0x003e6ffffe6cb2fa82) + to single: f32(0x1.ffffe800000000000000p-25:0x337ffff4) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.ff801a9af58a10000000p-15:0x003f0ff801a9af58a1) + to single: f32(0x1.ff801c00000000000000p-15:0x387fc00e) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000c06a1ef50000000p-14:0x003f100000c06a1ef5) + to single: f32(0x1.00000e00000000000000p-14:0x38800007) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) + to single: f32(0x1.00000000000000000000p+0:0x3f800000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) + to single: f32(0x1.00400000000000000000p+0:0x3f802000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from double: f64(0x1.00000000000000000000p-1022:0x000010000000000000) + to single: f32(0x1.00000000000000000000p-149:0x00000001) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.3d5054450ed000000000p-1023:0x000009ea82a2287680) + to single: f32(0x1.00000000000000000000p-149:0x00000001) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.5731f750864200000000p-1023:0x00000ab98fba843210) + to single: f32(0x1.00000000000000000000p-149:0x00000001) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) + to single: f32(0x1.00000000000000000000p+0:0x3f800000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from double: f64(0x1.00000000000000000000p+1:0x004000000000000000) + to single: f32(0x1.00000000000000000000p+1:0x40000000) (OK) + to int32: 2 (OK) + to int64: 2 (OK) + to uint32: 2 (OK) + to uint64: 2 (OK) +from double: f64(0x1.5bf0a8b1457690000000p+1:0x004005bf0a8b145769) + to single: f32(0x1.5bf0aa00000000000000p+1:0x402df855) (INEXACT ) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from double: f64(0x1.921fb54442d180000000p+1:0x00400921fb54442d18) + to single: f32(0x1.921fb600000000000000p+1:0x40490fdb) (INEXACT ) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) + to single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) (OK) + to int32: 65503 (OK) + to int64: 65503 (OK) + to uint32: 65503 (OK) + to uint64: 65503 (OK) +from double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) + to single: f32(0x1.ffc00000000000000000p+15:0x477fe000) (OK) + to int32: 65504 (OK) + to int64: 65504 (OK) + to uint32: 65504 (OK) + to uint64: 65504 (OK) +from double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) + to single: f32(0x1.ffc20000000000000000p+15:0x477fe100) (OK) + to int32: 65505 (OK) + to int64: 65505 (OK) + to uint32: 65505 (OK) + to uint64: 65505 (OK) +from double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) + to single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) (OK) + to int32: 131007 (OK) + to int64: 131007 (OK) + to uint32: 131007 (OK) + to uint64: 131007 (OK) +from double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) + to single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) (OK) + to int32: 131008 (OK) + to int64: 131008 (OK) + to uint32: 131008 (OK) + to uint64: 131008 (OK) +from double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) + to single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) (OK) + to int32: 131009 (OK) + to int64: 131009 (OK) + to uint32: 131009 (OK) + to uint64: 131009 (OK) +from double: f64(0x1.fffffffc000000000000p+30:0x0041dfffffffc00000) + to single: f32(0x1.00000000000000000000p+31:0x4f000000) (INEXACT ) + to int32: 2147483647 (OK) + to int64: 2147483647 (OK) + to uint32: 2147483647 (OK) + to uint64: 2147483647 (OK) +from double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(0x1.fffffffffffff0000000p+1023:0x007fefffffffffffff) + to single: f32(inf:0x7f800000) (OVERFLOW INEXACT ) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(inf:0x007ff0000000000000) + to single: f32(inf:0x7f800000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff8000000000000) + to single: f32(-nan:0xffffffff) (OK) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff0000000000001) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff4000000000000) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +### Rounding downwards +from double: f64(nan:0x007ff4000000000000) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(-nan:0x00fff8000000000000) + to single: f32(-nan:0xffffffff) (OK) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(-inf:0x00fff0000000000000) + to single: f32(-inf:0xff800000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffffffffff0000000p+1023:0x00ffefffffffffffff) + to single: f32(-inf:0xff800000) (OVERFLOW INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.1874b135ff6540000000p+103:0x00c661874b135ff654) + to single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) (INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.c0bab523323b90000000p+99:0x00c62c0bab523323b9) + to single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) (INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p+1:0x00c000000000000000) + to single: f32(-0x1.00000000000000000000p+1:0xc0000000) (OK) + to int32: -2 (OK) + to int64: -2 (OK) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p+0:0x00bff0000000000000) + to single: f32(-0x1.00000000000000000000p+0:0xbf800000) (OK) + to int32: -1 (OK) + to int64: -1 (OK) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p-1022:0x008010000000000000) + to single: f32(-0x1.00000000000000000000p-149:0x80000001) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) + to single: f32(-0x1.00000000000000000000p-126:0x80800000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(0x0.00000000000000000000p+0:00000000000000000000) + to single: f32(0x0.00000000000000000000p+0:0000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from double: f64(0x1.00000000000000000000p-126:0x003810000000000000) + to single: f32(0x1.00000000000000000000p-126:0x00800000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000001c5f680000000p-25:0x003e600000001c5f68) + to single: f32(0x1.00000000000000000000p-25:0x33000000) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.ffffe6cb2fa820000000p-25:0x003e6ffffe6cb2fa82) + to single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.ff801a9af58a10000000p-15:0x003f0ff801a9af58a1) + to single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000c06a1ef50000000p-14:0x003f100000c06a1ef5) + to single: f32(0x1.00000c00000000000000p-14:0x38800006) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) + to single: f32(0x1.00000000000000000000p+0:0x3f800000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) + to single: f32(0x1.00400000000000000000p+0:0x3f802000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from double: f64(0x1.00000000000000000000p-1022:0x000010000000000000) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.3d5054450ed000000000p-1023:0x000009ea82a2287680) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.5731f750864200000000p-1023:0x00000ab98fba843210) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) + to single: f32(0x1.00000000000000000000p+0:0x3f800000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from double: f64(0x1.00000000000000000000p+1:0x004000000000000000) + to single: f32(0x1.00000000000000000000p+1:0x40000000) (OK) + to int32: 2 (OK) + to int64: 2 (OK) + to uint32: 2 (OK) + to uint64: 2 (OK) +from double: f64(0x1.5bf0a8b1457690000000p+1:0x004005bf0a8b145769) + to single: f32(0x1.5bf0a800000000000000p+1:0x402df854) (INEXACT ) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from double: f64(0x1.921fb54442d180000000p+1:0x00400921fb54442d18) + to single: f32(0x1.921fb400000000000000p+1:0x40490fda) (INEXACT ) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) + to single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) (OK) + to int32: 65503 (OK) + to int64: 65503 (OK) + to uint32: 65503 (OK) + to uint64: 65503 (OK) +from double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) + to single: f32(0x1.ffc00000000000000000p+15:0x477fe000) (OK) + to int32: 65504 (OK) + to int64: 65504 (OK) + to uint32: 65504 (OK) + to uint64: 65504 (OK) +from double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) + to single: f32(0x1.ffc20000000000000000p+15:0x477fe100) (OK) + to int32: 65505 (OK) + to int64: 65505 (OK) + to uint32: 65505 (OK) + to uint64: 65505 (OK) +from double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) + to single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) (OK) + to int32: 131007 (OK) + to int64: 131007 (OK) + to uint32: 131007 (OK) + to uint64: 131007 (OK) +from double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) + to single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) (OK) + to int32: 131008 (OK) + to int64: 131008 (OK) + to uint32: 131008 (OK) + to uint64: 131008 (OK) +from double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) + to single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) (OK) + to int32: 131009 (OK) + to int64: 131009 (OK) + to uint32: 131009 (OK) + to uint64: 131009 (OK) +from double: f64(0x1.fffffffc000000000000p+30:0x0041dfffffffc00000) + to single: f32(0x1.fffffe00000000000000p+30:0x4effffff) (INEXACT ) + to int32: 2147483647 (OK) + to int64: 2147483647 (OK) + to uint32: 2147483647 (OK) + to uint64: 2147483647 (OK) +from double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(0x1.fffffffffffff0000000p+1023:0x007fefffffffffffff) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OVERFLOW INEXACT ) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(inf:0x007ff0000000000000) + to single: f32(inf:0x7f800000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff8000000000000) + to single: f32(-nan:0xffffffff) (OK) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff0000000000001) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff4000000000000) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +### Rounding to zero +from double: f64(nan:0x007ff4000000000000) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(-nan:0x00fff8000000000000) + to single: f32(-nan:0xffffffff) (OK) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(-inf:0x00fff0000000000000) + to single: f32(-inf:0xff800000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffffffffff0000000p+1023:0x00ffefffffffffffff) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OVERFLOW INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) + to single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.1874b135ff6540000000p+103:0x00c661874b135ff654) + to single: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) (INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.c0bab523323b90000000p+99:0x00c62c0bab523323b9) + to single: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) (INEXACT ) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p+1:0x00c000000000000000) + to single: f32(-0x1.00000000000000000000p+1:0xc0000000) (OK) + to int32: -2 (OK) + to int64: -2 (OK) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p+0:0x00bff0000000000000) + to single: f32(-0x1.00000000000000000000p+0:0xbf800000) (OK) + to int32: -1 (OK) + to int64: -1 (OK) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p-1022:0x008010000000000000) + to single: f32(-0x0.00000000000000000000p+0:0x80000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) + to single: f32(-0x1.00000000000000000000p-126:0x80800000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from double: f64(0x0.00000000000000000000p+0:00000000000000000000) + to single: f32(0x0.00000000000000000000p+0:0000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from double: f64(0x1.00000000000000000000p-126:0x003810000000000000) + to single: f32(0x1.00000000000000000000p-126:0x00800000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000001c5f680000000p-25:0x003e600000001c5f68) + to single: f32(0x1.00000000000000000000p-25:0x33000000) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.ffffe6cb2fa820000000p-25:0x003e6ffffe6cb2fa82) + to single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.ff801a9af58a10000000p-15:0x003f0ff801a9af58a1) + to single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000c06a1ef50000000p-14:0x003f100000c06a1ef5) + to single: f32(0x1.00000c00000000000000p-14:0x38800006) (INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) + to single: f32(0x1.00000000000000000000p+0:0x3f800000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) + to single: f32(0x1.00400000000000000000p+0:0x3f802000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from double: f64(0x1.00000000000000000000p-1022:0x000010000000000000) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.3d5054450ed000000000p-1023:0x000009ea82a2287680) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.5731f750864200000000p-1023:0x00000ab98fba843210) + to single: f32(0x0.00000000000000000000p+0:0000000000) (UNDERFLOW INEXACT ) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) + to single: f32(0x1.00000000000000000000p+0:0x3f800000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from double: f64(0x1.00000000000000000000p+1:0x004000000000000000) + to single: f32(0x1.00000000000000000000p+1:0x40000000) (OK) + to int32: 2 (OK) + to int64: 2 (OK) + to uint32: 2 (OK) + to uint64: 2 (OK) +from double: f64(0x1.5bf0a8b1457690000000p+1:0x004005bf0a8b145769) + to single: f32(0x1.5bf0a800000000000000p+1:0x402df854) (INEXACT ) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from double: f64(0x1.921fb54442d180000000p+1:0x00400921fb54442d18) + to single: f32(0x1.921fb400000000000000p+1:0x40490fda) (INEXACT ) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) + to single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) (OK) + to int32: 65503 (OK) + to int64: 65503 (OK) + to uint32: 65503 (OK) + to uint64: 65503 (OK) +from double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) + to single: f32(0x1.ffc00000000000000000p+15:0x477fe000) (OK) + to int32: 65504 (OK) + to int64: 65504 (OK) + to uint32: 65504 (OK) + to uint64: 65504 (OK) +from double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) + to single: f32(0x1.ffc20000000000000000p+15:0x477fe100) (OK) + to int32: 65505 (OK) + to int64: 65505 (OK) + to uint32: 65505 (OK) + to uint64: 65505 (OK) +from double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) + to single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) (OK) + to int32: 131007 (OK) + to int64: 131007 (OK) + to uint32: 131007 (OK) + to uint64: 131007 (OK) +from double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) + to single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) (OK) + to int32: 131008 (OK) + to int64: 131008 (OK) + to uint32: 131008 (OK) + to uint64: 131008 (OK) +from double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) + to single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) (OK) + to int32: 131009 (OK) + to int64: 131009 (OK) + to uint32: 131009 (OK) + to uint64: 131009 (OK) +from double: f64(0x1.fffffffc000000000000p+30:0x0041dfffffffc00000) + to single: f32(0x1.fffffe00000000000000p+30:0x4effffff) (INEXACT ) + to int32: 2147483647 (OK) + to int64: 2147483647 (OK) + to uint32: 2147483647 (OK) + to uint64: 2147483647 (OK) +from double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(0x1.fffffffffffff0000000p+1023:0x007fefffffffffffff) + to single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) (OVERFLOW INEXACT ) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(inf:0x007ff0000000000000) + to single: f32(inf:0x7f800000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff8000000000000) + to single: f32(-nan:0xffffffff) (OK) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff0000000000001) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from double: f64(nan:0x007ff4000000000000) + to single: f32(-nan:0xffffffff) (INVALID) + to int32: -1 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) diff --git a/tests/tcg/hexagon/hvx_misc.c b/tests/tcg/hexagon/hvx_misc.c index b896f5897e..6e2c9ab3cd 100644 --- a/tests/tcg/hexagon/hvx_misc.c +++ b/tests/tcg/hexagon/hvx_misc.c @@ -498,6 +498,49 @@ static void test_vsubuwsat_dv(void) check_output_w(__LINE__, 2); } +static void test_vshuff(void) +{ + /* Test that vshuff works when the two operands are the same register */ + const uint32_t splat = 0x089be55c; + const uint32_t shuff = 0x454fa926; + MMVector v0, v1; + + memset(expect, 0x12, sizeof(MMVector)); + memset(output, 0x34, sizeof(MMVector)); + + asm volatile("v25 = vsplat(%0)\n\t" + "vshuff(v25, v25, %1)\n\t" + "vmem(%2 + #0) = v25\n\t" + : /* no outputs */ + : "r"(splat), "r"(shuff), "r"(output) + : "v25", "memory"); + + /* + * The semantics of Hexagon are the operands are pass-by-value, so create + * two copies of the vsplat result. + */ + for (int i = 0; i < MAX_VEC_SIZE_BYTES / 4; i++) { + v0.uw[i] = splat; + v1.uw[i] = splat; + } + /* Do the vshuff operation */ + for (int offset = 1; offset < MAX_VEC_SIZE_BYTES; offset <<= 1) { + if (shuff & offset) { + for (int k = 0; k < MAX_VEC_SIZE_BYTES; k++) { + if (!(k & offset)) { + uint8_t tmp = v0.ub[k]; + v0.ub[k] = v1.ub[k + offset]; + v1.ub[k + offset] = tmp; + } + } + } + } + /* Put the result in the expect buffer for verification */ + expect[0] = v1; + + check_output_b(__LINE__, 1); +} + int main() { init_buffers(); @@ -533,6 +576,8 @@ int main() test_vadduwsat(); test_vsubuwsat_dv(); + test_vshuff(); + puts(err ? "FAIL" : "PASS"); return err ? 1 : 0; } diff --git a/tests/tcg/hexagon/load_unpack.c b/tests/tcg/hexagon/load_unpack.c index 3575a37a28..4aa26fc388 100644 --- a/tests/tcg/hexagon/load_unpack.c +++ b/tests/tcg/hexagon/load_unpack.c @@ -245,7 +245,7 @@ TEST_pr(loadbsw4_pr, long long, S, 4, 0x0000ff000000ff00LL, */ #define BxW_LOAD_pbr(SZ, RES, PTR) \ __asm__( \ - "r4 = #(1 << (16 - 3))\n\t" \ + "r4 = #(1 << (16 - 4))\n\t" \ "m0 = r4\n\t" \ "%0 = mem" #SZ "(%1++m0:brev)\n\t" \ : "=r"(RES), "+r"(PTR) \ @@ -273,15 +273,15 @@ void test_##NAME(void) \ } TEST_pbr(loadbzw2_pbr, int, Z, 0x00000000, - 0x00020081, 0x00060085, 0x00040083, 0x00080087) + 0x00020081, 0x000a0089, 0x00060085, 0x000e008d) TEST_pbr(loadbsw2_pbr, int, S, 0x0000ff00, - 0x00020081, 0x00060085, 0x00040083, 0x00080087) + 0x00020081, 0x000aff89, 0x0006ff85, 0x000eff8d) TEST_pbr(loadbzw4_pbr, long long, Z, 0x0000000000000000LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x0006008500040083LL, 0x000a008900080087LL) + 0x0004008300020081LL, 0x000c008b000a0089LL, + 0x0008008700060085LL, 0x0010008f000e008dLL) TEST_pbr(loadbsw4_pbr, long long, S, 0x0000ff000000ff00LL, - 0x0004008300020081LL, 0x0008008700060085LL, - 0x0006008500040083LL, 0x000a008900080087LL) + 0x0004008300020081LL, 0x000cff8b000aff89LL, + 0x0008ff870006ff85LL, 0x0010ff8f000eff8dLL) /* **************************************************************************** diff --git a/tests/tcg/hexagon/usr.c b/tests/tcg/hexagon/usr.c index a531511cec..fb4514989c 100644 --- a/tests/tcg/hexagon/usr.c +++ b/tests/tcg/hexagon/usr.c @@ -86,6 +86,7 @@ const uint32_t SF_QNaN_neg = 0xffc00000; const uint32_t SF_SNaN_neg = 0xffb00000; const uint32_t SF_HEX_NaN = 0xffffffff; const uint32_t SF_zero = 0x00000000; +const uint32_t SF_zero_neg = 0x80000000; const uint32_t SF_one = 0x3f800000; const uint32_t SF_one_recip = 0x3f7f0001; /* 0.9960... */ const uint32_t SF_one_invsqrta = 0x3f7f0000; /* 0.99609375 */ @@ -100,6 +101,7 @@ const uint64_t DF_QNaN_neg = 0xfff8000000000000ULL; const uint64_t DF_SNaN_neg = 0xfff7000000000000ULL; const uint64_t DF_HEX_NaN = 0xffffffffffffffffULL; const uint64_t DF_zero = 0x0000000000000000ULL; +const uint64_t DF_zero_neg = 0x8000000000000000ULL; const uint64_t DF_any = 0x3f80000000000000ULL; const uint64_t DF_one = 0x3ff0000000000000ULL; const uint64_t DF_one_hh = 0x3ff001ff80000000ULL; /* 1.00048... */ @@ -933,6 +935,8 @@ int main() TEST_R_OP_RR(sfmin, SF_QNaN, SF_one, SF_one, USR_CLEAR); TEST_R_OP_RR(sfmin, SF_SNaN, SF_QNaN, SF_HEX_NaN, USR_FPINVF); TEST_R_OP_RR(sfmin, SF_QNaN, SF_SNaN, SF_HEX_NaN, USR_FPINVF); + TEST_R_OP_RR(sfmin, SF_zero, SF_zero_neg, SF_zero_neg, USR_CLEAR); + TEST_R_OP_RR(sfmin, SF_zero_neg, SF_zero, SF_zero_neg, USR_CLEAR); TEST_R_OP_RR(sfmax, SF_one, SF_small_neg, SF_one, USR_CLEAR); TEST_R_OP_RR(sfmax, SF_one, SF_SNaN, SF_one, USR_FPINVF); @@ -941,6 +945,8 @@ int main() TEST_R_OP_RR(sfmax, SF_QNaN, SF_one, SF_one, USR_CLEAR); TEST_R_OP_RR(sfmax, SF_SNaN, SF_QNaN, SF_HEX_NaN, USR_FPINVF); TEST_R_OP_RR(sfmax, SF_QNaN, SF_SNaN, SF_HEX_NaN, USR_FPINVF); + TEST_R_OP_RR(sfmax, SF_zero, SF_zero_neg, SF_zero, USR_CLEAR); + TEST_R_OP_RR(sfmax, SF_zero_neg, SF_zero, SF_zero, USR_CLEAR); TEST_R_OP_RR(sfadd, SF_one, SF_QNaN, SF_HEX_NaN, USR_CLEAR); TEST_R_OP_RR(sfadd, SF_one, SF_SNaN, SF_HEX_NaN, USR_FPINVF); @@ -1003,6 +1009,8 @@ int main() TEST_P_OP_PP(dfmin, DF_QNaN, DF_any, DF_any, USR_CLEAR); TEST_P_OP_PP(dfmin, DF_SNaN, DF_QNaN, DF_HEX_NaN, USR_FPINVF); TEST_P_OP_PP(dfmin, DF_QNaN, DF_SNaN, DF_HEX_NaN, USR_FPINVF); + TEST_P_OP_PP(dfmin, DF_zero, DF_zero_neg, DF_zero_neg, USR_CLEAR); + TEST_P_OP_PP(dfmin, DF_zero_neg, DF_zero, DF_zero_neg, USR_CLEAR); TEST_P_OP_PP(dfmax, DF_any, DF_small_neg, DF_any, USR_CLEAR); TEST_P_OP_PP(dfmax, DF_any, DF_SNaN, DF_any, USR_FPINVF); @@ -1011,6 +1019,8 @@ int main() TEST_P_OP_PP(dfmax, DF_QNaN, DF_any, DF_any, USR_CLEAR); TEST_P_OP_PP(dfmax, DF_SNaN, DF_QNaN, DF_HEX_NaN, USR_FPINVF); TEST_P_OP_PP(dfmax, DF_QNaN, DF_SNaN, DF_HEX_NaN, USR_FPINVF); + TEST_P_OP_PP(dfmax, DF_zero, DF_zero_neg, DF_zero, USR_CLEAR); + TEST_P_OP_PP(dfmax, DF_zero_neg, DF_zero, DF_zero, USR_CLEAR); TEST_XP_OP_PP(dfmpyhh, DF_one, DF_one, DF_one, DF_one_hh, USR_CLEAR); TEST_XP_OP_PP(dfmpyhh, DF_zero, DF_any, DF_QNaN, DF_HEX_NaN, USR_CLEAR); diff --git a/tests/tcg/i386/Makefile.softmmu-target b/tests/tcg/i386/Makefile.softmmu-target index 9b9038d0be..ed922d59c8 100644 --- a/tests/tcg/i386/Makefile.softmmu-target +++ b/tests/tcg/i386/Makefile.softmmu-target @@ -40,8 +40,7 @@ run-plugin-%-with-libinsn.so: -chardev file$(COMMA)path=$@.out$(COMMA)id=output \ -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ -d plugin -D $*-with-libinsn.so.pout \ - $(QEMU_OPTS) $*, \ - "$* on $(TARGET_NAME)") + $(QEMU_OPTS) $*) # Running QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index bd73c96d0d..3273aa8061 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -5,10 +5,16 @@ I386_SRC=$(SRC_PATH)/tests/tcg/i386 # Set search path for all sources VPATH += $(I386_SRC) +config-cc.mak: Makefile + $(quiet-@)( \ + $(call cc-option,-fno-pie, CROSS_CC_HAS_I386_NOPIE)) 3> config-cc.mak + +-include config-cc.mak + I386_SRCS=$(notdir $(wildcard $(I386_SRC)/*.c)) ALL_X86_TESTS=$(I386_SRCS:.c=) -SKIP_I386_TESTS=test-i386-ssse3 -X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS)) +SKIP_I386_TESTS=test-i386-ssse3 test-avx test-3dnow test-mmx +X86_64_TESTS:=$(filter test-i386-bmi2 $(SKIP_I386_TESTS), $(ALL_X86_TESTS)) test-i386-sse-exceptions: CFLAGS += -msse4.1 -mfpmath=sse run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max @@ -18,6 +24,7 @@ test-i386-pcmpistri: CFLAGS += -msse4.2 run-test-i386-pcmpistri: QEMU_OPTS += -cpu max run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max +test-i386-bmi2: CFLAGS=-O2 run-test-i386-bmi2: QEMU_OPTS += -cpu max run-plugin-test-i386-bmi2-%: QEMU_OPTS += -cpu max @@ -52,7 +59,7 @@ test-i386-fprem.ref: test-i386-fprem run-test-i386-fprem: TIMEOUT=60 run-test-i386-fprem: test-i386-fprem test-i386-fprem.ref - $(call run-test,test-i386-fprem, $(QEMU) $<,"$< on $(TARGET_NAME)") + $(call run-test,test-i386-fprem, $(QEMU) $<) $(call diff-out,test-i386-fprem, test-i386-fprem.ref) else SKIP_I386_TESTS+=test-i386-fprem @@ -62,8 +69,7 @@ endif run-plugin-%-with-libinsn.so: $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ - -d plugin -D $*-with-libinsn.so.pout $*, \ - "$* (inline) on $(TARGET_NAME)") + -d plugin -D $*-with-libinsn.so.pout $*) # Update TESTS I386_TESTS:=$(filter-out $(SKIP_I386_TESTS), $(ALL_X86_TESTS)) @@ -80,3 +86,28 @@ run-sha512-sse: QEMU_OPTS+=-cpu max run-plugin-sha512-sse-with-%: QEMU_OPTS+=-cpu max TESTS+=sha512-sse + +CLEANFILES += test-avx.h test-mmx.h test-3dnow.h +test-3dnow.h: test-mmx.py x86.csv + $(PYTHON) $(I386_SRC)/test-mmx.py $(I386_SRC)/x86.csv $@ 3DNOW + +test-mmx.h: test-mmx.py x86.csv + $(PYTHON) $(I386_SRC)/test-mmx.py $(I386_SRC)/x86.csv $@ MMX SSE SSE2 SSE3 SSSE3 + +test-avx.h: test-avx.py x86.csv + $(PYTHON) $(I386_SRC)/test-avx.py $(I386_SRC)/x86.csv $@ + +test-3dnow: CFLAGS += -masm=intel -O -I. +run-test-3dnow: QEMU_OPTS += -cpu max +run-plugin-test-3dnow: QEMU_OPTS += -cpu max +test-3dnow: test-3dnow.h + +test-mmx: CFLAGS += -masm=intel -O -I. +run-test-mmx: QEMU_OPTS += -cpu max +run-plugin-test-mmx: QEMU_OPTS += -cpu max +test-mmx: test-mmx.h + +test-avx: CFLAGS += -masm=intel -O -I. +run-test-avx: QEMU_OPTS += -cpu max +run-plugin-test-avx: QEMU_OPTS += -cpu max +test-avx: test-avx.h diff --git a/tests/tcg/i386/README b/tests/tcg/i386/README index 09e88f30dc..403d10dad8 100644 --- a/tests/tcg/i386/README +++ b/tests/tcg/i386/README @@ -15,6 +15,15 @@ The Linux system call vm86() is used to test vm86 emulation. Various exceptions are raised to test most of the x86 user space exception reporting. +test-avx +-------- + +This program executes most SSE/AVX instructions and generates a text output, +for comparison with the output obtained with a real CPU or another emulator. + +test-avx.h is generate from x86.csv by test-avx.py +x86.csv comes from https://github.com/quasilyte/avx512test + linux-test ---------- diff --git a/tests/tcg/i386/test-3dnow.c b/tests/tcg/i386/test-3dnow.c new file mode 100644 index 0000000000..67abc68677 --- /dev/null +++ b/tests/tcg/i386/test-3dnow.c @@ -0,0 +1,3 @@ +#define EMMS "femms" +#define TEST_FILE "test-3dnow.h" +#include "test-mmx.c" diff --git a/tests/tcg/i386/test-avx.c b/tests/tcg/i386/test-avx.c new file mode 100644 index 0000000000..23c170dd79 --- /dev/null +++ b/tests/tcg/i386/test-avx.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include + +typedef void (*testfn)(void); + +typedef struct { + uint64_t q0, q1; +} __attribute__((aligned(16))) v2di; + +typedef struct { + uint64_t mm[8]; + v2di xmm[16]; + uint64_t r[16]; + uint64_t flags; + uint32_t ff; + uint64_t pad; + v2di mem[4]; + v2di mem0[4]; +} reg_state; + +typedef struct { + int n; + testfn fn; + const char *s; + reg_state *init; +} TestDef; + +reg_state initI; +reg_state initF32; +reg_state initF64; + +static void dump_xmm(const char *name, int n, const v2di *r, int ff) +{ + printf("%s%d = %016lx %016lx\n", + name, n, r->q1, r->q0); + if (ff == 64) { + double v[2]; + memcpy(v, r, sizeof(v)); + printf(" %16g %16g\n", + v[1], v[0]); + } else if (ff == 32) { + float v[4]; + memcpy(v, r, sizeof(v)); + printf(" %8g %8g %8g %8g\n", + v[3], v[2], v[1], v[0]); + } +} + +static void dump_regs(reg_state *s) +{ + int i; + + for (i = 0; i < 16; i++) { + dump_xmm("xmm", i, &s->xmm[i], 0); + } + for (i = 0; i < 4; i++) { + dump_xmm("mem", i, &s->mem0[i], 0); + } +} + +static void compare_state(const reg_state *a, const reg_state *b) +{ + int i; + for (i = 0; i < 8; i++) { + if (a->mm[i] != b->mm[i]) { + printf("MM%d = %016lx\n", i, b->mm[i]); + } + } + for (i = 0; i < 16; i++) { + if (a->r[i] != b->r[i]) { + printf("r%d = %016lx\n", i, b->r[i]); + } + } + for (i = 0; i < 16; i++) { + if (memcmp(&a->xmm[i], &b->xmm[i], 16)) { + dump_xmm("xmm", i, &b->xmm[i], a->ff); + } + } + for (i = 0; i < 4; i++) { + if (memcmp(&a->mem0[i], &a->mem[i], 16)) { + dump_xmm("mem", i, &a->mem[i], a->ff); + } + } + if (a->flags != b->flags) { + printf("FLAGS = %016lx\n", b->flags); + } +} + +#define LOADMM(r, o) "movq " #r ", " #o "[%0]\n\t" +#define LOADXMM(r, o) "movdqa " #r ", " #o "[%0]\n\t" +#define STOREMM(r, o) "movq " #o "[%1], " #r "\n\t" +#define STOREXMM(r, o) "movdqa " #o "[%1], " #r "\n\t" +#define MMREG(F) \ + F(mm0, 0x00) \ + F(mm1, 0x08) \ + F(mm2, 0x10) \ + F(mm3, 0x18) \ + F(mm4, 0x20) \ + F(mm5, 0x28) \ + F(mm6, 0x30) \ + F(mm7, 0x38) +#define XMMREG(F) \ + F(xmm0, 0x040) \ + F(xmm1, 0x050) \ + F(xmm2, 0x060) \ + F(xmm3, 0x070) \ + F(xmm4, 0x080) \ + F(xmm5, 0x090) \ + F(xmm6, 0x0a0) \ + F(xmm7, 0x0b0) \ + F(xmm8, 0x0c0) \ + F(xmm9, 0x0d0) \ + F(xmm10, 0x0e0) \ + F(xmm11, 0x0f0) \ + F(xmm12, 0x100) \ + F(xmm13, 0x110) \ + F(xmm14, 0x120) \ + F(xmm15, 0x130) +#define LOADREG(r, o) "mov " #r ", " #o "[rax]\n\t" +#define STOREREG(r, o) "mov " #o "[rax], " #r "\n\t" +#define REG(F) \ + F(rbx, 0x148) \ + F(rcx, 0x150) \ + F(rdx, 0x158) \ + F(rsi, 0x160) \ + F(rdi, 0x168) \ + F(r8, 0x180) \ + F(r9, 0x188) \ + F(r10, 0x190) \ + F(r11, 0x198) \ + F(r12, 0x1a0) \ + F(r13, 0x1a8) \ + F(r14, 0x1b0) \ + F(r15, 0x1b8) \ + +static void run_test(const TestDef *t) +{ + reg_state result; + reg_state *init = t->init; + memcpy(init->mem, init->mem0, sizeof(init->mem)); + printf("%5d %s\n", t->n, t->s); + asm volatile( + MMREG(LOADMM) + XMMREG(LOADXMM) + "sub rsp, 128\n\t" + "push rax\n\t" + "push rbx\n\t" + "push rcx\n\t" + "push rdx\n\t" + "push %1\n\t" + "push %2\n\t" + "mov rax, %0\n\t" + "pushf\n\t" + "pop rbx\n\t" + "shr rbx, 8\n\t" + "shl rbx, 8\n\t" + "mov rcx, 0x1c0[rax]\n\t" + "and rcx, 0xff\n\t" + "or rbx, rcx\n\t" + "push rbx\n\t" + "popf\n\t" + REG(LOADREG) + "mov rax, 0x140[rax]\n\t" + "call [rsp]\n\t" + "mov [rsp], rax\n\t" + "mov rax, 8[rsp]\n\t" + REG(STOREREG) + "mov rbx, [rsp]\n\t" + "mov 0x140[rax], rbx\n\t" + "mov rbx, 0\n\t" + "mov 0x170[rax], rbx\n\t" + "mov 0x178[rax], rbx\n\t" + "pushf\n\t" + "pop rbx\n\t" + "and rbx, 0xff\n\t" + "mov 0x1c0[rax], rbx\n\t" + "add rsp, 16\n\t" + "pop rdx\n\t" + "pop rcx\n\t" + "pop rbx\n\t" + "pop rax\n\t" + "add rsp, 128\n\t" + MMREG(STOREMM) + XMMREG(STOREXMM) + : : "r"(init), "r"(&result), "r"(t->fn) + : "memory", "cc", + "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", + "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", + "xmm12", "xmm13", "xmm14", "xmm15" + ); + compare_state(init, &result); +} + +#define TEST(n, cmd, type) \ +static void __attribute__((naked)) test_##n(void) \ +{ \ + asm volatile(cmd); \ + asm volatile("ret"); \ +} +#include "test-avx.h" + + +static const TestDef test_table[] = { +#define TEST(n, cmd, type) {n, test_##n, cmd, &init##type}, +#include "test-avx.h" + {-1, NULL, "", NULL} +}; + +static void run_all(void) +{ + const TestDef *t; + for (t = test_table; t->fn; t++) { + run_test(t); + } +} + +#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0])) + +float val_f32[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5, 8.3}; +double val_f64[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5}; +v2di val_i64[] = { + {0x3d6b3b6a9e4118f2lu, 0x355ae76d2774d78clu}, + {0xd851c54a56bf1f29lu, 0x4a84d1d50bf4c4fflu}, + {0x5826475e2c5fd799lu, 0xfd32edc01243f5e9lu}, +}; + +v2di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull}; +v2di indexq = {0x000000000000001full, 0x000000000000008full}; +v2di indexd = {0x00000002000000efull, 0xfffffff500000010ull}; + +void init_f32reg(v2di *r) +{ + static int n; + float v[4]; + int i; + for (i = 0; i < 4; i++) { + v[i] = val_f32[n++]; + if (n == ARRAY_LEN(val_f32)) { + n = 0; + } + } + memcpy(r, v, sizeof(*r)); +} + +void init_f64reg(v2di *r) +{ + static int n; + double v[2]; + int i; + for (i = 0; i < 2; i++) { + v[i] = val_f64[n++]; + if (n == ARRAY_LEN(val_f64)) { + n = 0; + } + } + memcpy(r, v, sizeof(*r)); +} + +void init_intreg(v2di *r) +{ + static uint64_t mask; + static int n; + + r->q0 = val_i64[n].q0 ^ mask; + r->q1 = val_i64[n].q1 ^ mask; + n++; + if (n == ARRAY_LEN(val_i64)) { + n = 0; + mask *= 0x104C11DB7; + } +} + +static void init_all(reg_state *s) +{ + int i; + + s->r[3] = (uint64_t)&s->mem[0]; /* rdx */ + s->r[5] = (uint64_t)&s->mem[2]; /* rdi */ + s->flags = 2; + for (i = 0; i < 8; i++) { + s->xmm[i] = deadbeef; + } + s->xmm[13] = indexd; + s->xmm[14] = indexq; + for (i = 0; i < 2; i++) { + s->mem0[i] = deadbeef; + } +} + +int main(int argc, char *argv[]) +{ + init_all(&initI); + init_intreg(&initI.xmm[10]); + init_intreg(&initI.xmm[11]); + init_intreg(&initI.xmm[12]); + init_intreg(&initI.mem0[1]); + printf("Int:\n"); + dump_regs(&initI); + + init_all(&initF32); + init_f32reg(&initF32.xmm[10]); + init_f32reg(&initF32.xmm[11]); + init_f32reg(&initF32.xmm[12]); + init_f32reg(&initF32.mem0[1]); + initF32.ff = 32; + printf("F32:\n"); + dump_regs(&initF32); + + init_all(&initF64); + init_f64reg(&initF64.xmm[10]); + init_f64reg(&initF64.xmm[11]); + init_f64reg(&initF64.xmm[12]); + init_f64reg(&initF64.mem0[1]); + initF64.ff = 64; + printf("F64:\n"); + dump_regs(&initF64); + + if (argc > 1) { + int n = atoi(argv[1]); + run_test(&test_table[n]); + } else { + run_all(); + } + return 0; +} diff --git a/tests/tcg/i386/test-avx.py b/tests/tcg/i386/test-avx.py new file mode 100755 index 0000000000..e16a3d8bee --- /dev/null +++ b/tests/tcg/i386/test-avx.py @@ -0,0 +1,370 @@ +#! /usr/bin/env python3 + +# Generate test-avx.h from x86.csv + +import csv +import sys +from fnmatch import fnmatch + +archs = [ + "SSE", "SSE2", "SSE3", "SSSE3", "SSE4_1", "SSE4_2", +] + +ignore = set(["FISTTP", + "LDMXCSR", "VLDMXCSR", "STMXCSR", "VSTMXCSR"]) + +imask = { + 'vBLENDPD': 0xff, + 'vBLENDPS': 0x0f, + 'CMP[PS][SD]': 0x07, + 'VCMP[PS][SD]': 0x1f, + 'vDPPD': 0x33, + 'vDPPS': 0xff, + 'vEXTRACTPS': 0x03, + 'vINSERTPS': 0xff, + 'MPSADBW': 0x7, + 'VMPSADBW': 0x3f, + 'vPALIGNR': 0x3f, + 'vPBLENDW': 0xff, + 'vPCMP[EI]STR*': 0x0f, + 'vPEXTRB': 0x0f, + 'vPEXTRW': 0x07, + 'vPEXTRD': 0x03, + 'vPEXTRQ': 0x01, + 'vPINSRB': 0x0f, + 'vPINSRW': 0x07, + 'vPINSRD': 0x03, + 'vPINSRQ': 0x01, + 'vPSHUF[DW]': 0xff, + 'vPSHUF[LH]W': 0xff, + 'vPS[LR][AL][WDQ]': 0x3f, + 'vPS[RL]LDQ': 0x1f, + 'vROUND[PS][SD]': 0x7, + 'vSHUFPD': 0x0f, + 'vSHUFPS': 0xff, + 'vAESKEYGENASSIST': 0, + 'VEXTRACT[FI]128': 0x01, + 'VINSERT[FI]128': 0x01, + 'VPBLENDD': 0xff, + 'VPERM2[FI]128': 0x33, + 'VPERMPD': 0xff, + 'VPERMQ': 0xff, + 'VPERMILPS': 0xff, + 'VPERMILPD': 0x0f, + } + +def strip_comments(x): + for l in x: + if l != '' and l[0] != '#': + yield l + +def reg_w(w): + if w == 8: + return 'al' + elif w == 16: + return 'ax' + elif w == 32: + return 'eax' + elif w == 64: + return 'rax' + raise Exception("bad reg_w %d" % w) + +def mem_w(w): + if w == 8: + t = "BYTE" + elif w == 16: + t = "WORD" + elif w == 32: + t = "DWORD" + elif w == 64: + t = "QWORD" + elif w == 128: + t = "XMMWORD" + elif w == 256: + t = "YMMWORD" + else: + raise Exception() + + return t + " PTR 16[rdx]" + +class XMMArg(): + isxmm = True + def __init__(self, reg, mw): + if mw not in [0, 8, 16, 32, 64, 128, 256]: + raise Exception("Bad /m width: %s" % w) + self.reg = reg + self.mw = mw + self.ismem = mw != 0 + def regstr(self, n): + if n < 0: + return mem_w(self.mw) + else: + return "%smm%d" % (self.reg, n) + +class MMArg(): + isxmm = True + def __init__(self, mw): + if mw not in [0, 32, 64]: + raise Exception("Bad mem width: %s" % mw) + self.mw = mw + self.ismem = mw != 0 + def regstr(self, n): + return "mm%d" % (n & 7) + +def match(op, pattern): + if pattern[0] == 'v': + return fnmatch(op, pattern[1:]) or fnmatch(op, 'V'+pattern[1:]) + return fnmatch(op, pattern) + +class ArgVSIB(): + isxmm = True + ismem = False + def __init__(self, reg, w): + if w not in [32, 64]: + raise Exception("Bad vsib width: %s" % w) + self.w = w + self.reg = reg + def regstr(self, n): + reg = "%smm%d" % (self.reg, n >> 2) + return "[rsi + %s * %d]" % (reg, 1 << (n & 3)) + +class ArgImm8u(): + isxmm = False + ismem = False + def __init__(self, op): + for k, v in imask.items(): + if match(op, k): + self.mask = imask[k]; + return + raise Exception("Unknown immediate") + def vals(self): + mask = self.mask + yield 0 + n = 0 + while n != mask: + n += 1 + while (n & ~mask) != 0: + n += (n & ~mask) + yield n + +class ArgRM(): + isxmm = False + def __init__(self, rw, mw): + if rw not in [8, 16, 32, 64]: + raise Exception("Bad r/w width: %s" % w) + if mw not in [0, 8, 16, 32, 64]: + raise Exception("Bad r/w width: %s" % w) + self.rw = rw + self.mw = mw + self.ismem = mw != 0 + def regstr(self, n): + if n < 0: + return mem_w(self.mw) + else: + return reg_w(self.rw) + +class ArgMem(): + isxmm = False + ismem = True + def __init__(self, w): + if w not in [8, 16, 32, 64, 128, 256]: + raise Exception("Bad mem width: %s" % w) + self.w = w + def regstr(self, n): + return mem_w(self.w) + +class SkipInstruction(Exception): + pass + +def ArgGenerator(arg, op): + if arg[:3] == 'xmm' or arg[:3] == "ymm": + if "/" in arg: + r, m = arg.split('/') + if (m[0] != 'm'): + raise Exception("Expected /m: %s", arg) + return XMMArg(arg[0], int(m[1:])); + else: + return XMMArg(arg[0], 0); + elif arg[:2] == 'mm': + if "/" in arg: + r, m = arg.split('/') + if (m[0] != 'm'): + raise Exception("Expected /m: %s", arg) + return MMArg(int(m[1:])); + else: + return MMArg(0); + elif arg[:4] == 'imm8': + return ArgImm8u(op); + elif arg == '': + return None + elif arg[0] == 'r': + if '/m' in arg: + r, m = arg.split('/') + if (m[0] != 'm'): + raise Exception("Expected /m: %s", arg) + mw = int(m[1:]) + if r == 'r': + rw = mw + else: + rw = int(r[1:]) + return ArgRM(rw, mw) + + return ArgRM(int(arg[1:]), 0); + elif arg[0] == 'm': + return ArgMem(int(arg[1:])) + elif arg[:2] == 'vm': + return ArgVSIB(arg[-1], int(arg[2:-1])) + else: + raise Exception("Unrecognised arg: %s", arg) + +class InsnGenerator: + def __init__(self, op, args): + self.op = op + if op[-2:] in ["PS", "PD", "SS", "SD"]: + if op[-1] == 'S': + self.optype = 'F32' + else: + self.optype = 'F64' + else: + self.optype = 'I' + + try: + self.args = list(ArgGenerator(a, op) for a in args) + if not any((x.isxmm for x in self.args)): + raise SkipInstruction + if len(self.args) > 0 and self.args[-1] is None: + self.args = self.args[:-1] + except SkipInstruction: + raise + except Exception as e: + raise Exception("Bad arg %s: %s" % (op, e)) + + def gen(self): + regs = (10, 11, 12) + dest = 9 + + nreg = len(self.args) + if nreg == 0: + yield self.op + return + if isinstance(self.args[-1], ArgImm8u): + nreg -= 1 + immarg = self.args[-1] + else: + immarg = None + memarg = -1 + for n, arg in enumerate(self.args): + if arg.ismem: + memarg = n + + if (self.op.startswith("VGATHER") or self.op.startswith("VPGATHER")): + if "GATHERD" in self.op: + ireg = 13 << 2 + else: + ireg = 14 << 2 + regset = [ + (dest, ireg | 0, regs[0]), + (dest, ireg | 1, regs[0]), + (dest, ireg | 2, regs[0]), + (dest, ireg | 3, regs[0]), + ] + if memarg >= 0: + raise Exception("vsib with memory: %s" % self.op) + elif nreg == 1: + regset = [(regs[0],)] + if memarg == 0: + regset += [(-1,)] + elif nreg == 2: + regset = [ + (regs[0], regs[1]), + (regs[0], regs[0]), + ] + if memarg == 0: + regset += [(-1, regs[0])] + elif memarg == 1: + regset += [(dest, -1)] + elif nreg == 3: + regset = [ + (dest, regs[0], regs[1]), + (dest, regs[0], regs[0]), + (regs[0], regs[0], regs[1]), + (regs[0], regs[1], regs[0]), + (regs[0], regs[0], regs[0]), + ] + if memarg == 2: + regset += [ + (dest, regs[0], -1), + (regs[0], regs[0], -1), + ] + elif memarg > 0: + raise Exception("Memarg %d" % memarg) + elif nreg == 4: + regset = [ + (dest, regs[0], regs[1], regs[2]), + (dest, regs[0], regs[0], regs[1]), + (dest, regs[0], regs[1], regs[0]), + (dest, regs[1], regs[0], regs[0]), + (dest, regs[0], regs[0], regs[0]), + (regs[0], regs[0], regs[1], regs[2]), + (regs[0], regs[1], regs[0], regs[2]), + (regs[0], regs[1], regs[2], regs[0]), + (regs[0], regs[0], regs[0], regs[1]), + (regs[0], regs[0], regs[1], regs[0]), + (regs[0], regs[1], regs[0], regs[0]), + (regs[0], regs[0], regs[0], regs[0]), + ] + if memarg == 2: + regset += [ + (dest, regs[0], -1, regs[1]), + (dest, regs[0], -1, regs[0]), + (regs[0], regs[0], -1, regs[1]), + (regs[0], regs[1], -1, regs[0]), + (regs[0], regs[0], -1, regs[0]), + ] + elif memarg > 0: + raise Exception("Memarg4 %d" % memarg) + else: + raise Exception("Too many regs: %s(%d)" % (self.op, nreg)) + + for regv in regset: + argstr = [] + for i in range(nreg): + arg = self.args[i] + argstr.append(arg.regstr(regv[i])) + if immarg is None: + yield self.op + ' ' + ','.join(argstr) + else: + for immval in immarg.vals(): + yield self.op + ' ' + ','.join(argstr) + ',' + str(immval) + +def split0(s): + if s == '': + return [] + return s.split(',') + +def main(): + n = 0 + if len(sys.argv) != 3: + print("Usage: test-avx.py x86.csv test-avx.h") + exit(1) + csvfile = open(sys.argv[1], 'r', newline='') + with open(sys.argv[2], "w") as outf: + outf.write("// Generated by test-avx.py. Do not edit.\n") + for row in csv.reader(strip_comments(csvfile)): + insn = row[0].replace(',', '').split() + if insn[0] in ignore: + continue + cpuid = row[6] + if cpuid in archs: + try: + g = InsnGenerator(insn[0], insn[1:]) + for insn in g.gen(): + outf.write('TEST(%d, "%s", %s)\n' % (n, insn, g.optype)) + n += 1 + except SkipInstruction: + pass + outf.write("#undef TEST\n") + csvfile.close() + +if __name__ == "__main__": + main() diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c index 935a4d2a73..5fadf47510 100644 --- a/tests/tcg/i386/test-i386-bmi2.c +++ b/tests/tcg/i386/test-i386-bmi2.c @@ -1,6 +1,66 @@ /* See if various BMI2 instructions give expected results */ #include #include +#include + +#define insn1q(name, arg0) \ +static inline uint64_t name##q(uint64_t arg0) \ +{ \ + uint64_t result64; \ + asm volatile (#name "q %1, %0" : "=r"(result64) : "rm"(arg0)); \ + return result64; \ +} + +#define insn1l(name, arg0) \ +static inline uint32_t name##l(uint32_t arg0) \ +{ \ + uint32_t result32; \ + asm volatile (#name "l %k1, %k0" : "=r"(result32) : "rm"(arg0)); \ + return result32; \ +} + +#define insn2q(name, arg0, c0, arg1, c1) \ +static inline uint64_t name##q(uint64_t arg0, uint64_t arg1) \ +{ \ + uint64_t result64; \ + asm volatile (#name "q %2, %1, %0" : "=r"(result64) : c0(arg0), c1(arg1)); \ + return result64; \ +} + +#define insn2l(name, arg0, c0, arg1, c1) \ +static inline uint32_t name##l(uint32_t arg0, uint32_t arg1) \ +{ \ + uint32_t result32; \ + asm volatile (#name "l %k2, %k1, %k0" : "=r"(result32) : c0(arg0), c1(arg1)); \ + return result32; \ +} + +#ifdef __x86_64 +insn2q(pext, src, "r", mask, "rm") +insn2q(pdep, src, "r", mask, "rm") +insn2q(andn, clear, "rm", val, "r") +insn2q(bextr, range, "rm", val, "r") +insn2q(bzhi, pos, "rm", val, "r") +insn2q(rorx, val, "r", n, "i") +insn2q(sarx, val, "rm", n, "r") +insn2q(shlx, val, "rm", n, "r") +insn2q(shrx, val, "rm", n, "r") +insn1q(blsi, src) +insn1q(blsmsk, src) +insn1q(blsr, src) +#endif +insn2l(pext, src, "r", mask, "rm") +insn2l(pdep, src, "r", mask, "rm") +insn2l(andn, clear, "rm", val, "r") +insn2l(bextr, range, "rm", val, "r") +insn2l(bzhi, pos, "rm", val, "r") +insn2l(rorx, val, "r", n, "i") +insn2l(sarx, val, "rm", n, "r") +insn2l(shlx, val, "rm", n, "r") +insn2l(shrx, val, "rm", n, "r") +insn1l(blsi, src) +insn1l(blsmsk, src) +insn1l(blsr, src) int main(int argc, char *argv[]) { uint64_t ehlo = 0x202020204f4c4845ull; @@ -11,32 +71,125 @@ int main(int argc, char *argv[]) { uint64_t result64; /* 64 bits */ - asm volatile ("pextq %2, %1, %0" : "=r"(result64) : "r"(ehlo), "m"(mask)); + result64 = andnq(mask, ehlo); + assert(result64 == 0x002020204d4c4844); + + result64 = pextq(ehlo, mask); assert(result64 == 133); - asm volatile ("pdepq %2, %1, %0" : "=r"(result64) : "r"(result64), "m"(mask)); + result64 = pdepq(result64, mask); assert(result64 == (ehlo & mask)); - asm volatile ("pextq %2, %1, %0" : "=r"(result64) : "r"(-1ull), "m"(mask)); + result64 = pextq(-1ull, mask); assert(result64 == 511); /* mask has 9 bits set */ - asm volatile ("pdepq %2, %1, %0" : "=r"(result64) : "r"(-1ull), "m"(mask)); + result64 = pdepq(-1ull, mask); assert(result64 == mask); + + result64 = bextrq(mask, 0x3f00); + assert(result64 == (mask & ~INT64_MIN)); + + result64 = bextrq(mask, 0x1038); + assert(result64 == 0xa0); + + result64 = bextrq(mask, 0x10f8); + assert(result64 == 0); + + result64 = blsiq(0x30); + assert(result64 == 0x10); + + result64 = blsiq(0x30ull << 32); + assert(result64 == 0x10ull << 32); + + result64 = blsmskq(0x30); + assert(result64 == 0x1f); + + result64 = blsrq(0x30); + assert(result64 == 0x20); + + result64 = blsrq(0x30ull << 32); + assert(result64 == 0x20ull << 32); + + result64 = bzhiq(mask, 0x3f); + assert(result64 == (mask & ~INT64_MIN)); + + result64 = bzhiq(mask, 0x1f); + assert(result64 == (mask & ~(-1 << 30))); + + result64 = rorxq(0x2132435465768798, 8); + assert(result64 == 0x9821324354657687); + + result64 = sarxq(0xffeeddccbbaa9988, 8); + assert(result64 == 0xffffeeddccbbaa99); + + result64 = sarxq(0x77eeddccbbaa9988, 8 | 64); + assert(result64 == 0x0077eeddccbbaa99); + + result64 = shrxq(0xffeeddccbbaa9988, 8); + assert(result64 == 0x00ffeeddccbbaa99); + + result64 = shrxq(0x77eeddccbbaa9988, 8 | 192); + assert(result64 == 0x0077eeddccbbaa99); + + result64 = shlxq(0xffeeddccbbaa9988, 8); + assert(result64 == 0xeeddccbbaa998800); #endif /* 32 bits */ - asm volatile ("pextl %2, %k1, %k0" : "=r"(result32) : "r"((uint32_t) ehlo), "m"(mask)); + result32 = andnl(mask, ehlo); + assert(result32 == 0x04d4c4844); + + result32 = pextl((uint32_t) ehlo, mask); assert(result32 == 5); - asm volatile ("pdepl %2, %k1, %k0" : "=r"(result32) : "r"(result32), "m"(mask)); + result32 = pdepl(result32, mask); assert(result32 == (uint32_t)(ehlo & mask)); - asm volatile ("pextl %2, %k1, %k0" : "=r"(result32) : "r"(-1ull), "m"(mask)); + result32 = pextl(-1u, mask); assert(result32 == 7); /* mask has 3 bits set */ - asm volatile ("pdepl %2, %k1, %k0" : "=r"(result32) : "r"(-1ull), "m"(mask)); + result32 = pdepl(-1u, mask); assert(result32 == (uint32_t)mask); + result32 = bextrl(mask, 0x1f00); + assert(result32 == (mask & ~INT32_MIN)); + + result32 = bextrl(ehlo, 0x1018); + assert(result32 == 0x4f); + + result32 = bextrl(mask, 0x1038); + assert(result32 == 0); + + result32 = blsil(0xffff); + assert(result32 == 1); + + result32 = blsmskl(0x300); + assert(result32 == 0x1ff); + + result32 = blsrl(0xffc); + assert(result32 == 0xff8); + + result32 = bzhil(mask, 0xf); + assert(result32 == 1); + + result32 = rorxl(0x65768798, 8); + assert(result32 == 0x98657687); + + result32 = sarxl(0xffeeddcc, 8); + assert(result32 == 0xffffeedd); + + result32 = sarxl(0x77eeddcc, 8 | 32); + assert(result32 == 0x0077eedd); + + result32 = shrxl(0xffeeddcc, 8); + assert(result32 == 0x00ffeedd); + + result32 = shrxl(0x77eeddcc, 8 | 128); + assert(result32 == 0x0077eedd); + + result32 = shlxl(0xffeeddcc, 8); + assert(result32 == 0xeeddcc00); + return 0; } diff --git a/tests/tcg/i386/test-i386.c b/tests/tcg/i386/test-i386.c index ac8d5a3c1f..864c4e620d 100644 --- a/tests/tcg/i386/test-i386.c +++ b/tests/tcg/i386/test-i386.c @@ -34,15 +34,8 @@ #endif //#define LINUX_VM86_IOPL_FIX //#define TEST_P4_FLAGS -#ifdef __SSE__ -#define TEST_SSE #define TEST_CMOV 1 #define TEST_FCOMI 1 -#else -#undef TEST_SSE -#define TEST_CMOV 1 -#define TEST_FCOMI 1 -#endif #if defined(__x86_64__) #define FMT64X "%016lx" @@ -1998,7 +1991,7 @@ uint8_t code[] = { 0xc3, /* ret */ }; -asm(".section \".data\"\n" +asm(".section \".data_x\",\"awx\"\n" "smc_code2:\n" "movl 4(%esp), %eax\n" "movl %eax, smc_patch_addr2 + 1\n" @@ -2104,568 +2097,6 @@ static void test_enter(void) TEST_ENTER("w", uint16_t, 31); } -#ifdef TEST_SSE - -typedef int __m64 __attribute__ ((vector_size(8))); -typedef float __m128 __attribute__ ((vector_size(16))); - -typedef union { - double d[2]; - float s[4]; - uint32_t l[4]; - uint64_t q[2]; - __m128 dq; -} XMMReg; - -static uint64_t __attribute__((aligned(16))) test_values[4][2] = { - { 0x456723c698694873, 0xdc515cff944a58ec }, - { 0x1f297ccd58bad7ab, 0x41f21efba9e3e146 }, - { 0x007c62c2085427f8, 0x231be9e8cde7438d }, - { 0x0f76255a085427f8, 0xc233e9e8c4c9439a }, -}; - -#define SSE_OP(op)\ -{\ - asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ - printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ - #op,\ - a.q[1], a.q[0],\ - b.q[1], b.q[0],\ - r.q[1], r.q[0]);\ -} - -#define SSE_OP2(op)\ -{\ - int i;\ - for(i=0;i<2;i++) {\ - a.q[0] = test_values[2*i][0];\ - a.q[1] = test_values[2*i][1];\ - b.q[0] = test_values[2*i+1][0];\ - b.q[1] = test_values[2*i+1][1];\ - SSE_OP(op);\ - }\ -} - -#define MMX_OP2(op)\ -{\ - int i;\ - for(i=0;i<2;i++) {\ - a.q[0] = test_values[2*i][0];\ - b.q[0] = test_values[2*i+1][0];\ - asm volatile (#op " %2, %0" : "=y" (r.q[0]) : "0" (a.q[0]), "y" (b.q[0]));\ - printf("%-9s: a=" FMT64X " b=" FMT64X " r=" FMT64X "\n",\ - #op,\ - a.q[0],\ - b.q[0],\ - r.q[0]);\ - }\ - SSE_OP2(op);\ -} - -#define SHUF_OP(op, ib)\ -{\ - a.q[0] = test_values[0][0];\ - a.q[1] = test_values[0][1];\ - b.q[0] = test_values[1][0];\ - b.q[1] = test_values[1][1];\ - asm volatile (#op " $" #ib ", %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ - printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ - #op,\ - a.q[1], a.q[0],\ - b.q[1], b.q[0],\ - ib,\ - r.q[1], r.q[0]);\ -} - -#define PSHUF_OP(op, ib)\ -{\ - int i;\ - for(i=0;i<2;i++) {\ - a.q[0] = test_values[2*i][0];\ - a.q[1] = test_values[2*i][1];\ - asm volatile (#op " $" #ib ", %1, %0" : "=x" (r.dq) : "x" (a.dq));\ - printf("%-9s: a=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ - #op,\ - a.q[1], a.q[0],\ - ib,\ - r.q[1], r.q[0]);\ - }\ -} - -#define SHIFT_IM(op, ib)\ -{\ - int i;\ - for(i=0;i<2;i++) {\ - a.q[0] = test_values[2*i][0];\ - a.q[1] = test_values[2*i][1];\ - asm volatile (#op " $" #ib ", %0" : "=x" (r.dq) : "0" (a.dq));\ - printf("%-9s: a=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ - #op,\ - a.q[1], a.q[0],\ - ib,\ - r.q[1], r.q[0]);\ - }\ -} - -#define SHIFT_OP(op, ib)\ -{\ - int i;\ - SHIFT_IM(op, ib);\ - for(i=0;i<2;i++) {\ - a.q[0] = test_values[2*i][0];\ - a.q[1] = test_values[2*i][1];\ - b.q[0] = ib;\ - b.q[1] = 0;\ - asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ - printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ - #op,\ - a.q[1], a.q[0],\ - b.q[1], b.q[0],\ - r.q[1], r.q[0]);\ - }\ -} - -#define MOVMSK(op)\ -{\ - int i, reg;\ - for(i=0;i<2;i++) {\ - a.q[0] = test_values[2*i][0];\ - a.q[1] = test_values[2*i][1];\ - asm volatile (#op " %1, %0" : "=r" (reg) : "x" (a.dq));\ - printf("%-9s: a=" FMT64X "" FMT64X " r=%08x\n",\ - #op,\ - a.q[1], a.q[0],\ - reg);\ - }\ -} - -#define SSE_OPS(a) \ -SSE_OP(a ## ps);\ -SSE_OP(a ## ss); - -#define SSE_OPD(a) \ -SSE_OP(a ## pd);\ -SSE_OP(a ## sd); - -#define SSE_COMI(op, field)\ -{\ - unsigned long eflags;\ - XMMReg a, b;\ - a.field[0] = a1;\ - b.field[0] = b1;\ - asm volatile (#op " %2, %1\n"\ - "pushf\n"\ - "pop %0\n"\ - : "=rm" (eflags)\ - : "x" (a.dq), "x" (b.dq));\ - printf("%-9s: a=%f b=%f cc=%04lx\n",\ - #op, a1, b1,\ - eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\ -} - -void test_sse_comi(double a1, double b1) -{ - SSE_COMI(ucomiss, s); - SSE_COMI(ucomisd, d); - SSE_COMI(comiss, s); - SSE_COMI(comisd, d); -} - -#define CVT_OP_XMM(op)\ -{\ - asm volatile (#op " %1, %0" : "=x" (r.dq) : "x" (a.dq));\ - printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ - #op,\ - a.q[1], a.q[0],\ - r.q[1], r.q[0]);\ -} - -/* Force %xmm0 usage to avoid the case where both register index are 0 - to test instruction decoding more extensively */ -#define CVT_OP_XMM2MMX(op)\ -{\ - asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq) \ - : "%xmm0"); \ - asm volatile("emms\n"); \ - printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "\n",\ - #op,\ - a.q[1], a.q[0],\ - r.q[0]);\ -} - -#define CVT_OP_MMX2XMM(op)\ -{\ - asm volatile (#op " %1, %0" : "=x" (r.dq) : "y" (a.q[0]));\ - asm volatile("emms\n"); \ - printf("%-9s: a=" FMT64X " r=" FMT64X "" FMT64X "\n",\ - #op,\ - a.q[0],\ - r.q[1], r.q[0]);\ -} - -#define CVT_OP_REG2XMM(op)\ -{\ - asm volatile (#op " %1, %0" : "=x" (r.dq) : "r" (a.l[0]));\ - printf("%-9s: a=%08x r=" FMT64X "" FMT64X "\n",\ - #op,\ - a.l[0],\ - r.q[1], r.q[0]);\ -} - -#define CVT_OP_XMM2REG(op)\ -{\ - asm volatile (#op " %1, %0" : "=r" (r.l[0]) : "x" (a.dq));\ - printf("%-9s: a=" FMT64X "" FMT64X " r=%08x\n",\ - #op,\ - a.q[1], a.q[0],\ - r.l[0]);\ -} - -struct fpxstate { - uint16_t fpuc; - uint16_t fpus; - uint16_t fptag; - uint16_t fop; - uint32_t fpuip; - uint16_t cs_sel; - uint16_t dummy0; - uint32_t fpudp; - uint16_t ds_sel; - uint16_t dummy1; - uint32_t mxcsr; - uint32_t mxcsr_mask; - uint8_t fpregs1[8 * 16]; - uint8_t xmm_regs[8 * 16]; - uint8_t dummy2[224]; -}; - -static struct fpxstate fpx_state __attribute__((aligned(16))); -static struct fpxstate fpx_state2 __attribute__((aligned(16))); - -void test_fxsave(void) -{ - struct fpxstate *fp = &fpx_state; - struct fpxstate *fp2 = &fpx_state2; - int i, nb_xmm; - XMMReg a, b; - a.q[0] = test_values[0][0]; - a.q[1] = test_values[0][1]; - b.q[0] = test_values[1][0]; - b.q[1] = test_values[1][1]; - - asm("movdqa %2, %%xmm0\n" - "movdqa %3, %%xmm7\n" -#if defined(__x86_64__) - "movdqa %2, %%xmm15\n" -#endif - " fld1\n" - " fldpi\n" - " fldln2\n" - " fxsave %0\n" - " fxrstor %0\n" - " fxsave %1\n" - " fninit\n" - : "=m" (*(uint32_t *)fp2), "=m" (*(uint32_t *)fp) - : "m" (a), "m" (b)); - printf("fpuc=%04x\n", fp->fpuc); - printf("fpus=%04x\n", fp->fpus); - printf("fptag=%04x\n", fp->fptag); - for(i = 0; i < 3; i++) { - printf("ST%d: " FMT64X " %04x\n", - i, - *(uint64_t *)&fp->fpregs1[i * 16], - *(uint16_t *)&fp->fpregs1[i * 16 + 8]); - } - printf("mxcsr=%08x\n", fp->mxcsr & 0x1f80); -#if defined(__x86_64__) - nb_xmm = 16; -#else - nb_xmm = 8; -#endif - for(i = 0; i < nb_xmm; i++) { - printf("xmm%d: " FMT64X "" FMT64X "\n", - i, - *(uint64_t *)&fp->xmm_regs[i * 16], - *(uint64_t *)&fp->xmm_regs[i * 16 + 8]); - } -} - -void test_sse(void) -{ - XMMReg r, a, b; - int i; - - MMX_OP2(punpcklbw); - MMX_OP2(punpcklwd); - MMX_OP2(punpckldq); - MMX_OP2(packsswb); - MMX_OP2(pcmpgtb); - MMX_OP2(pcmpgtw); - MMX_OP2(pcmpgtd); - MMX_OP2(packuswb); - MMX_OP2(punpckhbw); - MMX_OP2(punpckhwd); - MMX_OP2(punpckhdq); - MMX_OP2(packssdw); - MMX_OP2(pcmpeqb); - MMX_OP2(pcmpeqw); - MMX_OP2(pcmpeqd); - - MMX_OP2(paddq); - MMX_OP2(pmullw); - MMX_OP2(psubusb); - MMX_OP2(psubusw); - MMX_OP2(pminub); - MMX_OP2(pand); - MMX_OP2(paddusb); - MMX_OP2(paddusw); - MMX_OP2(pmaxub); - MMX_OP2(pandn); - - MMX_OP2(pmulhuw); - MMX_OP2(pmulhw); - - MMX_OP2(psubsb); - MMX_OP2(psubsw); - MMX_OP2(pminsw); - MMX_OP2(por); - MMX_OP2(paddsb); - MMX_OP2(paddsw); - MMX_OP2(pmaxsw); - MMX_OP2(pxor); - MMX_OP2(pmuludq); - MMX_OP2(pmaddwd); - MMX_OP2(psadbw); - MMX_OP2(psubb); - MMX_OP2(psubw); - MMX_OP2(psubd); - MMX_OP2(psubq); - MMX_OP2(paddb); - MMX_OP2(paddw); - MMX_OP2(paddd); - - MMX_OP2(pavgb); - MMX_OP2(pavgw); - - asm volatile ("pinsrw $1, %1, %0" : "=y" (r.q[0]) : "r" (0x12345678)); - printf("%-9s: r=" FMT64X "\n", "pinsrw", r.q[0]); - - asm volatile ("pinsrw $5, %1, %0" : "=x" (r.dq) : "r" (0x12345678)); - printf("%-9s: r=" FMT64X "" FMT64X "\n", "pinsrw", r.q[1], r.q[0]); - - a.q[0] = test_values[0][0]; - a.q[1] = test_values[0][1]; - asm volatile ("pextrw $1, %1, %0" : "=r" (r.l[0]) : "y" (a.q[0])); - printf("%-9s: r=%08x\n", "pextrw", r.l[0]); - - asm volatile ("pextrw $5, %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); - printf("%-9s: r=%08x\n", "pextrw", r.l[0]); - - asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "y" (a.q[0])); - printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); - - asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); - printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); - - { - r.q[0] = -1; - r.q[1] = -1; - - a.q[0] = test_values[0][0]; - a.q[1] = test_values[0][1]; - b.q[0] = test_values[1][0]; - b.q[1] = test_values[1][1]; - asm volatile("maskmovq %1, %0" : - : "y" (a.q[0]), "y" (b.q[0]), "D" (&r) - : "memory"); - printf("%-9s: r=" FMT64X " a=" FMT64X " b=" FMT64X "\n", - "maskmov", - r.q[0], - a.q[0], - b.q[0]); - asm volatile("maskmovdqu %1, %0" : - : "x" (a.dq), "x" (b.dq), "D" (&r) - : "memory"); - printf("%-9s: r=" FMT64X "" FMT64X " a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X "\n", - "maskmov", - r.q[1], r.q[0], - a.q[1], a.q[0], - b.q[1], b.q[0]); - } - - asm volatile ("emms"); - - SSE_OP2(punpcklqdq); - SSE_OP2(punpckhqdq); - SSE_OP2(andps); - SSE_OP2(andpd); - SSE_OP2(andnps); - SSE_OP2(andnpd); - SSE_OP2(orps); - SSE_OP2(orpd); - SSE_OP2(xorps); - SSE_OP2(xorpd); - - SSE_OP2(unpcklps); - SSE_OP2(unpcklpd); - SSE_OP2(unpckhps); - SSE_OP2(unpckhpd); - - SHUF_OP(shufps, 0x78); - SHUF_OP(shufpd, 0x02); - - PSHUF_OP(pshufd, 0x78); - PSHUF_OP(pshuflw, 0x78); - PSHUF_OP(pshufhw, 0x78); - - SHIFT_OP(psrlw, 7); - SHIFT_OP(psrlw, 16); - SHIFT_OP(psraw, 7); - SHIFT_OP(psraw, 16); - SHIFT_OP(psllw, 7); - SHIFT_OP(psllw, 16); - - SHIFT_OP(psrld, 7); - SHIFT_OP(psrld, 32); - SHIFT_OP(psrad, 7); - SHIFT_OP(psrad, 32); - SHIFT_OP(pslld, 7); - SHIFT_OP(pslld, 32); - - SHIFT_OP(psrlq, 7); - SHIFT_OP(psrlq, 32); - SHIFT_OP(psllq, 7); - SHIFT_OP(psllq, 32); - - SHIFT_IM(psrldq, 16); - SHIFT_IM(psrldq, 7); - SHIFT_IM(pslldq, 16); - SHIFT_IM(pslldq, 7); - - MOVMSK(movmskps); - MOVMSK(movmskpd); - - /* FPU specific ops */ - - { - uint32_t mxcsr; - asm volatile("stmxcsr %0" : "=m" (mxcsr)); - printf("mxcsr=%08x\n", mxcsr & 0x1f80); - asm volatile("ldmxcsr %0" : : "m" (mxcsr)); - } - - test_sse_comi(2, -1); - test_sse_comi(2, 2); - test_sse_comi(2, 3); - test_sse_comi(2, q_nan.d); - test_sse_comi(q_nan.d, -1); - - for(i = 0; i < 2; i++) { - a.s[0] = 2.7; - a.s[1] = 3.4; - a.s[2] = 4; - a.s[3] = -6.3; - b.s[0] = 45.7; - b.s[1] = 353.4; - b.s[2] = 4; - b.s[3] = 56.3; - if (i == 1) { - a.s[0] = q_nan.d; - b.s[3] = q_nan.d; - } - - SSE_OPS(add); - SSE_OPS(mul); - SSE_OPS(sub); - SSE_OPS(min); - SSE_OPS(div); - SSE_OPS(max); - SSE_OPS(sqrt); - SSE_OPS(cmpeq); - SSE_OPS(cmplt); - SSE_OPS(cmple); - SSE_OPS(cmpunord); - SSE_OPS(cmpneq); - SSE_OPS(cmpnlt); - SSE_OPS(cmpnle); - SSE_OPS(cmpord); - - - a.d[0] = 2.7; - a.d[1] = -3.4; - b.d[0] = 45.7; - b.d[1] = -53.4; - if (i == 1) { - a.d[0] = q_nan.d; - b.d[1] = q_nan.d; - } - SSE_OPD(add); - SSE_OPD(mul); - SSE_OPD(sub); - SSE_OPD(min); - SSE_OPD(div); - SSE_OPD(max); - SSE_OPD(sqrt); - SSE_OPD(cmpeq); - SSE_OPD(cmplt); - SSE_OPD(cmple); - SSE_OPD(cmpunord); - SSE_OPD(cmpneq); - SSE_OPD(cmpnlt); - SSE_OPD(cmpnle); - SSE_OPD(cmpord); - } - - /* float to float/int */ - a.s[0] = 2.7; - a.s[1] = 3.4; - a.s[2] = 4; - a.s[3] = -6.3; - CVT_OP_XMM(cvtps2pd); - CVT_OP_XMM(cvtss2sd); - CVT_OP_XMM2MMX(cvtps2pi); - CVT_OP_XMM2MMX(cvttps2pi); - CVT_OP_XMM2REG(cvtss2si); - CVT_OP_XMM2REG(cvttss2si); - CVT_OP_XMM(cvtps2dq); - CVT_OP_XMM(cvttps2dq); - - a.d[0] = 2.6; - a.d[1] = -3.4; - CVT_OP_XMM(cvtpd2ps); - CVT_OP_XMM(cvtsd2ss); - CVT_OP_XMM2MMX(cvtpd2pi); - CVT_OP_XMM2MMX(cvttpd2pi); - CVT_OP_XMM2REG(cvtsd2si); - CVT_OP_XMM2REG(cvttsd2si); - CVT_OP_XMM(cvtpd2dq); - CVT_OP_XMM(cvttpd2dq); - - /* sse/mmx moves */ - CVT_OP_XMM2MMX(movdq2q); - CVT_OP_MMX2XMM(movq2dq); - - /* int to float */ - a.l[0] = -6; - a.l[1] = 2; - a.l[2] = 100; - a.l[3] = -60000; - CVT_OP_MMX2XMM(cvtpi2ps); - CVT_OP_MMX2XMM(cvtpi2pd); - CVT_OP_REG2XMM(cvtsi2ss); - CVT_OP_REG2XMM(cvtsi2sd); - CVT_OP_XMM(cvtdq2ps); - CVT_OP_XMM(cvtdq2pd); - - /* XXX: test PNI insns */ -#if 0 - SSE_OP2(movshdup); -#endif - asm volatile ("emms"); -} - -#endif - #define TEST_CONV_RAX(op)\ {\ unsigned long a, r;\ @@ -2756,9 +2187,5 @@ int main(int argc, char **argv) #endif test_enter(); test_conv(); -#ifdef TEST_SSE - test_sse(); - test_fxsave(); -#endif return 0; } diff --git a/tests/tcg/i386/test-mmx.c b/tests/tcg/i386/test-mmx.c new file mode 100644 index 0000000000..09e5d583ff --- /dev/null +++ b/tests/tcg/i386/test-mmx.c @@ -0,0 +1,315 @@ +#include +#include +#include +#include + +#ifndef TEST_FILE +#define TEST_FILE "test-mmx.h" +#endif +#ifndef EMMS +#define EMMS "emms" +#endif + +typedef void (*testfn)(void); + +typedef struct { + uint64_t q0, q1; +} __attribute__((aligned(16))) v2di; + +typedef struct { + uint64_t mm[8]; + v2di xmm[8]; + uint64_t r[16]; + uint64_t flags; + uint32_t ff; + uint64_t pad; + v2di mem[4]; + v2di mem0[4]; +} reg_state; + +typedef struct { + int n; + testfn fn; + const char *s; + reg_state *init; +} TestDef; + +reg_state initI; +reg_state initF32; +reg_state initF64; + +static void dump_mmx(int n, const uint64_t *r, int ff) +{ + if (ff == 32) { + float v[2]; + memcpy(v, r, sizeof(v)); + printf("MM%d = %016lx %8g %8g\n", n, *r, v[1], v[0]); + } else { + printf("MM%d = %016lx\n", n, *r); + } +} + +static void dump_xmm(const char *name, int n, const v2di *r, int ff) +{ + printf("%s%d = %016lx %016lx\n", + name, n, r->q1, r->q0); + if (ff == 32) { + float v[4]; + memcpy(v, r, sizeof(v)); + printf(" %8g %8g %8g %8g\n", + v[3], v[2], v[1], v[0]); + } +} + +static void dump_regs(reg_state *s, int ff) +{ + int i; + + for (i = 0; i < 8; i++) { + dump_mmx(i, &s->mm[i], ff); + } + for (i = 0; i < 4; i++) { + dump_xmm("mem", i, &s->mem0[i], 0); + } +} + +static void compare_state(const reg_state *a, const reg_state *b) +{ + int i; + for (i = 0; i < 8; i++) { + if (a->mm[i] != b->mm[i]) { + printf("MM%d = %016lx\n", i, b->mm[i]); + } + } + for (i = 0; i < 16; i++) { + if (a->r[i] != b->r[i]) { + printf("r%d = %016lx\n", i, b->r[i]); + } + } + for (i = 0; i < 8; i++) { + if (memcmp(&a->xmm[i], &b->xmm[i], 8)) { + dump_xmm("xmm", i, &b->xmm[i], a->ff); + } + } + for (i = 0; i < 4; i++) { + if (memcmp(&a->mem0[i], &a->mem[i], 16)) { + dump_xmm("mem", i, &a->mem[i], a->ff); + } + } + if (a->flags != b->flags) { + printf("FLAGS = %016lx\n", b->flags); + } +} + +#define LOADMM(r, o) "movq " #r ", " #o "[%0]\n\t" +#define LOADXMM(r, o) "movdqa " #r ", " #o "[%0]\n\t" +#define STOREMM(r, o) "movq " #o "[%1], " #r "\n\t" +#define STOREXMM(r, o) "movdqa " #o "[%1], " #r "\n\t" +#define MMREG(F) \ + F(mm0, 0x00) \ + F(mm1, 0x08) \ + F(mm2, 0x10) \ + F(mm3, 0x18) \ + F(mm4, 0x20) \ + F(mm5, 0x28) \ + F(mm6, 0x30) \ + F(mm7, 0x38) +#define XMMREG(F) \ + F(xmm0, 0x040) \ + F(xmm1, 0x050) \ + F(xmm2, 0x060) \ + F(xmm3, 0x070) \ + F(xmm4, 0x080) \ + F(xmm5, 0x090) \ + F(xmm6, 0x0a0) \ + F(xmm7, 0x0b0) +#define LOADREG(r, o) "mov " #r ", " #o "[rax]\n\t" +#define STOREREG(r, o) "mov " #o "[rax], " #r "\n\t" +#define REG(F) \ + F(rbx, 0xc8) \ + F(rcx, 0xd0) \ + F(rdx, 0xd8) \ + F(rsi, 0xe0) \ + F(rdi, 0xe8) \ + F(r8, 0x100) \ + F(r9, 0x108) \ + F(r10, 0x110) \ + F(r11, 0x118) \ + F(r12, 0x120) \ + F(r13, 0x128) \ + F(r14, 0x130) \ + F(r15, 0x138) \ + +static void run_test(const TestDef *t) +{ + reg_state result; + reg_state *init = t->init; + memcpy(init->mem, init->mem0, sizeof(init->mem)); + printf("%5d %s\n", t->n, t->s); + asm volatile( + MMREG(LOADMM) + XMMREG(LOADXMM) + "sub rsp, 128\n\t" + "push rax\n\t" + "push rbx\n\t" + "push rcx\n\t" + "push rdx\n\t" + "push %1\n\t" + "push %2\n\t" + "mov rax, %0\n\t" + "pushf\n\t" + "pop rbx\n\t" + "shr rbx, 8\n\t" + "shl rbx, 8\n\t" + "mov rcx, 0x140[rax]\n\t" + "and rcx, 0xff\n\t" + "or rbx, rcx\n\t" + "push rbx\n\t" + "popf\n\t" + REG(LOADREG) + "mov rax, 0xc0[rax]\n\t" + "call [rsp]\n\t" + "mov [rsp], rax\n\t" + "mov rax, 8[rsp]\n\t" + REG(STOREREG) + "mov rbx, [rsp]\n\t" + "mov 0xc0[rax], rbx\n\t" + "mov rbx, 0\n\t" + "mov 0xf0[rax], rbx\n\t" + "mov 0xf8[rax], rbx\n\t" + "pushf\n\t" + "pop rbx\n\t" + "and rbx, 0xff\n\t" + "mov 0x140[rax], rbx\n\t" + "add rsp, 16\n\t" + "pop rdx\n\t" + "pop rcx\n\t" + "pop rbx\n\t" + "pop rax\n\t" + "add rsp, 128\n\t" + MMREG(STOREMM) + EMMS "\n\t" + XMMREG(STOREXMM) + : : "r"(init), "r"(&result), "r"(t->fn) + : "memory", "cc", + "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", + "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", + "xmm12", "xmm13", "xmm14", "xmm15" + ); + compare_state(init, &result); +} + +#define TEST(n, cmd, type) \ +static void __attribute__((naked)) test_##n(void) \ +{ \ + asm volatile(cmd); \ + asm volatile("ret"); \ +} +#include TEST_FILE + + +static const TestDef test_table[] = { +#define TEST(n, cmd, type) {n, test_##n, cmd, &init##type}, +#include TEST_FILE + {-1, NULL, "", NULL} +}; + +static void run_all(void) +{ + const TestDef *t; + for (t = test_table; t->fn; t++) { + run_test(t); + } +} + +#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0])) + +float val_f32[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5, 8.3}; +uint64_t val_i64[] = { + 0x3d6b3b6a9e4118f2lu, 0x355ae76d2774d78clu, + 0xd851c54a56bf1f29lu, 0x4a84d1d50bf4c4fflu, + 0x5826475e2c5fd799lu, 0xfd32edc01243f5e9lu, +}; + +v2di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull}; + +void init_f32reg(uint64_t *r) +{ + static int n; + float v[2]; + int i; + for (i = 0; i < 2; i++) { + v[i] = val_f32[n++]; + if (n == ARRAY_LEN(val_f32)) { + n = 0; + } + } + memcpy(r, v, sizeof(*r)); +} + +void init_intreg(uint64_t *r) +{ + static uint64_t mask; + static int n; + + *r = val_i64[n] ^ mask; + n++; + if (n == ARRAY_LEN(val_i64)) { + n = 0; + mask *= 0x104C11DB7; + } +} + +static void init_all(reg_state *s) +{ + int i; + + for (i = 0; i < 16; i++) { + init_intreg(&s->r[i]); + } + s->r[3] = (uint64_t)&s->mem[0]; /* rdx */ + s->r[5] = (uint64_t)&s->mem[2]; /* rdi */ + s->r[6] = 0; + s->r[7] = 0; + s->flags = 2; + for (i = 0; i < 8; i++) { + s->xmm[i] = deadbeef; + memcpy(&s->mm[i], &s->xmm[i], sizeof(s->mm[i])); + } + for (i = 0; i < 2; i++) { + s->mem0[i] = deadbeef; + } +} + +int main(int argc, char *argv[]) +{ + init_all(&initI); + init_intreg(&initI.mm[5]); + init_intreg(&initI.mm[6]); + init_intreg(&initI.mm[7]); + init_intreg(&initI.mem0[1].q0); + init_intreg(&initI.mem0[1].q1); + printf("Int:\n"); + dump_regs(&initI, 0); + + init_all(&initF32); + init_f32reg(&initF32.mm[5]); + init_f32reg(&initF32.mm[6]); + init_f32reg(&initF32.mm[7]); + init_f32reg(&initF32.mem0[1].q0); + init_f32reg(&initF32.mem0[1].q1); + initF32.ff = 32; + printf("F32:\n"); + dump_regs(&initF32, 32); + + if (argc > 1) { + int n = atoi(argv[1]); + run_test(&test_table[n]); + } else { + run_all(); + } + return 0; +} diff --git a/tests/tcg/i386/test-mmx.py b/tests/tcg/i386/test-mmx.py new file mode 100755 index 0000000000..392315e176 --- /dev/null +++ b/tests/tcg/i386/test-mmx.py @@ -0,0 +1,244 @@ +#! /usr/bin/env python3 + +# Generate test-avx.h from x86.csv + +import csv +import sys +from fnmatch import fnmatch + +ignore = set(["EMMS", "FEMMS", "FISTTP", + "LDMXCSR", "VLDMXCSR", "STMXCSR", "VSTMXCSR"]) + +imask = { + 'PALIGNR': 0x3f, + 'PEXTRB': 0x0f, + 'PEXTRW': 0x07, + 'PEXTRD': 0x03, + 'PEXTRQ': 0x01, + 'PINSRB': 0x0f, + 'PINSRW': 0x07, + 'PINSRD': 0x03, + 'PINSRQ': 0x01, + 'PSHUF[DW]': 0xff, + 'PSHUF[LH]W': 0xff, + 'PS[LR][AL][WDQ]': 0x3f, +} + +def strip_comments(x): + for l in x: + if l != '' and l[0] != '#': + yield l + +def reg_w(w): + if w == 8: + return 'al' + elif w == 16: + return 'ax' + elif w == 32: + return 'eax' + elif w == 64: + return 'rax' + raise Exception("bad reg_w %d" % w) + +def mem_w(w): + if w == 8: + t = "BYTE" + elif w == 16: + t = "WORD" + elif w == 32: + t = "DWORD" + elif w == 64: + t = "QWORD" + else: + raise Exception() + + return t + " PTR 32[rdx]" + +class MMArg(): + isxmm = True + + def __init__(self, mw): + if mw not in [0, 32, 64]: + raise Exception("Bad /m width: %s" % w) + self.mw = mw + self.ismem = mw != 0 + def regstr(self, n): + if n < 0: + return mem_w(self.mw) + else: + return "mm%d" % (n, ) + +def match(op, pattern): + return fnmatch(op, pattern) + +class ArgImm8u(): + isxmm = False + ismem = False + def __init__(self, op): + for k, v in imask.items(): + if match(op, k): + self.mask = imask[k]; + return + raise Exception("Unknown immediate") + def vals(self): + mask = self.mask + yield 0 + n = 0 + while n != mask: + n += 1 + while (n & ~mask) != 0: + n += (n & ~mask) + yield n + +class ArgRM(): + isxmm = False + def __init__(self, rw, mw): + if rw not in [8, 16, 32, 64]: + raise Exception("Bad r/w width: %s" % w) + if mw not in [0, 8, 16, 32, 64]: + raise Exception("Bad r/w width: %s" % w) + self.rw = rw + self.mw = mw + self.ismem = mw != 0 + def regstr(self, n): + if n < 0: + return mem_w(self.mw) + else: + return reg_w(self.rw) + +class ArgMem(): + isxmm = False + ismem = True + def __init__(self, w): + if w not in [8, 16, 32, 64, 128, 256]: + raise Exception("Bad mem width: %s" % w) + self.w = w + def regstr(self, n): + return mem_w(self.w) + +class SkipInstruction(Exception): + pass + +def ArgGenerator(arg, op): + if arg[:2] == 'mm': + if "/" in arg: + r, m = arg.split('/') + if (m[0] != 'm'): + raise Exception("Expected /m: %s", arg) + return MMArg(int(m[1:])); + else: + return MMArg(0); + elif arg[:4] == 'imm8': + return ArgImm8u(op); + elif arg[0] == 'r': + if '/m' in arg: + r, m = arg.split('/') + if (m[0] != 'm'): + raise Exception("Expected /m: %s", arg) + mw = int(m[1:]) + if r == 'r': + rw = mw + else: + rw = int(r[1:]) + return ArgRM(rw, mw) + + return ArgRM(int(arg[1:]), 0); + elif arg[0] == 'm': + return ArgMem(int(arg[1:])) + else: + raise SkipInstruction + +class InsnGenerator: + def __init__(self, op, args): + self.op = op + if op[0:2] == "PF": + self.optype = 'F32' + else: + self.optype = 'I' + + try: + self.args = list(ArgGenerator(a, op) for a in args) + if len(self.args) > 0 and self.args[-1] is None: + self.args = self.args[:-1] + except SkipInstruction: + raise + except Exception as e: + raise Exception("Bad arg %s: %s" % (op, e)) + + def gen(self): + regs = (5, 6, 7) + dest = 4 + + nreg = len(self.args) + if nreg == 0: + yield self.op + return + if isinstance(self.args[-1], ArgImm8u): + nreg -= 1 + immarg = self.args[-1] + else: + immarg = None + memarg = -1 + for n, arg in enumerate(self.args): + if arg.ismem: + memarg = n + + if nreg == 1: + regset = [(regs[0],)] + if memarg == 0: + regset += [(-1,)] + elif nreg == 2: + regset = [ + (regs[0], regs[1]), + (regs[0], regs[0]), + ] + if memarg == 0: + regset += [(-1, regs[0])] + elif memarg == 1: + regset += [(dest, -1)] + else: + raise Exception("Too many regs: %s(%d)" % (self.op, nreg)) + + for regv in regset: + argstr = [] + for i in range(nreg): + arg = self.args[i] + argstr.append(arg.regstr(regv[i])) + if immarg is None: + yield self.op + ' ' + ','.join(argstr) + else: + for immval in immarg.vals(): + yield self.op + ' ' + ','.join(argstr) + ',' + str(immval) + +def split0(s): + if s == '': + return [] + return s.split(',') + +def main(): + n = 0 + if len(sys.argv) <= 3: + print("Usage: test-mmx.py x86.csv test-mmx.h CPUID...") + exit(1) + csvfile = open(sys.argv[1], 'r', newline='') + archs = sys.argv[3:] + with open(sys.argv[2], "w") as outf: + outf.write("// Generated by test-mmx.py. Do not edit.\n") + for row in csv.reader(strip_comments(csvfile)): + insn = row[0].replace(',', '').split() + if insn[0] in ignore: + continue + cpuid = row[6] + if cpuid in archs: + try: + g = InsnGenerator(insn[0], insn[1:]) + for insn in g.gen(): + outf.write('TEST(%d, "%s", %s)\n' % (n, insn, g.optype)) + n += 1 + except SkipInstruction: + pass + outf.write("#undef TEST\n") + csvfile.close() + +if __name__ == "__main__": + main() diff --git a/tests/tcg/i386/x86.csv b/tests/tcg/i386/x86.csv new file mode 100644 index 0000000000..c43bf42dd3 --- /dev/null +++ b/tests/tcg/i386/x86.csv @@ -0,0 +1,4658 @@ +# x86 instruction set description version 0.2x, 2018-05-08 +# +# https://golang.org/x/arch/x86 +# +# The latest version of the CSV file is +# available online at https://golang.org/s/x86.csv. +# +# This file contains a block of comment lines, each beginning with #, +# followed by entries in CSV format. All the # comments are at the top +# of the file, so a reader can skip past the comments and hand the +# rest of the file to a standard CSV reader. +# Each CSV line contains these fields: +# +# 1. The Intel manual instruction mnemonic. For example, "SHR r/m32, imm8". +# +# 2. The Go assembler instruction mnemonic. For example, "SHRL imm8, r/m32". +# +# 3. The GNU binutils instruction mnemonic. For example, "shrl imm8, r/m32". +# +# 4. The instruction encoding. For example, "C1 /4 ib". +# +# 5. The validity of the instruction in 32-bit (aka compatiblity, legacy) mode. +# +# 6. The validity of the instruction in 64-bit mode. +# +# 7. The CPUID feature flags that signal support for the instruction. +# +# 8. Additional comma-separated tags containing hints about the instruction. +# +# 9. The read/write actions of the instruction on the arguments used in +# the Intel mnemonic. For example, "rw,r" to denote that "SHR r/m32, imm8" +# reads and writes its first argument but only reads its second argument. +# +# 10. Whether the opcode used in the Intel mnemonic has encoding forms +# distinguished only by operand size, like most arithmetic instructions. +# The string "Y" indicates yes, the string "" indicates no. +# +# 11. The data size of the operation in bits. In general this is the size corresponding +# to the Go and GNU assembler opcode suffix. +# Mnemonics (the opcode string) +# +# The instruction mnemonics are as used in the Intel manual, with a few exceptions. +# +# Mnemonics claiming general memory forms but that really require fixed addressing modes +# are omitted in favor of their equivalents with implicit arguments.. +# For example, "CMPS m16, m16" (really CMPS [SI], [DI]) is omitted in favor of "CMPSW". +# +# Instruction forms with an explicit REP, REPE, or REPNE prefix are also omitted. +# Encoders and decoders are expected to handle those prefixes separately. +# +# Perhaps most significantly, the argument syntaxes used in the mnemonic indicate +# exactly how to derive the argument from the instruction encoding, or vice versa. +# +# Immediate values: imm8, imm8u, imm16, imm16u, imm32, imm64. +# Immediates are signed by default; the u suffixes indicates an unsigned value. +# Immediates may have bitfield-like modifier that specifies how much bits +# are used. For example, imm8u:4 is encoded like 8bit immediate, +# but only 4bits are meaningful while the others are ignored or must be 0. +# +# Memory operands. The forms m, m128, m14/28byte, m16, m16&16, m16&32, m16&64, m16:16, m16:32, +# m16:64, m16int, m256, m2byte, m32, m32&32, m32fp, m32int, m512byte, m64, m64fp, m64int, +# m8, m80bcd, m80dec, m80fp, m94/108byte. These operands always correspond to the +# memory address specified by the r/m half of the modrm encoding. +# +# Integer registers. +# The forms r8, r16, r32, r64 indicate a register selected by the modrm reg encoding. +# The forms rmr16, rmr32, rmr64 indicate a register (never memory) selected by the modrm r/m encoding. +# The forms r/m8, r/m16, r/m32, and r/m64 indicate a register or memory selected by the modrm r/m encoding. +# Forms with two sizes, like r32/m16 also indicate a register or memory selected by the modrm r/m encodng, +# but the size for a register argument differs from the size of a memory argument. +# The forms r8V, r16V, r32V, r64V indicate a register selected by the VEX.vvvv bits. +# +# Multimedia registers. +# The forms mm1, xmm1, and ymm1 indicate a multimedia register selected by the +# modrm reg encoding. +# The forms mm2, xmm2, and ymm2 indicate a register (never memory) selected by +# the modrm r/m encoding. +# The forms mm2/m64, xmm2/m128, and so on indicate a register or memory +# selected by the modrm r/m encoding. +# The forms xmmV and ymmV indicate a register selected by the VEX.vvvv bits. +# The forms xmmI and ymmI indicate a register selected by the top four bits of an /is4 immediate byte. +# +# Bound registers. +# The form bnd1 indicates a bound register selected by the modrm reg encoding. +# The form bnd2 indicates a bound register (never memory) selected by the modrm r/m encoding. +# The forms bnd2/m64 and bnd2/m128 indicate a register or memorys selected by the modrm r/m encoding. +# TODO: Describe mib. +# +# One-of-a-kind operands: rel8, rel16, rel32, ptr16:16, ptr16:32, +# moffs8, moffs16, moffs32, moffs64, vm32x, vm32y, vm64x, and vm64y +# are all as in the Intel manual. +# +# Encodings +# +# The encodings are also as used in the Intel manual, with automated corrections. +# For example, the Intel manual sometimes omits the modrm /r indicator or other trailing bytes, +# and it also contains typographical errors. +# These problems are corrected so that the CSV data may be used to generate +# tools for processing x86 machine code. +# See https://golang.org/x/arch/x86/x86map for one such generator. +# +# Valid32 and Valid64 +# +# These columns hold validity abbreviations as defined in the Intel manual: +# V, I, N.E., N.P., N.S., or N.I. +# Tools processing the data are typically only concerned with whether the +# column is "V" (valid) or not. +# This data is also corrected compared to the manual. +# For example, the manual lists many instruction forms using REX bytes +# with an incorrect "V" in the Valid32 column. +# +# CPUID Feature Flags +# +# This column specifies CPUID feature flags that must be present in order +# to use the instruction. If multiple flags are required, +# they are listed separated by plus signs, as in PCLMULQDQ+AVX. +# The column can also list one of the values 486, Pentium, PentiumII, and P6, +# indicating that the instruction was introduced on that architecture version. +# +# Tags +# +# The tag column does not correspond to a traditional column in the Intel manual tables. +# Instead, it is itself a comma-separated list of tags or hints derived by analysis +# of the instruction set or the instruction encodings. +# +# The tags address16, address32, and address64 indicate that the instruction form +# applies when using the specified addressing size. It may therefore be necessary to use an +# address size prefix byte to access the instruction. +# If two address tags are listed, the instruction can be used with either of those +# address sizes. An instruction will never list all three address sizes. +# (In fact, today, no instruction lists two address sizes, but that may change.) +# +# The tags operand16, operand32, and operand64 indicate that the instruction form +# applies when using the specified operand size. It may therefore be necessary to use an +# operand size prefix byte to access the instruction. +# If two operand tags are listed, the instruction can be used with either of those +# operand sizes. An instruction will never list all three operand sizes. +# For some instructions, default64 is used instead of operand64, +# which specifies data promotion to 64-bit. +# For instructions with different possible data sizes, +# it also describes that default data size is 64-bit instead of 32-bit. +# Using refining prefix like 0x66 will lead to 32-bit operation (if supported). +# +# The tags modrm_regonly or modrm_memonly indicate that the modrm byte's +# r/m encoding must specify a register or memory, respectively. +# Especially in newer instructions, the modrm constraint may be the only way +# to distinguish two instruction forms. For example the MOVHLPS and MOVLPS +# instructions share the same encoding, except that the former requires the +# modrm byte's r/m to indicate a register, while the latter requires it to indicate memory. +# +# The tags pseudo and pseudo64 indicate that this instruction form is redundant +# with others listed in the table and should be ignored when generating disassembly +# or instruction scanning programs. The pseudo64 tag is reserved for the case where +# the manual lists an instruction twice, once with the optional 64-bit mode REX byte. +# Since most decoders will handle the REX byte separately, the form with the +# unnecessary REX is tagged pseudo64. +# +# The amd tag marks AMD-specific instructions. +# As an example, all instructions of SSE4a have such tag. +# +# The AVX512-specific tags: scaleX and bscaleX. +# scale1, scale2, scale4, scale8, scale16, scale32, scale64 specify +# the compressed displacement multiplier (scaling). +# For example, if displacement is 128 and scale32 is set, +# disp8 value should be calculated as 128/32. +# bscale4 and bscale8 have the same meaning, but are used +# when instruction uses embedded broadcast feature. +# If instruction does not have bscaleX tag, it does not support EVEX broadcasting. +# +# Related packages (can be a good source of additional documentation): +# x86csv - read and manipulate x86.csv +# x86spec - x86.csv generator +# x86map - x86asm table generator based on x86.csv +# x86avxgen - cmd/internal/obj/x86 optab generator based x86.csv +# All listed packages are located at golang.org/x/arch/x86/. +"PUSH imm32","-/PUSHL/PUSHQ imm32","-/pushl/pushq imm32","68 id","V","N.S.","","operand32","r","Y","" +"PUSH imm32","-/PUSHL/PUSHQ imm32","-/pushl/pushq imm32","68 id","N.S.","V","","default64","r","Y","" +"AAA","AAA","aaa","37","V","N.S.","","","","","" +"AAD","AAD","aad","D5 0A","V","I","","pseudo","","","" +"AAD imm8u","AAD imm8u","aad imm8u","D5 ib","V","N.S.","","","r","","" +"AAM","AAM","aam","D4 0A","V","I","","pseudo","","","" +"AAM imm8u","AAM imm8u","aam imm8u","D4 ib","V","N.S.","","","r","","" +"AAS","AAS","aas","3F","V","N.S.","","","","","" +"ADC AL, imm8","ADCB imm8, AL","adcb imm8, AL","14 ib","V","V","","","rw,r","Y","8" +"ADC r/m8, imm8","ADCB imm8, r/m8","adcb imm8, r/m8","80 /2 ib","V","V","","","rw,r","Y","8" +"ADC r/m8, imm8","ADCB imm8, r/m8","adcb imm8, r/m8","82 /2 ib","V","N.S.","","","rw,r","Y","8" +"ADC r/m8, imm8","ADCB imm8, r/m8","adcb imm8, r/m8","REX 80 /2 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"ADC r8, r/m8","ADCB r/m8, r8","adcb r/m8, r8","12 /r","V","V","","","rw,r","Y","8" +"ADC r8, r/m8","ADCB r/m8, r8","adcb r/m8, r8","REX 12 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"ADC r/m8, r8","ADCB r8, r/m8","adcb r8, r/m8","10 /r","V","V","","","rw,r","Y","8" +"ADC r/m8, r8","ADCB r8, r/m8","adcb r8, r/m8","REX 10 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"ADC EAX, imm32","ADCL imm32, EAX","adcl imm32, EAX","15 id","V","V","","operand32","rw,r","Y","32" +"ADC r/m32, imm32","ADCL imm32, r/m32","adcl imm32, r/m32","81 /2 id","V","V","","operand32","rw,r","Y","32" +"ADC r/m32, imm8","ADCL imm8, r/m32","adcl imm8, r/m32","83 /2 ib","V","V","","operand32","rw,r","Y","32" +"ADC r32, r/m32","ADCL r/m32, r32","adcl r/m32, r32","13 /r","V","V","","operand32","rw,r","Y","32" +"ADC r/m32, r32","ADCL r32, r/m32","adcl r32, r/m32","11 /r","V","V","","operand32","rw,r","Y","32" +"ADC RAX, imm32","ADCQ imm32, RAX","adcq imm32, RAX","REX.W 15 id","N.S.","V","","","rw,r","Y","64" +"ADC r/m64, imm32","ADCQ imm32, r/m64","adcq imm32, r/m64","REX.W 81 /2 id","N.S.","V","","","rw,r","Y","64" +"ADC r/m64, imm8","ADCQ imm8, r/m64","adcq imm8, r/m64","REX.W 83 /2 ib","N.S.","V","","","rw,r","Y","64" +"ADC r64, r/m64","ADCQ r/m64, r64","adcq r/m64, r64","REX.W 13 /r","N.S.","V","","","rw,r","Y","64" +"ADC r/m64, r64","ADCQ r64, r/m64","adcq r64, r/m64","REX.W 11 /r","N.S.","V","","","rw,r","Y","64" +"ADC AX, imm16","ADCW imm16, AX","adcw imm16, AX","15 iw","V","V","","operand16","rw,r","Y","16" +"ADC r/m16, imm16","ADCW imm16, r/m16","adcw imm16, r/m16","81 /2 iw","V","V","","operand16","rw,r","Y","16" +"ADC r/m16, imm8","ADCW imm8, r/m16","adcw imm8, r/m16","83 /2 ib","V","V","","operand16","rw,r","Y","16" +"ADC r16, r/m16","ADCW r/m16, r16","adcw r/m16, r16","13 /r","V","V","","operand16","rw,r","Y","16" +"ADC r/m16, r16","ADCW r16, r/m16","adcw r16, r/m16","11 /r","V","V","","operand16","rw,r","Y","16" +"ADCX r32, r/m32","ADCXL r/m32, r32","adcxl r/m32, r32","66 0F 38 F6 /r","V","V","ADX","operand16,operand32","rw,r","Y","32" +"ADCX r64, r/m64","ADCXQ r/m64, r64","adcxq r/m64, r64","66 REX.W 0F 38 F6 /r","N.S.","V","ADX","","rw,r","Y","64" +"ADD AL, imm8","ADDB imm8, AL","addb imm8, AL","04 ib","V","V","","","rw,r","Y","8" +"ADD r/m8, imm8","ADDB imm8, r/m8","addb imm8, r/m8","80 /0 ib","V","V","","","rw,r","Y","8" +"ADD r/m8, imm8","ADDB imm8, r/m8","addb imm8, r/m8","82 /0 ib","V","N.S.","","","rw,r","Y","8" +"ADD r/m8, imm8","ADDB imm8, r/m8","addb imm8, r/m8","REX 80 /0 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"ADD r8, r/m8","ADDB r/m8, r8","addb r/m8, r8","02 /r","V","V","","","rw,r","Y","8" +"ADD r8, r/m8","ADDB r/m8, r8","addb r/m8, r8","REX 02 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"ADD r/m8, r8","ADDB r8, r/m8","addb r8, r/m8","00 /r","V","V","","","rw,r","Y","8" +"ADD r/m8, r8","ADDB r8, r/m8","addb r8, r/m8","REX 00 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"ADD EAX, imm32","ADDL imm32, EAX","addl imm32, EAX","05 id","V","V","","operand32","rw,r","Y","32" +"ADD r/m32, imm32","ADDL imm32, r/m32","addl imm32, r/m32","81 /0 id","V","V","","operand32","rw,r","Y","32" +"ADD r/m32, imm8","ADDL imm8, r/m32","addl imm8, r/m32","83 /0 ib","V","V","","operand32","rw,r","Y","32" +"ADD r32, r/m32","ADDL r/m32, r32","addl r/m32, r32","03 /r","V","V","","operand32","rw,r","Y","32" +"ADD r/m32, r32","ADDL r32, r/m32","addl r32, r/m32","01 /r","V","V","","operand32","rw,r","Y","32" +"ADDPD xmm1, xmm2/m128","ADDPD xmm2/m128, xmm1","addpd xmm2/m128, xmm1","66 0F 58 /r","V","V","SSE2","","rw,r","","" +"ADDPS xmm1, xmm2/m128","ADDPS xmm2/m128, xmm1","addps xmm2/m128, xmm1","0F 58 /r","V","V","SSE","","rw,r","","" +"ADD RAX, imm32","ADDQ imm32, RAX","addq imm32, RAX","REX.W 05 id","N.S.","V","","","rw,r","Y","64" +"ADD r/m64, imm32","ADDQ imm32, r/m64","addq imm32, r/m64","REX.W 81 /0 id","N.S.","V","","","rw,r","Y","64" +"ADD r/m64, imm8","ADDQ imm8, r/m64","addq imm8, r/m64","REX.W 83 /0 ib","N.S.","V","","","rw,r","Y","64" +"ADD r64, r/m64","ADDQ r/m64, r64","addq r/m64, r64","REX.W 03 /r","N.S.","V","","","rw,r","Y","64" +"ADD r/m64, r64","ADDQ r64, r/m64","addq r64, r/m64","REX.W 01 /r","N.S.","V","","","rw,r","Y","64" +"ADDSD xmm1, xmm2/m64","ADDSD xmm2/m64, xmm1","addsd xmm2/m64, xmm1","F2 0F 58 /r","V","V","SSE2","","rw,r","","" +"ADDSS xmm1, xmm2/m32","ADDSS xmm2/m32, xmm1","addss xmm2/m32, xmm1","F3 0F 58 /r","V","V","SSE","","rw,r","","" +"ADDSUBPD xmm1, xmm2/m128","ADDSUBPD xmm2/m128, xmm1","addsubpd xmm2/m128, xmm1","66 0F D0 /r","V","V","SSE3","","rw,r","","" +"ADDSUBPS xmm1, xmm2/m128","ADDSUBPS xmm2/m128, xmm1","addsubps xmm2/m128, xmm1","F2 0F D0 /r","V","V","SSE3","","rw,r","","" +"ADD AX, imm16","ADDW imm16, AX","addw imm16, AX","05 iw","V","V","","operand16","rw,r","Y","16" +"ADD r/m16, imm16","ADDW imm16, r/m16","addw imm16, r/m16","81 /0 iw","V","V","","operand16","rw,r","Y","16" +"ADD r/m16, imm8","ADDW imm8, r/m16","addw imm8, r/m16","83 /0 ib","V","V","","operand16","rw,r","Y","16" +"ADD r16, r/m16","ADDW r/m16, r16","addw r/m16, r16","03 /r","V","V","","operand16","rw,r","Y","16" +"ADD r/m16, r16","ADDW r16, r/m16","addw r16, r/m16","01 /r","V","V","","operand16","rw,r","Y","16" +"ADOX r32, r/m32","ADOXL r/m32, r32","adoxl r/m32, r32","F3 0F 38 F6 /r","V","V","ADX","operand16,operand32","rw,r","Y","32" +"ADOX r64, r/m64","ADOXQ r/m64, r64","adoxq r/m64, r64","F3 REX.W 0F 38 F6 /r","N.S.","V","ADX","","rw,r","Y","64" +"AESDEC xmm1, xmm2/m128","AESDEC xmm2/m128, xmm1","aesdec xmm2/m128, xmm1","66 0F 38 DE /r","V","V","AES","","rw,r","","" +"AESDECLAST xmm1, xmm2/m128","AESDECLAST xmm2/m128, xmm1","aesdeclast xmm2/m128, xmm1","66 0F 38 DF /r","V","V","AES","","rw,r","","" +"AESENC xmm1, xmm2/m128","AESENC xmm2/m128, xmm1","aesenc xmm2/m128, xmm1","66 0F 38 DC /r","V","V","AES","","rw,r","","" +"AESENCLAST xmm1, xmm2/m128","AESENCLAST xmm2/m128, xmm1","aesenclast xmm2/m128, xmm1","66 0F 38 DD /r","V","V","AES","","rw,r","","" +"AESIMC xmm1, xmm2/m128","AESIMC xmm2/m128, xmm1","aesimc xmm2/m128, xmm1","66 0F 38 DB /r","V","V","AES","","w,r","","" +"AESKEYGENASSIST xmm1, xmm2/m128, imm8u","AESKEYGENASSIST imm8u, xmm2/m128, xmm1","aeskeygenassist imm8u, xmm2/m128, xmm1","66 0F 3A DF /r ib","V","V","AES","","w,r,r","","" +"AND AL, imm8","ANDB imm8, AL","andb imm8, AL","24 ib","V","V","","","rw,r","Y","8" +"AND r/m8, imm8","ANDB imm8, r/m8","andb imm8, r/m8","REX 80 /4 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"AND r/m8, imm8u","ANDB imm8u, r/m8","andb imm8u, r/m8","80 /4 ib","V","V","","","rw,r","Y","8" +"AND r/m8, imm8u","ANDB imm8u, r/m8","andb imm8u, r/m8","82 /4 ib","V","N.S.","","","rw,r","Y","8" +"AND r8, r/m8","ANDB r/m8, r8","andb r/m8, r8","22 /r","V","V","","","rw,r","Y","8" +"AND r8, r/m8","ANDB r/m8, r8","andb r/m8, r8","REX 22 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"AND r/m8, r8","ANDB r8, r/m8","andb r8, r/m8","20 /r","V","V","","","rw,r","Y","8" +"AND r/m8, r8","ANDB r8, r/m8","andb r8, r/m8","REX 20 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"AND EAX, imm32","ANDL imm32, EAX","andl imm32, EAX","25 id","V","V","","operand32","rw,r","Y","32" +"AND r/m32, imm32","ANDL imm32, r/m32","andl imm32, r/m32","81 /4 id","V","V","","operand32","rw,r","Y","32" +"AND r/m32, imm8","ANDL imm8, r/m32","andl imm8, r/m32","83 /4 ib","V","V","","operand32","rw,r","Y","32" +"AND r32, r/m32","ANDL r/m32, r32","andl r/m32, r32","23 /r","V","V","","operand32","rw,r","Y","32" +"AND r/m32, r32","ANDL r32, r/m32","andl r32, r/m32","21 /r","V","V","","operand32","rw,r","Y","32" +"ANDN r32, r32V, r/m32","ANDNL r/m32, r32V, r32","andnl r/m32, r32V, r32","VEX.DDS.128.0F38.W0 F2 /r","V","V","BMI1","","rw,r,r","Y","32" +"ANDNPD xmm1, xmm2/m128","ANDNPD xmm2/m128, xmm1","andnpd xmm2/m128, xmm1","66 0F 55 /r","V","V","SSE2","","rw,r","","" +"ANDNPS xmm1, xmm2/m128","ANDNPS xmm2/m128, xmm1","andnps xmm2/m128, xmm1","0F 55 /r","V","V","SSE","","rw,r","","" +"ANDN r64, r64V, r/m64","ANDNQ r/m64, r64V, r64","andnq r/m64, r64V, r64","VEX.DDS.128.0F38.W1 F2 /r","N.S.","V","BMI1","","rw,r,r","Y","64" +"ANDPD xmm1, xmm2/m128","ANDPD xmm2/m128, xmm1","andpd xmm2/m128, xmm1","66 0F 54 /r","V","V","SSE2","","rw,r","","" +"ANDPS xmm1, xmm2/m128","ANDPS xmm2/m128, xmm1","andps xmm2/m128, xmm1","0F 54 /r","V","V","SSE","","rw,r","","" +"AND RAX, imm32","ANDQ imm32, RAX","andq imm32, RAX","REX.W 25 id","N.S.","V","","","rw,r","Y","64" +"AND r/m64, imm32","ANDQ imm32, r/m64","andq imm32, r/m64","REX.W 81 /4 id","N.S.","V","","","rw,r","Y","64" +"AND r/m64, imm8","ANDQ imm8, r/m64","andq imm8, r/m64","REX.W 83 /4 ib","N.S.","V","","","rw,r","Y","64" +"AND r64, r/m64","ANDQ r/m64, r64","andq r/m64, r64","REX.W 23 /r","N.S.","V","","","rw,r","Y","64" +"AND r/m64, r64","ANDQ r64, r/m64","andq r64, r/m64","REX.W 21 /r","N.S.","V","","","rw,r","Y","64" +"AND AX, imm16","ANDW imm16, AX","andw imm16, AX","25 iw","V","V","","operand16","rw,r","Y","16" +"AND r/m16, imm16","ANDW imm16, r/m16","andw imm16, r/m16","81 /4 iw","V","V","","operand16","rw,r","Y","16" +"AND r/m16, imm8","ANDW imm8, r/m16","andw imm8, r/m16","83 /4 ib","V","V","","operand16","rw,r","Y","16" +"AND r16, r/m16","ANDW r/m16, r16","andw r/m16, r16","23 /r","V","V","","operand16","rw,r","Y","16" +"AND r/m16, r16","ANDW r16, r/m16","andw r16, r/m16","21 /r","V","V","","operand16","rw,r","Y","16" +"ARPL r/m16, r16","ARPL r16, r/m16","arpl r16, r/m16","63 /r","V","N.S.","","","rw,r","","" +"BEXTR r32, r/m32, r32V","BEXTRL r32V, r/m32, r32","bextrl r32V, r/m32, r32","VEX.NDS.128.0F38.W0 F7 /r","V","V","BMI1","","w,r,r","Y","32" +"BEXTR r64, r/m64, r64V","BEXTRQ r64V, r/m64, r64","bextrq r64V, r/m64, r64","VEX.NDS.128.0F38.W1 F7 /r","N.S.","V","BMI1","","w,r,r","Y","64" +"BEXTR_XOP r32, r/m32, imm32u","BEXTR_XOPL imm32u, r/m32, r32","bextr_xopl imm32u, r/m32, r32","XOP.128.0A.WIG 10 /r","V","V","TBM","amd,operand16,operand32","w,r,r","Y","32" +"BEXTR_XOP r64, r/m64, imm32u","BEXTR_XOPQ imm32u, r/m64, r64","bextr_xopq imm32u, r/m64, r64","XOP.128.0A.WIG 10 /r","N.S.","V","TBM","amd,operand64","w,r,r","Y","64" +"BLCFILL r32V, r/m32","BLCFILLL r/m32, r32V","blcfill r/m32, r32V","XOP.NDD.128.09.WIG 01 /1","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"BLCFILL r64V, r/m64","BLCFILLQ r/m64, r64V","blcfill r/m64, r64V","XOP.NDD.128.09.W1 01 /1","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"BLCIC r32V, r/m32","BLCICL r/m32, r32V","blcicl r/m32, r32V","XOP.NDD.128.09.WIG 01 /5","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"BLCIC r64V, r/m64","BLCICQ r/m64, r64V","blcicq r/m64, r64V","XOP.NDD.128.09.WIG 01 /5","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"BLCI r32V, r/m32","BLCIL r/m32, r32V","blcil r/m32, r32V","XOP.NDD.128.09.WIG 02 /6","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"BLCI r64V, r/m64","BLCIQ r/m64, r64V","blciq r/m64, r64V","XOP.NDD.128.09.WIG 02 /6","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"BLCMSK r32V, r/m32","BLCMSKL r/m32, r32V","blcmskl r/m32, r32V","XOP.NDD.128.09.WIG 02 /1","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"BLCMSK r64V, r/m64","BLCMSKQ r/m64, r64V","blcmskq r/m64, r64V","XOP.NDD.128.09.WIG 02 /1","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"BLCS r32V, r/m32","BLCSL r/m32, r32V","blcsl r/m32, r32V","XOP.NDD.128.09.WIG 01 /3","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"BLCS r64V, r/m64","BLCSQ r/m64, r64V","blcsq r/m64, r64V","XOP.NDD.128.09.WIG 01 /3","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"BLENDPD xmm1, xmm2/m128, imm8u","BLENDPD imm8u, xmm2/m128, xmm1","blendpd imm8u, xmm2/m128, xmm1","66 0F 3A 0D /r ib","V","V","SSE4_1","","rw,r,r","","" +"BLENDPS xmm1, xmm2/m128, imm8u","BLENDPS imm8u, xmm2/m128, xmm1","blendps imm8u, xmm2/m128, xmm1","66 0F 3A 0C /r ib","V","V","SSE4_1","","rw,r,r","","" +"BLENDVPD xmm1, xmm2/m128, ","BLENDVPD , xmm2/m128, xmm1","blendvpd , xmm2/m128, xmm1","66 0F 38 15 /r","V","V","SSE4_1","","rw,r,r","","" +"BLENDVPS xmm1, xmm2/m128, ","BLENDVPS , xmm2/m128, xmm1","blendvps , xmm2/m128, xmm1","66 0F 38 14 /r","V","V","SSE4_1","","rw,r,r","","" +"BLSFILL r32V, r/m32","BLSFILLL r/m32, r32V","blsfill r/m32, r32V","XOP.NDD.128.09.WIG 01 /2","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"BLSFILL r64V, r/m64","BLSFILLQ r/m64, r64V","blsfill r/m64, r64V","XOP.NDD.128.09.W1 01 /2","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"BLSIC r32V, r/m32","BLSICL r/m32, r32V","blsicl r/m32, r32V","XOP.NDD.128.09.WIG 01 /6","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"BLSIC r64V, r/m64","BLSICQ r/m64, r64V","blsicq r/m64, r64V","XOP.NDD.128.09.WIG 01 /6","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"BLSI r32V, r/m32","BLSIL r/m32, r32V","blsil r/m32, r32V","VEX.NDD.128.0F38.W0 F3 /3","V","V","BMI1","","w,r","Y","32" +"BLSI r64V, r/m64","BLSIQ r/m64, r64V","blsiq r/m64, r64V","VEX.NDD.128.0F38.W1 F3 /3","N.S.","V","BMI1","","w,r","Y","64" +"BLSMSK r32V, r/m32","BLSMSKL r/m32, r32V","blsmskl r/m32, r32V","VEX.NDD.128.0F38.W0 F3 /2","V","V","BMI1","","w,r","Y","32" +"BLSMSK r64V, r/m64","BLSMSKQ r/m64, r64V","blsmskq r/m64, r64V","VEX.NDD.128.0F38.W1 F3 /2","N.S.","V","BMI1","","w,r","Y","64" +"BLSR r32V, r/m32","BLSRL r/m32, r32V","blsrl r/m32, r32V","VEX.NDD.128.0F38.W0 F3 /1","V","V","BMI1","","w,r","Y","32" +"BLSR r64V, r/m64","BLSRQ r/m64, r64V","blsrq r/m64, r64V","VEX.NDD.128.0F38.W1 F3 /1","N.S.","V","BMI1","","w,r","Y","64" +"BNDCL bnd1, r/m32","BNDCL r/m32, bnd1","bndcl r/m32, bnd1","F3 0F 1A /r","V","N.S.","MPX","","r,r","","" +"BNDCL bnd1, r/m64","BNDCL r/m64, bnd1","bndcl r/m64, bnd1","F3 0F 1A /r","N.S.","V","MPX","","r,r","","" +"BNDCN bnd1, r/m32","BNDCN r/m32, bnd1","bndcn r/m32, bnd1","F2 0F 1B /r","V","N.S.","MPX","","r,r","","" +"BNDCN bnd1, r/m64","BNDCN r/m64, bnd1","bndcn r/m64, bnd1","F2 0F 1B /r","N.S.","V","MPX","","r,r","","" +"BNDCU bnd1, r/m32","BNDCU r/m32, bnd1","bndcu r/m32, bnd1","F2 0F 1A /r","V","N.S.","MPX","","r,r","","" +"BNDCU bnd1, r/m64","BNDCU r/m64, bnd1","bndcu r/m64, bnd1","F2 0F 1A /r","N.S.","V","MPX","","r,r","","" +"BNDLDX bnd1, mib","BNDLDX mib, bnd1","bndldx mib, bnd1","0F 1A /r","V","V","MPX","modrm_memonly","w,r","","" +"BNDMK bnd1, m32","BNDMK m32, bnd1","bndmk m32, bnd1","F3 0F 1B /r","V","N.S.","MPX","modrm_memonly","w,r","","" +"BNDMK bnd1, m64","BNDMK m64, bnd1","bndmk m64, bnd1","F3 0F 1B /r","N.S.","V","MPX","modrm_memonly","w,r","","" +"BNDMOV bnd2/m128, bnd1","BNDMOV bnd1, bnd2/m128","bndmov bnd1, bnd2/m128","66 0F 1B /r","N.S.","V","MPX","","w,r","","" +"BNDMOV bnd2/m64, bnd1","BNDMOV bnd1, bnd2/m64","bndmov bnd1, bnd2/m64","66 0F 1B /r","V","N.S.","MPX","","w,r","","" +"BNDMOV bnd1, bnd2/m128","BNDMOV bnd2/m128, bnd1","bndmov bnd2/m128, bnd1","66 0F 1A /r","N.S.","V","MPX","","w,r","","" +"BNDMOV bnd1, bnd2/m64","BNDMOV bnd2/m64, bnd1","bndmov bnd2/m64, bnd1","66 0F 1A /r","V","N.S.","MPX","","w,r","","" +"BNDSTX mib, bnd1","BNDSTX bnd1, mib","bndstx bnd1, mib","0F 1B /r","V","V","MPX","modrm_memonly","w,r","","" +"BOUND r32, m32&32","BOUNDL m32&32, r32","boundl r32, m32&32","62 /r","V","N.S.","","modrm_memonly,operand32","r,r","Y","32" +"BOUND r16, m16&16","BOUNDW m16&16, r16","boundw r16, m16&16","62 /r","V","N.S.","","modrm_memonly,operand16","r,r","Y","16" +"BSF r32, r/m32","BSFL r/m32, r32","bsfl r/m32, r32","0F BC /r","V","V","","operand32","rw,r","Y","32" +"BSF r32, r/m32","BSFL r/m32, r32","bsfl r/m32, r32","F3 0F BC /r","V","V","","operand32","rw,r","Y","32" +"BSF r64, r/m64","BSFQ r/m64, r64","bsfq r/m64, r64","F3 REX.W 0F BC /r","N.S.","V","","","rw,r","Y","64" +"BSF r64, r/m64","BSFQ r/m64, r64","bsfq r/m64, r64","REX.W 0F BC /r","N.S.","V","","","rw,r","Y","64" +"BSF r16, r/m16","BSFW r/m16, r16","bsfw r/m16, r16","0F BC /r","V","V","","operand16","rw,r","Y","16" +"BSF r16, r/m16","BSFW r/m16, r16","bsfw r/m16, r16","F3 0F BC /r","V","V","","operand16","rw,r","Y","16" +"BSR r32, r/m32","BSRL r/m32, r32","bsrl r/m32, r32","0F BD /r","V","V","","operand32","rw,r","Y","32" +"BSR r32, r/m32","BSRL r/m32, r32","bsrl r/m32, r32","F3 0F BD /r","V","V","","operand32","rw,r","Y","32" +"BSR r64, r/m64","BSRQ r/m64, r64","bsrq r/m64, r64","F3 REX.W 0F BD /r","N.S.","V","","","rw,r","Y","64" +"BSR r64, r/m64","BSRQ r/m64, r64","bsrq r/m64, r64","REX.W 0F BD /r","N.S.","V","","","rw,r","Y","64" +"BSR r16, r/m16","BSRW r/m16, r16","bsrw r/m16, r16","0F BD /r","V","V","","operand16","rw,r","Y","16" +"BSR r16, r/m16","BSRW r/m16, r16","bsrw r/m16, r16","F3 0F BD /r","V","V","","operand16","rw,r","Y","16" +"BSWAP r32op","BSWAPL r32op","bswap r32op","0F C8+rd","V","V","486","operand32","rw","Y","32" +"BSWAP r64op","BSWAPQ r64op","bswap r64op","REX.W 0F C8+ro","N.S.","V","486","","rw","Y","64" +"BSWAP r16op","BSWAPW r16op","bswap r16op","0F C8+rw","V","V","486","operand16","rw","Y","16" +"BTC r/m32, imm8u","BTCL imm8u, r/m32","btcl imm8u, r/m32","0F BA /7 ib","V","V","","operand32","rw,r","Y","32" +"BTC r/m32, r32","BTCL r32, r/m32","btcl r32, r/m32","0F BB /r","V","V","","operand32","rw,r","Y","32" +"BTC r/m64, imm8u","BTCQ imm8u, r/m64","btcq imm8u, r/m64","REX.W 0F BA /7 ib","N.S.","V","","","rw,r","Y","64" +"BTC r/m64, r64","BTCQ r64, r/m64","btcq r64, r/m64","REX.W 0F BB /r","N.S.","V","","","rw,r","Y","64" +"BTC r/m16, imm8u","BTCW imm8u, r/m16","btcw imm8u, r/m16","0F BA /7 ib","V","V","","operand16","rw,r","Y","16" +"BTC r/m16, r16","BTCW r16, r/m16","btcw r16, r/m16","0F BB /r","V","V","","operand16","rw,r","Y","16" +"BT r/m32, imm8u","BTL imm8u, r/m32","btl imm8u, r/m32","0F BA /4 ib","V","V","","operand32","r,r","Y","32" +"BT r/m32, r32","BTL r32, r/m32","btl r32, r/m32","0F A3 /r","V","V","","operand32","r,r","Y","32" +"BT r/m64, imm8u","BTQ imm8u, r/m64","btq imm8u, r/m64","REX.W 0F BA /4 ib","N.S.","V","","","r,r","Y","64" +"BT r/m64, r64","BTQ r64, r/m64","btq r64, r/m64","REX.W 0F A3 /r","N.S.","V","","","r,r","Y","64" +"BTR r/m32, imm8u","BTRL imm8u, r/m32","btrl imm8u, r/m32","0F BA /6 ib","V","V","","operand32","rw,r","Y","32" +"BTR r/m32, r32","BTRL r32, r/m32","btrl r32, r/m32","0F B3 /r","V","V","","operand32","rw,r","Y","32" +"BTR r/m64, imm8u","BTRQ imm8u, r/m64","btrq imm8u, r/m64","REX.W 0F BA /6 ib","N.S.","V","","","rw,r","Y","64" +"BTR r/m64, r64","BTRQ r64, r/m64","btrq r64, r/m64","REX.W 0F B3 /r","N.S.","V","","","rw,r","Y","64" +"BTR r/m16, imm8u","BTRW imm8u, r/m16","btrw imm8u, r/m16","0F BA /6 ib","V","V","","operand16","rw,r","Y","16" +"BTR r/m16, r16","BTRW r16, r/m16","btrw r16, r/m16","0F B3 /r","V","V","","operand16","rw,r","Y","16" +"BTS r/m32, imm8u","BTSL imm8u, r/m32","btsl imm8u, r/m32","0F BA /5 ib","V","V","","operand32","rw,r","Y","32" +"BTS r/m32, r32","BTSL r32, r/m32","btsl r32, r/m32","0F AB /r","V","V","","operand32","rw,r","Y","32" +"BTS r/m64, imm8u","BTSQ imm8u, r/m64","btsq imm8u, r/m64","REX.W 0F BA /5 ib","N.S.","V","","","rw,r","Y","64" +"BTS r/m64, r64","BTSQ r64, r/m64","btsq r64, r/m64","REX.W 0F AB /r","N.S.","V","","","rw,r","Y","64" +"BTS r/m16, imm8u","BTSW imm8u, r/m16","btsw imm8u, r/m16","0F BA /5 ib","V","V","","operand16","rw,r","Y","16" +"BTS r/m16, r16","BTSW r16, r/m16","btsw r16, r/m16","0F AB /r","V","V","","operand16","rw,r","Y","16" +"BT r/m16, imm8u","BTW imm8u, r/m16","btw imm8u, r/m16","0F BA /4 ib","V","V","","operand16","r,r","Y","16" +"BT r/m16, r16","BTW r16, r/m16","btw r16, r/m16","0F A3 /r","V","V","","operand16","r,r","Y","16" +"BZHI r32, r/m32, r32V","BZHIL r32V, r/m32, r32","bzhil r32V, r/m32, r32","VEX.NDS.128.0F38.W0 F5 /r","V","V","BMI2","","w,r,r","Y","32" +"BZHI r64, r/m64, r64V","BZHIQ r64V, r/m64, r64","bzhiq r64V, r/m64, r64","VEX.NDS.128.0F38.W1 F5 /r","N.S.","V","BMI2","","w,r,r","Y","64" +"CALL rel16","CALL rel16","call rel16","E8 cw","V","N.S.","","operand16","r","Y","" +"CALL rel32","CALL rel32","call rel32","E8 cd","V","N.S.","","operand32","r","Y","" +"CALL rel32","CALL rel32","call rel32","E8 cd","N.S.","V","","default64","r","Y","" +"CALL r/m32","CALLL* r/m32","calll* r/m32","FF /2","V","N.S.","","operand32","r","Y","32" +"CALL r/m64","CALLQ* r/m64","callq* r/m64","FF /2","N.S.","V","","default64","r","Y","64" +"CALL r/m16","CALLW* r/m16","callw* r/m16","FF /2","V","N.S.","","operand16","r","Y","16" +"CBW","CBW","cbtw","98","V","V","","operand16","","","" +"CDQ","CDQ","cltd","99","V","V","","operand32","","","" +"CDQE","CDQE","cltq","REX.W 98","N.S.","V","","","","","" +"CLAC","CLAC","clac","0F 01 CA","V","V","","","","","" +"CLC","CLC","clc","F8","V","V","","","","","" +"CLD","CLD","cld","FC","V","V","","","","","" +"CLFLUSH m8","CLFLUSH m8","clflush m8","0F AE /7","V","V","","modrm_memonly","r","","" +"CLFLUSHOPT m8","CLFLUSHOPT m8","clflushopt m8","66 0F AE /7","V","V","","modrm_memonly","r","","" +"CLGI","CLGI","clgi","0F 01 DD","V","V","SVM","amd","","","" +"CLI","CLI","cli","FA","V","V","","","","","" +"CLRSSBSY m64","CLRSSBSY m64","clrssbsy m64","F3 0F AE /6","V","V","CET","modrm_memonly","w","","" +"CLTS","CLTS","clts","0F 06","V","V","","","","","" +"CLWB m8","CLWB m8","clwb m8","66 0F AE /6","V","V","CLWB","modrm_memonly","r","","" +"CLZERO EAX","CLZEROL EAX","clzerol EAX","0F 01 FC","V","V","CLZERO","amd,modrm_regonly,operand32","r","Y","32" +"CLZERO RAX","CLZEROQ RAX","clzeroq RAX","REX.W 0F 01 FC","N.S.","V","CLZERO","amd,modrm_regonly","r","Y","64" +"CLZERO AX","CLZEROW AX","clzerow AX","0F 01 FC","V","V","CLZERO","amd,modrm_regonly,operand16","r","Y","16" +"CMC","CMC","cmc","F5","V","V","","","","","" +"CMOVC r16, r/m16","CMOVC r/m16, r16","cmovc r/m16, r16","0F 42 /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVC r32, r/m32","CMOVC r/m32, r32","cmovc r/m32, r32","0F 42 /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVC r64, r/m64","CMOVC r/m64, r64","cmovc r/m64, r64","REX.W 0F 42 /r","N.E.","V","","pseudo","rw,r","","" +"CMOVAE r32, r/m32","CMOVLCC r/m32, r32","cmovael r/m32, r32","0F 43 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVB r32, r/m32","CMOVLCS r/m32, r32","cmovbl r/m32, r32","0F 42 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVE r32, r/m32","CMOVLEQ r/m32, r32","cmovel r/m32, r32","0F 44 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVGE r32, r/m32","CMOVLGE r/m32, r32","cmovgel r/m32, r32","0F 4D /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVG r32, r/m32","CMOVLGT r/m32, r32","cmovgl r/m32, r32","0F 4F /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVA r32, r/m32","CMOVLHI r/m32, r32","cmoval r/m32, r32","0F 47 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVLE r32, r/m32","CMOVLLE r/m32, r32","cmovlel r/m32, r32","0F 4E /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVBE r32, r/m32","CMOVLLS r/m32, r32","cmovbel r/m32, r32","0F 46 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVL r32, r/m32","CMOVLLT r/m32, r32","cmovll r/m32, r32","0F 4C /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVS r32, r/m32","CMOVLMI r/m32, r32","cmovsl r/m32, r32","0F 48 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVNE r32, r/m32","CMOVLNE r/m32, r32","cmovnel r/m32, r32","0F 45 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVNO r32, r/m32","CMOVLOC r/m32, r32","cmovnol r/m32, r32","0F 41 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVO r32, r/m32","CMOVLOS r/m32, r32","cmovol r/m32, r32","0F 40 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVNP r32, r/m32","CMOVLPC r/m32, r32","cmovnpl r/m32, r32","0F 4B /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVNS r32, r/m32","CMOVLPL r/m32, r32","cmovnsl r/m32, r32","0F 49 /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVP r32, r/m32","CMOVLPS r/m32, r32","cmovpl r/m32, r32","0F 4A /r","V","V","","P6,operand32","rw,r","Y","32" +"CMOVNA r16, r/m16","CMOVNA r/m16, r16","cmovna r/m16, r16","0F 46 /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNA r32, r/m32","CMOVNA r/m32, r32","cmovna r/m32, r32","0F 46 /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNA r64, r/m64","CMOVNA r/m64, r64","cmovna r/m64, r64","REX.W 0F 46 /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNAE r16, r/m16","CMOVNAE r/m16, r16","cmovnae r/m16, r16","0F 42 /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNAE r32, r/m32","CMOVNAE r/m32, r32","cmovnae r/m32, r32","0F 42 /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNAE r64, r/m64","CMOVNAE r/m64, r64","cmovnae r/m64, r64","REX.W 0F 42 /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNB r16, r/m16","CMOVNB r/m16, r16","cmovnb r/m16, r16","0F 43 /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNB r32, r/m32","CMOVNB r/m32, r32","cmovnb r/m32, r32","0F 43 /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNB r64, r/m64","CMOVNB r/m64, r64","cmovnb r/m64, r64","REX.W 0F 43 /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNBE r16, r/m16","CMOVNBE r/m16, r16","cmovnbe r/m16, r16","0F 47 /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNBE r32, r/m32","CMOVNBE r/m32, r32","cmovnbe r/m32, r32","0F 47 /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNBE r64, r/m64","CMOVNBE r/m64, r64","cmovnbe r/m64, r64","REX.W 0F 47 /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNC r16, r/m16","CMOVNC r/m16, r16","cmovnc r/m16, r16","0F 43 /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNC r32, r/m32","CMOVNC r/m32, r32","cmovnc r/m32, r32","0F 43 /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNC r64, r/m64","CMOVNC r/m64, r64","cmovnc r/m64, r64","REX.W 0F 43 /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNG r16, r/m16","CMOVNG r/m16, r16","cmovng r/m16, r16","0F 4E /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNG r32, r/m32","CMOVNG r/m32, r32","cmovng r/m32, r32","0F 4E /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNG r64, r/m64","CMOVNG r/m64, r64","cmovng r/m64, r64","REX.W 0F 4E /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNGE r16, r/m16","CMOVNGE r/m16, r16","cmovnge r/m16, r16","0F 4C /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNGE r32, r/m32","CMOVNGE r/m32, r32","cmovnge r/m32, r32","0F 4C /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNGE r64, r/m64","CMOVNGE r/m64, r64","cmovnge r/m64, r64","REX.W 0F 4C /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNL r16, r/m16","CMOVNL r/m16, r16","cmovnl r/m16, r16","0F 4D /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNL r32, r/m32","CMOVNL r/m32, r32","cmovnl r/m32, r32","0F 4D /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNL r64, r/m64","CMOVNL r/m64, r64","cmovnl r/m64, r64","REX.W 0F 4D /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNLE r16, r/m16","CMOVNLE r/m16, r16","cmovnle r/m16, r16","0F 4F /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNLE r32, r/m32","CMOVNLE r/m32, r32","cmovnle r/m32, r32","0F 4F /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNLE r64, r/m64","CMOVNLE r/m64, r64","cmovnle r/m64, r64","REX.W 0F 4F /r","N.E.","V","","pseudo","rw,r","","" +"CMOVNZ r16, r/m16","CMOVNZ r/m16, r16","cmovnz r/m16, r16","0F 45 /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVNZ r32, r/m32","CMOVNZ r/m32, r32","cmovnz r/m32, r32","0F 45 /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVNZ r64, r/m64","CMOVNZ r/m64, r64","cmovnz r/m64, r64","REX.W 0F 45 /r","N.E.","V","","pseudo","rw,r","","" +"CMOVPE r16, r/m16","CMOVPE r/m16, r16","cmovpe r/m16, r16","0F 4A /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVPE r32, r/m32","CMOVPE r/m32, r32","cmovpe r/m32, r32","0F 4A /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVPE r64, r/m64","CMOVPE r/m64, r64","cmovpe r/m64, r64","REX.W 0F 4A /r","N.E.","V","","pseudo","rw,r","","" +"CMOVPO r16, r/m16","CMOVPO r/m16, r16","cmovpo r/m16, r16","0F 4B /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVPO r32, r/m32","CMOVPO r/m32, r32","cmovpo r/m32, r32","0F 4B /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVPO r64, r/m64","CMOVPO r/m64, r64","cmovpo r/m64, r64","REX.W 0F 4B /r","N.E.","V","","pseudo","rw,r","","" +"CMOVAE r64, r/m64","CMOVQCC r/m64, r64","cmovaeq r/m64, r64","REX.W 0F 43 /r","N.S.","V","","","rw,r","Y","64" +"CMOVB r64, r/m64","CMOVQCS r/m64, r64","cmovbq r/m64, r64","REX.W 0F 42 /r","N.S.","V","","","rw,r","Y","64" +"CMOVE r64, r/m64","CMOVQEQ r/m64, r64","cmoveq r/m64, r64","REX.W 0F 44 /r","N.S.","V","","","rw,r","Y","64" +"CMOVGE r64, r/m64","CMOVQGE r/m64, r64","cmovgeq r/m64, r64","REX.W 0F 4D /r","N.S.","V","","","rw,r","Y","64" +"CMOVG r64, r/m64","CMOVQGT r/m64, r64","cmovgq r/m64, r64","REX.W 0F 4F /r","N.S.","V","","","rw,r","Y","64" +"CMOVA r64, r/m64","CMOVQHI r/m64, r64","cmovaq r/m64, r64","REX.W 0F 47 /r","N.S.","V","","","rw,r","Y","64" +"CMOVLE r64, r/m64","CMOVQLE r/m64, r64","cmovleq r/m64, r64","REX.W 0F 4E /r","N.S.","V","","","rw,r","Y","64" +"CMOVBE r64, r/m64","CMOVQLS r/m64, r64","cmovbeq r/m64, r64","REX.W 0F 46 /r","N.S.","V","","","rw,r","Y","64" +"CMOVL r64, r/m64","CMOVQLT r/m64, r64","cmovlq r/m64, r64","REX.W 0F 4C /r","N.S.","V","","","rw,r","Y","64" +"CMOVS r64, r/m64","CMOVQMI r/m64, r64","cmovsq r/m64, r64","REX.W 0F 48 /r","N.S.","V","","","rw,r","Y","64" +"CMOVNE r64, r/m64","CMOVQNE r/m64, r64","cmovneq r/m64, r64","REX.W 0F 45 /r","N.S.","V","","","rw,r","Y","64" +"CMOVNO r64, r/m64","CMOVQOC r/m64, r64","cmovnoq r/m64, r64","REX.W 0F 41 /r","N.S.","V","","","rw,r","Y","64" +"CMOVO r64, r/m64","CMOVQOS r/m64, r64","cmovoq r/m64, r64","REX.W 0F 40 /r","N.S.","V","","","rw,r","Y","64" +"CMOVNP r64, r/m64","CMOVQPC r/m64, r64","cmovnpq r/m64, r64","REX.W 0F 4B /r","N.S.","V","","","rw,r","Y","64" +"CMOVNS r64, r/m64","CMOVQPL r/m64, r64","cmovnsq r/m64, r64","REX.W 0F 49 /r","N.S.","V","","","rw,r","Y","64" +"CMOVP r64, r/m64","CMOVQPS r/m64, r64","cmovpq r/m64, r64","REX.W 0F 4A /r","N.S.","V","","","rw,r","Y","64" +"CMOVAE r16, r/m16","CMOVWCC r/m16, r16","cmovaew r/m16, r16","0F 43 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVB r16, r/m16","CMOVWCS r/m16, r16","cmovbw r/m16, r16","0F 42 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVE r16, r/m16","CMOVWEQ r/m16, r16","cmovew r/m16, r16","0F 44 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVGE r16, r/m16","CMOVWGE r/m16, r16","cmovgew r/m16, r16","0F 4D /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVG r16, r/m16","CMOVWGT r/m16, r16","cmovgw r/m16, r16","0F 4F /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVA r16, r/m16","CMOVWHI r/m16, r16","cmovaw r/m16, r16","0F 47 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVLE r16, r/m16","CMOVWLE r/m16, r16","cmovlew r/m16, r16","0F 4E /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVBE r16, r/m16","CMOVWLS r/m16, r16","cmovbew r/m16, r16","0F 46 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVL r16, r/m16","CMOVWLT r/m16, r16","cmovlw r/m16, r16","0F 4C /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVS r16, r/m16","CMOVWMI r/m16, r16","cmovsw r/m16, r16","0F 48 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVNE r16, r/m16","CMOVWNE r/m16, r16","cmovnew r/m16, r16","0F 45 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVNO r16, r/m16","CMOVWOC r/m16, r16","cmovnow r/m16, r16","0F 41 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVO r16, r/m16","CMOVWOS r/m16, r16","cmovow r/m16, r16","0F 40 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVNP r16, r/m16","CMOVWPC r/m16, r16","cmovnpw r/m16, r16","0F 4B /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVNS r16, r/m16","CMOVWPL r/m16, r16","cmovnsw r/m16, r16","0F 49 /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVP r16, r/m16","CMOVWPS r/m16, r16","cmovpw r/m16, r16","0F 4A /r","V","V","","P6,operand16","rw,r","Y","16" +"CMOVZ r16, r/m16","CMOVZ r/m16, r16","cmovz r/m16, r16","0F 44 /r","V","V","","P6,operand16,pseudo","rw,r","","" +"CMOVZ r32, r/m32","CMOVZ r/m32, r32","cmovz r/m32, r32","0F 44 /r","V","V","","P6,operand32,pseudo","rw,r","","" +"CMOVZ r64, r/m64","CMOVZ r/m64, r64","cmovz r/m64, r64","REX.W 0F 44 /r","N.E.","V","","pseudo","rw,r","","" +"CMP AL, imm8","CMPB AL, imm8","cmpb imm8, AL","3C ib","V","V","","","r,r","Y","8" +"CMP r/m8, imm8","CMPB r/m8, imm8","cmpb imm8, r/m8","80 /7 ib","V","V","","","r,r","Y","8" +"CMP r/m8, imm8","CMPB r/m8, imm8","cmpb imm8, r/m8","82 /7 ib","V","N.S.","","","r,r","Y","8" +"CMP r/m8, imm8","CMPB r/m8, imm8","cmpb imm8, r/m8","REX 80 /7 ib","N.E.","V","","pseudo64","r,r","Y","8" +"CMP r/m8, r8","CMPB r/m8, r8","cmpb r8, r/m8","38 /r","V","V","","","r,r","Y","8" +"CMP r/m8, r8","CMPB r/m8, r8","cmpb r8, r/m8","REX 38 /r","N.E.","V","","pseudo64","r,r","Y","8" +"CMP r8, r/m8","CMPB r8, r/m8","cmpb r/m8, r8","3A /r","V","V","","","r,r","Y","8" +"CMP r8, r/m8","CMPB r8, r/m8","cmpb r/m8, r8","REX 3A /r","N.E.","V","","pseudo64","r,r","Y","8" +"CMP EAX, imm32","CMPL EAX, imm32","cmpl imm32, EAX","3D id","V","V","","operand32","r,r","Y","32" +"CMP r/m32, imm32","CMPL r/m32, imm32","cmpl imm32, r/m32","81 /7 id","V","V","","operand32","r,r","Y","32" +"CMP r/m32, imm8","CMPL r/m32, imm8","cmpl imm8, r/m32","83 /7 ib","V","V","","operand32","r,r","Y","32" +"CMP r/m32, r32","CMPL r/m32, r32","cmpl r32, r/m32","39 /r","V","V","","operand32","r,r","Y","32" +"CMP r32, r/m32","CMPL r32, r/m32","cmpl r/m32, r32","3B /r","V","V","","operand32","r,r","Y","32" +"CMPPD xmm1, xmm2/m128, imm8u","CMPPD imm8u, xmm1, xmm2/m128","cmppd imm8u, xmm2/m128, xmm1","66 0F C2 /r ib","V","V","SSE2","","rw,r,r","","" +"CMPPS xmm1, xmm2/m128, imm8u","CMPPS imm8u, xmm1, xmm2/m128","cmpps imm8u, xmm2/m128, xmm1","0F C2 /r ib","V","V","SSE","","rw,r,r","","" +"CMP RAX, imm32","CMPQ RAX, imm32","cmpq imm32, RAX","REX.W 3D id","N.S.","V","","","r,r","Y","64" +"CMP r/m64, imm32","CMPQ r/m64, imm32","cmpq imm32, r/m64","REX.W 81 /7 id","N.S.","V","","","r,r","Y","64" +"CMP r/m64, imm8","CMPQ r/m64, imm8","cmpq imm8, r/m64","REX.W 83 /7 ib","N.S.","V","","","r,r","Y","64" +"CMP r/m64, r64","CMPQ r/m64, r64","cmpq r64, r/m64","REX.W 39 /r","N.S.","V","","","r,r","Y","64" +"CMP r64, r/m64","CMPQ r64, r/m64","cmpq r/m64, r64","REX.W 3B /r","N.S.","V","","","r,r","Y","64" +"CMPSB","CMPSB","cmpsb","A6","V","V","","","","","" +"CMPSD xmm1, xmm2/m64, imm8u","CMPSD imm8u, xmm1, xmm2/m64","cmpsd imm8u, xmm2/m64, xmm1","F2 0F C2 /r ib","V","V","SSE2","","rw,r,r","","" +"CMPSD","CMPSL","cmpsl","A7","V","V","","operand32","","","" +"CMPSQ","CMPSQ","cmpsq","REX.W A7","N.S.","V","","","","","" +"CMPSS xmm1, xmm2/m32, imm8u","CMPSS imm8u, xmm1, xmm2/m32","cmpss imm8u, xmm2/m32, xmm1","F3 0F C2 /r ib","V","V","SSE","","rw,r,r","","" +"CMPSW","CMPSW","cmpsw","A7","V","V","","operand16","","","" +"CMP AX, imm16","CMPW AX, imm16","cmpw imm16, AX","3D iw","V","V","","operand16","r,r","Y","16" +"CMP r/m16, imm16","CMPW r/m16, imm16","cmpw imm16, r/m16","81 /7 iw","V","V","","operand16","r,r","Y","16" +"CMP r/m16, imm8","CMPW r/m16, imm8","cmpw imm8, r/m16","83 /7 ib","V","V","","operand16","r,r","Y","16" +"CMP r/m16, r16","CMPW r/m16, r16","cmpw r16, r/m16","39 /r","V","V","","operand16","r,r","Y","16" +"CMP r16, r/m16","CMPW r16, r/m16","cmpw r/m16, r16","3B /r","V","V","","operand16","r,r","Y","16" +"CMPXCHG16B m128","CMPXCHG16B m128","cmpxchg16b m128","REX.W 0F C7 /1","N.S.","V","","modrm_memonly","rw","","" +"CMPXCHG8B m64","CMPXCHG8B m64","cmpxchg8b m64","0F C7 /1","V","V","Pentium","modrm_memonly,operand16,operand32","rw","","" +"CMPXCHG r/m8, r8","CMPXCHGB r8, r/m8","cmpxchgb r8, r/m8","0F B0 /r","V","V","486","","rw,r","Y","8" +"CMPXCHG r/m8, r8","CMPXCHGB r8, r/m8","cmpxchgb r8, r/m8","REX 0F B0 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"CMPXCHG r/m32, r32","CMPXCHGL r32, r/m32","cmpxchgl r32, r/m32","0F B1 /r","V","V","486","operand32","rw,r","Y","32" +"CMPXCHG r/m64, r64","CMPXCHGQ r64, r/m64","cmpxchgq r64, r/m64","REX.W 0F B1 /r","N.S.","V","486","","rw,r","Y","64" +"CMPXCHG r/m16, r16","CMPXCHGW r16, r/m16","cmpxchgw r16, r/m16","0F B1 /r","V","V","486","operand16","rw,r","Y","16" +"COMISD xmm1, xmm2/m64","COMISD xmm2/m64, xmm1","comisd xmm2/m64, xmm1","66 0F 2F /r","V","V","SSE2","","r,r","","" +"COMISS xmm1, xmm2/m32","COMISS xmm2/m32, xmm1","comiss xmm2/m32, xmm1","0F 2F /r","V","V","SSE","","r,r","","" +"CPUID","CPUID","cpuid","0F A2","V","V","486","","","","" +"CQO","CQO","cqto","REX.W 99","N.S.","V","","","","","" +"CRC32 r32, r/m8","CRC32B r/m8, r32","crc32b r/m8, r32","F2 0F 38 F0 /r","V","V","SSE4_2","operand16,operand32","rw,r","Y","8" +"CRC32 r32, r/m8","CRC32B r/m8, r32","crc32b r/m8, r32","F2 REX 0F 38 F0 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"CRC32 r64, r/m8","CRC32B r/m8, r64","crc32b r/m8, r64","F2 REX.W 0F 38 F0 /r","N.S.","V","SSE4_2","","rw,r","Y","8" +"CRC32 r32, r/m32","CRC32L r/m32, r32","crc32l r/m32, r32","F2 0F 38 F1 /r","V","V","SSE4_2","operand32","rw,r","Y","32" +"CRC32 r64, r/m64","CRC32Q r/m64, r64","crc32q r/m64, r64","F2 REX.W 0F 38 F1 /r","N.S.","V","SSE4_2","","rw,r","Y","64" +"CRC32 r32, r/m16","CRC32W r/m16, r32","crc32w r/m16, r32","F2 0F 38 F1 /r","V","V","SSE4_2","operand16","rw,r","Y","16" +"CVTPD2PI mm1, xmm2/m128","CVTPD2PI xmm2/m128, mm1","cvtpd2pi xmm2/m128, mm1","66 0F 2D /r","V","V","SSE2","","w,r","","" +"CVTPD2DQ xmm1, xmm2/m128","CVTPD2PL xmm2/m128, xmm1","cvtpd2dq xmm2/m128, xmm1","F2 0F E6 /r","V","V","SSE2","","w,r","","" +"CVTPD2PS xmm1, xmm2/m128","CVTPD2PS xmm2/m128, xmm1","cvtpd2ps xmm2/m128, xmm1","66 0F 5A /r","V","V","SSE2","","w,r","","" +"CVTPI2PD xmm1, mm2/m64","CVTPI2PD mm2/m64, xmm1","cvtpi2pd mm2/m64, xmm1","66 0F 2A /r","V","V","SSE2","","w,r","","" +"CVTPI2PS xmm1, mm2/m64","CVTPI2PS mm2/m64, xmm1","cvtpi2ps mm2/m64, xmm1","0F 2A /r","V","V","SSE","","w,r","","" +"CVTDQ2PD xmm1, xmm2/m64","CVTPL2PD xmm2/m64, xmm1","cvtdq2pd xmm2/m64, xmm1","F3 0F E6 /r","V","V","SSE2","","w,r","","" +"CVTDQ2PS xmm1, xmm2/m128","CVTPL2PS xmm2/m128, xmm1","cvtdq2ps xmm2/m128, xmm1","0F 5B /r","V","V","SSE2","","w,r","","" +"CVTPS2PD xmm1, xmm2/m64","CVTPS2PD xmm2/m64, xmm1","cvtps2pd xmm2/m64, xmm1","0F 5A /r","V","V","SSE2","","w,r","","" +"CVTPS2PI mm1, xmm2/m64","CVTPS2PI xmm2/m64, mm1","cvtps2pi xmm2/m64, mm1","0F 2D /r","V","V","SSE","","w,r","","" +"CVTPS2DQ xmm1, xmm2/m128","CVTPS2PL xmm2/m128, xmm1","cvtps2dq xmm2/m128, xmm1","66 0F 5B /r","V","V","SSE2","","w,r","","" +"CVTSD2SI r32, xmm2/m64","CVTSD2SL xmm2/m64, r32","cvtsd2si xmm2/m64, r32","F2 0F 2D /r","V","V","SSE2","operand16,operand32","w,r","Y","32" +"CVTSD2SI r64, xmm2/m64","CVTSD2SL xmm2/m64, r64","cvtsd2siq xmm2/m64, r64","F2 REX.W 0F 2D /r","N.S.","V","SSE2","","w,r","Y","64" +"CVTSD2SS xmm1, xmm2/m64","CVTSD2SS xmm2/m64, xmm1","cvtsd2ss xmm2/m64, xmm1","F2 0F 5A /r","V","V","SSE2","","w,r","","" +"CVTSI2SD xmm1, r/m32","CVTSL2SD r/m32, xmm1","cvtsi2sdl r/m32, xmm1","F2 0F 2A /r","V","V","SSE2","operand16,operand32","w,r","Y","32" +"CVTSI2SS xmm1, r/m32","CVTSL2SS r/m32, xmm1","cvtsi2ssl r/m32, xmm1","F3 0F 2A /r","V","V","SSE","operand16,operand32","w,r","Y","32" +"CVTSI2SD xmm1, r/m64","CVTSQ2SD r/m64, xmm1","cvtsi2sdq r/m64, xmm1","F2 REX.W 0F 2A /r","N.S.","V","SSE2","","w,r","Y","64" +"CVTSI2SS xmm1, r/m64","CVTSQ2SS r/m64, xmm1","cvtsi2ssq r/m64, xmm1","F3 REX.W 0F 2A /r","N.S.","V","SSE","","w,r","Y","64" +"CVTSS2SD xmm1, xmm2/m32","CVTSS2SD xmm2/m32, xmm1","cvtss2sd xmm2/m32, xmm1","F3 0F 5A /r","V","V","SSE2","","w,r","","" +"CVTSS2SI r32, xmm2/m32","CVTSS2SL xmm2/m32, r32","cvtss2si xmm2/m32, r32","F3 0F 2D /r","V","V","SSE","operand16,operand32","w,r","Y","32" +"CVTSS2SI r64, xmm2/m32","CVTSS2SL xmm2/m32, r64","cvtss2siq xmm2/m32, r64","F3 REX.W 0F 2D /r","N.S.","V","SSE","","w,r","Y","64" +"CVTTPD2PI mm1, xmm2/m128","CVTTPD2PI xmm2/m128, mm1","cvttpd2pi xmm2/m128, mm1","66 0F 2C /r","V","V","SSE2","","w,r","","" +"CVTTPD2DQ xmm1, xmm2/m128","CVTTPD2PL xmm2/m128, xmm1","cvttpd2dq xmm2/m128, xmm1","66 0F E6 /r","V","V","SSE2","","w,r","","" +"CVTTPS2PI mm1, xmm2/m64","CVTTPS2PI xmm2/m64, mm1","cvttps2pi xmm2/m64, mm1","0F 2C /r","V","V","SSE","","w,r","","" +"CVTTPS2DQ xmm1, xmm2/m128","CVTTPS2PL xmm2/m128, xmm1","cvttps2dq xmm2/m128, xmm1","F3 0F 5B /r","V","V","SSE2","","w,r","","" +"CVTTSD2SI r32, xmm2/m64","CVTTSD2SL xmm2/m64, r32","cvttsd2si xmm2/m64, r32","F2 0F 2C /r","V","V","SSE2","operand16,operand32","w,r","Y","32" +"CVTTSD2SI r64, xmm2/m64","CVTTSD2SL xmm2/m64, r64","cvttsd2siq xmm2/m64, r64","F2 REX.W 0F 2C /r","N.S.","V","SSE2","","w,r","Y","64" +"CVTTSS2SI r32, xmm2/m32","CVTTSS2SL xmm2/m32, r32","cvttss2si xmm2/m32, r32","F3 0F 2C /r","V","V","SSE","operand16,operand32","w,r","Y","32" +"CVTTSS2SI r64, xmm2/m32","CVTTSS2SL xmm2/m32, r64","cvttss2siq xmm2/m32, r64","F3 REX.W 0F 2C /r","N.S.","V","SSE","","w,r","Y","64" +"CWD","CWD","cwtd","99","V","V","","operand16","","","" +"CWDE","CWDE","cwtl","98","V","V","","operand32","","","" +"DAA","DAA","daa","27","V","N.S.","","","","","" +"DAS","DAS","das","2F","V","N.S.","","","","","" +"DEC r/m8","DECB r/m8","decb r/m8","FE /1","V","V","","","rw","Y","8" +"DEC r/m8","DECB r/m8","decb r/m8","REX FE /1","N.E.","V","","pseudo64","rw","Y","8" +"DEC r/m32","DECL r/m32","decl r/m32","FF /1","V","V","","operand32","rw","Y","32" +"DEC r32op","DECL r32op","decl r32op","48+rd","V","N.S.","","operand32","rw","Y","32" +"DEC r/m64","DECQ r/m64","decq r/m64","REX.W FF /1","N.S.","V","","","rw","Y","64" +"DEC r/m16","DECW r/m16","decw r/m16","FF /1","V","V","","operand16","rw","Y","16" +"DEC r16op","DECW r16op","decw r16op","48+rw","V","N.S.","","operand16","rw","Y","16" +"DIV r/m8","DIVB r/m8","divb r/m8","F6 /6","V","V","","","r","Y","8" +"DIV r/m8","DIVB r/m8","divb r/m8","REX F6 /6","N.E.","V","","pseudo64","w","Y","8" +"DIV r/m32","DIVL r/m32","divl r/m32","F7 /6","V","V","","operand32","r","Y","32" +"DIVPD xmm1, xmm2/m128","DIVPD xmm2/m128, xmm1","divpd xmm2/m128, xmm1","66 0F 5E /r","V","V","SSE2","","rw,r","","" +"DIVPS xmm1, xmm2/m128","DIVPS xmm2/m128, xmm1","divps xmm2/m128, xmm1","0F 5E /r","V","V","SSE","","rw,r","","" +"DIV r/m64","DIVQ r/m64","divq r/m64","REX.W F7 /6","N.S.","V","","","r","Y","64" +"DIVSD xmm1, xmm2/m64","DIVSD xmm2/m64, xmm1","divsd xmm2/m64, xmm1","F2 0F 5E /r","V","V","SSE2","","rw,r","","" +"DIVSS xmm1, xmm2/m32","DIVSS xmm2/m32, xmm1","divss xmm2/m32, xmm1","F3 0F 5E /r","V","V","SSE","","rw,r","","" +"DIV r/m16","DIVW r/m16","divw r/m16","F7 /6","V","V","","operand16","r","Y","16" +"DPPD xmm1, xmm2/m128, imm8u","DPPD imm8u, xmm2/m128, xmm1","dppd imm8u, xmm2/m128, xmm1","66 0F 3A 41 /r ib","V","V","SSE4_1","","rw,r,r","","" +"DPPS xmm1, xmm2/m128, imm8u","DPPS imm8u, xmm2/m128, xmm1","dpps imm8u, xmm2/m128, xmm1","66 0F 3A 40 /r ib","V","V","SSE4_1","","rw,r,r","","" +"EMMS","EMMS","emms","0F 77","V","V","MMX","","","","" +"ENCLS","ENCLS","encls","0F 01 CF","V","V","","","","","" +"ENCLU","ENCLU","enclu","0F 01 D7","V","V","","","","","" +"ENDBR32","ENDBR32","endbr32","F3 0F 1E FB","V","V","CET","","","","" +"ENDBR64","ENDBR64","endbr64","F3 0F 1E FA","V","V","CET","","","Y","" +"ENTER imm16, 0","ENTER 0, imm16","enter imm16, 0","C8 iw 00","V","V","","pseudo","r,r","","" +"ENTER imm16, 1","ENTER 1, imm16","enter imm16, 1","C8 iw 01","V","V","","pseudo","r,r","","" +"ENTER imm16, imm8b","ENTERW/ENTERL/ENTERQ imm8b, imm16","enterw/enterl/enterq imm16, imm8b","C8 iw ib","V","V","","","r,r","","" +"EXTRACTPS r/m32, xmm1, imm8u:2","EXTRACTPS imm8u:2, xmm1, r/m32","extractps imm8u:2, xmm1, r/m32","66 0F 3A 17 /r ib","V","V","SSE4_1","","w,r,r","","" +"EXTRQ xmm1, imm8u, imm8u","EXTRQ imm8u, imm8u, xmm1","extrq imm8u, imm8u, xmm1","66 0F 78 /0 ib ib","V","V","SSE4a","amd,modrm_regonly","w,r,r","","" +"EXTRQ xmm1, xmm2","EXTRQ xmm2, xmm1","extrq xmm2, xmm1","66 0F 79 /r","V","V","SSE4a","amd,modrm_regonly","w,r","","" +"F2XM1","F2XM1","f2xm1","D9 F0","V","V","","","","","" +"FABS","FABS","fabs","D9 E1","V","V","","","","","" +"FADD ST(i), ST(0)","FADDD ST(0), ST(i)","fadd ST(0), ST(i)","DC C0+i","V","V","","","rw,r","Y","" +"FADD ST(0), ST(i)","FADDD ST(i), ST(0)","fadd ST(i), ST(0)","D8 C0+i","V","V","","","rw,r","Y","" +"FADD ST(0), m32fp","FADDD m32fp, ST(0)","fadds m32fp, ST(0)","D8 /0","V","V","","","rw,r","Y","32" +"FADD ST(0), m64fp","FADDD m64fp, ST(0)","faddl m64fp, ST(0)","DC /0","V","V","","","rw,r","Y","64" +"FADDP","FADDDP","faddp","DE C1","V","V","","pseudo","","","" +"FADDP ST(i), ST(0)","FADDDP ST(0), ST(i)","faddp ST(0), ST(i)","DE C0+i","V","V","","","rw,r","","" +"FBLD ST(0), m80dec","FBLD m80dec, ST(0)","fbld m80dec, ST(0)","DF /4","V","V","","","w,r","","" +"FBSTP m80dec, ST(0)","FBSTP ST(0), m80dec","fbstp ST(0), m80dec","DF /6","V","V","","","w,r","","" +"FCHS","FCHS","fchs","D9 E0","V","V","","","","","" +"FCLEX","FCLEX","fclex","9B DB E2","V","V","","pseudo","","","" +"FCMOVB ST(0), ST(i)","FCMOVB ST(i), ST(0)","fcmovb ST(i), ST(0)","DA C0+i","V","V","","P6","rw,r","","" +"FCMOVBE ST(0), ST(i)","FCMOVBE ST(i), ST(0)","fcmovbe ST(i), ST(0)","DA D0+i","V","V","","P6","rw,r","","" +"FCMOVE ST(0), ST(i)","FCMOVE ST(i), ST(0)","fcmove ST(i), ST(0)","DA C8+i","V","V","","P6","rw,r","","" +"FCMOVNB ST(0), ST(i)","FCMOVNB ST(i), ST(0)","fcmovnb ST(i), ST(0)","DB C0+i","V","V","","P6","rw,r","","" +"FCMOVNBE ST(0), ST(i)","FCMOVNBE ST(i), ST(0)","fcmovnbe ST(i), ST(0)","DB D0+i","V","V","","P6","rw,r","","" +"FCMOVNE ST(0), ST(i)","FCMOVNE ST(i), ST(0)","fcmovne ST(i), ST(0)","DB C8+i","V","V","","P6","rw,r","","" +"FCMOVNU ST(0), ST(i)","FCMOVNU ST(i), ST(0)","fcmovnu ST(i), ST(0)","DB D8+i","V","V","","P6","rw,r","","" +"FCMOVU ST(0), ST(i)","FCMOVU ST(i), ST(0)","fcmovu ST(i), ST(0)","DA D8+i","V","V","","P6","rw,r","","" +"FCOM","FCOMD","fcom","D8 D1","V","V","","pseudo","","Y","" +"FCOM ST(0), ST(i)","FCOMD ST(i), ST(0)","fcom ST(i), ST(0)","D8 D0+i","V","V","","","r,r","Y","" +"FCOM ST(0), ST(i)","FCOMD ST(i), ST(0)","fcom ST(i), ST(0)","DC D0+i","V","V","","","r,r","Y","" +"FCOM ST(0), m32fp","FCOMD m32fp, ST(0)","fcoms m32fp, ST(0)","D8 /2","V","V","","","r,r","Y","32" +"FCOM ST(0), m64fp","FCOMD m64fp, ST(0)","fcoml m64fp, ST(0)","DC /2","V","V","","","r,r","Y","64" +"FCOMP ST(0), m32fp","FCOMFP m32fp, ST(0)","fcomps m32fp, ST(0)","D8 /3","V","V","","","r,r","Y","32" +"FCOMI ST(0), ST(i)","FCOMI ST(i), ST(0)","fcomi ST(i), ST(0)","DB F0+i","V","V","PPRO","P6","r,r","","" +"FCOMIP ST(0), ST(i)","FCOMIP ST(i), ST(0)","fcomip ST(i), ST(0)","DF F0+i","V","V","PPRO","P6","r,r","","" +"FCOMP","FCOMP","fcomp","D8 D9","V","V","","pseudo","","Y","" +"FCOMP ST(0), ST(i)","FCOMP ST(i), ST(0)","fcomp ST(i), ST(0)","D8 D8+i","V","V","","","r,r","Y","" +"FCOMP ST(0), ST(i)","FCOMP ST(i), ST(0)","fcomp ST(i), ST(0)","DC D8+i","V","V","","","r,r","Y","" +"FCOMP ST(0), ST(i)","FCOMP ST(i), ST(0)","fcomp ST(i), ST(0)","DE D0+i","V","V","","","r,r","Y","" +"FCOMP ST(0), m64fp","FCOMPL m64fp, ST(0)","fcompl m64fp, ST(0)","DC /3","V","V","","","r,r","Y","64" +"FCOMPP","FCOMPP","fcompp","DE D9","V","V","","","","","" +"FCOS","FCOS","fcos","D9 FF","V","V","","","","","" +"FDECSTP","FDECSTP","fdecstp","D9 F6","V","V","","","","","" +"FDISI8087_NOP","FDISI8087_NOP","fdisi8087_nop","DB E1","V","V","","","","","" +"FDIVR ST(i), ST(0)","FDIVD ST(0), ST(i)","fdiv ST(0), ST(i)","DC F0+i","V","V","","","rw,r","Y","" +"FDIV ST(i), ST(0)","FDIVD ST(0), ST(i)","fdivr ST(0), ST(i)","DC F8+i","V","V","","","rw,r","Y","" +"FDIV ST(0), ST(i)","FDIVD ST(i), ST(0)","fdiv ST(i), ST(0)","D8 F0+i","V","V","","","rw,r","Y","" +"FDIV ST(0), m32fp","FDIVD m32fp, ST(0)","fdivs m32fp, ST(0)","D8 /6","V","V","","","rw,r","Y","32" +"FDIV ST(0), m64fp","FDIVD m64fp, ST(0)","fdivl m64fp, ST(0)","DC /6","V","V","","","rw,r","Y","64" +"FDIVR ST(0), m32fp","FDIVFR m32fp, ST(0)","fdivrs m32fp, ST(0)","D8 /7","V","V","","","rw,r","Y","32" +"FDIVP","FDIVP","fdivp","DE F9","V","V","","pseudo","","","" +"FDIVRP ST(i), ST(0)","FDIVP ST(0), ST(i)","fdivp ST(0), ST(i)","DE F0+i","V","V","","","rw,r","","" +"FDIVR ST(0), ST(i)","FDIVR ST(i), ST(0)","fdivr ST(i), ST(0)","D8 F8+i","V","V","","","rw,r","Y","" +"FDIVR ST(0), m64fp","FDIVRL m64fp, ST(0)","fdivrl m64fp, ST(0)","DC /7","V","V","","","rw,r","Y","64" +"FDIVRP","FDIVRP","fdivrp","DE F1","V","V","","pseudo","","","" +"FDIVP ST(i), ST(0)","FDIVRP ST(0), ST(i)","fdivrp ST(0), ST(i)","DE F8+i","V","V","","","rw,r","","" +"FEMMS","FEMMS","femms","0F 0E","V","V","3DNOW","amd","","","" +"FENI8087_NOP","FENI8087_NOP","feni8087_nop","DB E0","V","V","","","","","" +"FFREE ST(i)","FFREE ST(i)","ffree ST(i)","DD C0+i","V","V","","","r","","" +"FFREEP ST(i)","FFREEP ST(i)","ffreep ST(i)","DF C0+i","V","V","","","r","","" +"FIADD ST(0), m16int","FIADD m16int, ST(0)","fiadd m16int, ST(0)","DE /0","V","V","","","rw,r","Y","" +"FIADD ST(0), m32int","FIADDL m32int, ST(0)","fiaddl m32int, ST(0)","DA /0","V","V","","","rw,r","Y","32" +"FICOM ST(0), m16int","FICOM m16int, ST(0)","ficom m16int, ST(0)","DE /2","V","V","","","r,r","Y","" +"FICOM ST(0), m32int","FICOML m32int, ST(0)","ficoml m32int, ST(0)","DA /2","V","V","","","r,r","Y","32" +"FICOMP ST(0), m16int","FICOMP m16int, ST(0)","ficomp m16int, ST(0)","DE /3","V","V","","","r,r","Y","" +"FICOMP ST(0), m32int","FICOMPL m32int, ST(0)","ficompl m32int, ST(0)","DA /3","V","V","","","r,r","Y","32" +"FIDIV ST(0), m16int","FIDIV m16int, ST(0)","fidiv m16int, ST(0)","DE /6","V","V","","","rw,r","Y","" +"FIDIV ST(0), m32int","FIDIVL m32int, ST(0)","fidivl m32int, ST(0)","DA /6","V","V","","","rw,r","Y","32" +"FIDIVR ST(0), m16int","FIDIVR m16int, ST(0)","fidivr m16int, ST(0)","DE /7","V","V","","","rw,r","Y","" +"FIDIVR ST(0), m32int","FIDIVRL m32int, ST(0)","fidivrl m32int, ST(0)","DA /7","V","V","","","rw,r","Y","32" +"FILD ST(0), m16int","FILD m16int, ST(0)","fild m16int, ST(0)","DF /0","V","V","","","w,r","Y","" +"FILD ST(0), m32int","FILDL m32int, ST(0)","fildl m32int, ST(0)","DB /0","V","V","","","w,r","Y","32" +"FILD ST(0), m64int","FILDLL m64int, ST(0)","fildll m64int, ST(0)","DF /5","V","V","","","w,r","Y","64" +"FIMUL ST(0), m16int","FIMUL m16int, ST(0)","fimul m16int, ST(0)","DE /1","V","V","","","rw,r","Y","" +"FIMUL ST(0), m32int","FIMULL m32int, ST(0)","fimull m32int, ST(0)","DA /1","V","V","","","rw,r","Y","32" +"FINCSTP","FINCSTP","fincstp","D9 F7","V","V","","","","","" +"FINIT","FINIT","finit","9B DB E3","V","V","","pseudo","","","" +"FIST m16int, ST(0)","FIST ST(0), m16int","fist ST(0), m16int","DF /2","V","V","","","w,r","Y","" +"FIST m32int, ST(0)","FISTL ST(0), m32int","fistl ST(0), m32int","DB /2","V","V","","","w,r","Y","32" +"FISTP m16int, ST(0)","FISTP ST(0), m16int","fistp ST(0), m16int","DF /3","V","V","","","w,r","Y","" +"FISTP m32int, ST(0)","FISTPL ST(0), m32int","fistpl ST(0), m32int","DB /3","V","V","","","w,r","Y","32" +"FISTP m64int, ST(0)","FISTPLL ST(0), m64int","fistpll ST(0), m64int","DF /7","V","V","","","w,r","Y","64" +"FISTTP m16int, ST(0)","FISTTP ST(0), m16int","fisttp ST(0), m16int","DF /1","V","V","SSE3","modrm_memonly","w,r","Y","" +"FISTTP m32int, ST(0)","FISTTPL ST(0), m32int","fisttpl ST(0), m32int","DB /1","V","V","SSE3","modrm_memonly","w,r","Y","32" +"FISTTP m64int, ST(0)","FISTTPLL ST(0), m64int","fisttpll ST(0), m64int","DD /1","V","V","SSE3","modrm_memonly","w,r","Y","64" +"FISUB ST(0), m16int","FISUB m16int, ST(0)","fisub m16int, ST(0)","DE /4","V","V","","","rw,r","Y","" +"FISUB ST(0), m32int","FISUBL m32int, ST(0)","fisubl m32int, ST(0)","DA /4","V","V","","","rw,r","Y","32" +"FISUBR ST(0), m16int","FISUBR m16int, ST(0)","fisubr m16int, ST(0)","DE /5","V","V","","","rw,r","Y","" +"FISUBR ST(0), m32int","FISUBRL m32int, ST(0)","fisubrl m32int, ST(0)","DA /5","V","V","","","rw,r","Y","32" +"FLD ST(0), ST(i)","FLD ST(i), ST(0)","fld ST(i), ST(0)","D9 C0+i","V","V","","","w,r","Y","" +"FLD1","FLD1","fld1","D9 E8","V","V","","","","","" +"FLDCW m2byte","FLDCW m2byte","fldcw m2byte","D9 /5","V","V","","","r","","" +"FLDENV m28byte","FLDENV m28byte","fldenv m28byte","D9 /4","V","V","","operand32,operand64","r","","" +"FLDENV m14byte","FLDENVS m14byte","fldenv m14byte","D9 /4","V","V","","operand16","r","","" +"FLD ST(0), m64fp","FLDL m64fp, ST(0)","fldl m64fp, ST(0)","DD /0","V","V","","","w,r","Y","64" +"FLDL2E","FLDL2E","fldl2e","D9 EA","V","V","","","","","" +"FLDL2T","FLDL2T","fldl2t","D9 E9","V","V","","","","","" +"FLDLG2","FLDLG2","fldlg2","D9 EC","V","V","","","","","" +"FLDLN2","FLDLN2","fldln2","D9 ED","V","V","","","","","" +"FLDPI","FLDPI","fldpi","D9 EB","V","V","","","","","" +"FLD ST(0), m32fp","FLDS m32fp, ST(0)","flds m32fp, ST(0)","D9 /0","V","V","","","w,r","Y","32" +"FLD ST(0), m80fp","FLDT m80fp, ST(0)","fldt m80fp, ST(0)","DB /5","V","V","","","w,r","Y","80" +"FLDZ","FLDZ","fldz","D9 EE","V","V","","","","","" +"FMUL ST(i), ST(0)","FMUL ST(0), ST(i)","fmul ST(0), ST(i)","DC C8+i","V","V","","","rw,r","Y","" +"FMUL ST(0), ST(i)","FMUL ST(i), ST(0)","fmul ST(i), ST(0)","D8 C8+i","V","V","","","rw,r","Y","" +"FMUL ST(0), m64fp","FMULL m64fp, ST(0)","fmull m64fp, ST(0)","DC /1","V","V","","","rw,r","Y","64" +"FMULP","FMULP","fmulp","DE C9","V","V","","pseudo","","","" +"FMULP ST(i), ST(0)","FMULP ST(0), ST(i)","fmulp ST(0), ST(i)","DE C8+i","V","V","","","rw,r","","" +"FMUL ST(0), m32fp","FMULS m32fp, ST(0)","fmuls m32fp, ST(0)","D8 /1","V","V","","","rw,r","Y","32" +"FNCLEX","FNCLEX","fnclex","DB E2","V","V","","","","","" +"FNINIT","FNINIT","fninit","DB E3","V","V","","","","","" +"FNOP","FNOP","fnop","D9 D0","V","V","","","","","" +"FNSAVE m108byte","FNSAVE m108byte","fnsave m108byte","DD /6","V","V","","operand32,operand64","w","","" +"FNSAVE m94byte","FNSAVES m94byte","fnsave m94byte","DD /6","V","V","","operand16","w","","" +"FNSTCW m2byte","FNSTCW m2byte","fnstcw m2byte","D9 /7","V","V","","","w","","" +"FNSTENV m28byte","FNSTENV m28byte","fnstenv m28byte","D9 /6","V","V","","operand32,operand64","w","","" +"FNSTENV m14byte","FNSTENVS m14byte","fnstenv m14byte","D9 /6","V","V","","operand16","w","","" +"FNSTSW AX","FNSTSW AX","fnstsw AX","DF E0","V","V","","","w","","" +"FNSTSW m2byte","FNSTSW m2byte","fnstsw m2byte","DD /7","V","V","","","w","","" +"FPATAN","FPATAN","fpatan","D9 F3","V","V","","","","","" +"FPREM","FPREM","fprem","D9 F8","V","V","","","","","" +"FPREM1","FPREM1","fprem1","D9 F5","V","V","","","","","" +"FPTAN","FPTAN","fptan","D9 F2","V","V","","","","","" +"FRNDINT","FRNDINT","frndint","D9 FC","V","V","","","","","" +"FRSTOR m108byte","FRSTOR m108byte","frstor m108byte","DD /4","V","V","","operand32,operand64","r","","" +"FRSTOR m94byte","FRSTORS m94byte","frstor m94byte","DD /4","V","V","","operand16","r","","" +"FSAVE m94/108byte","FSAVE m94/108byte","fsave m94/108byte","9B DD /6","V","V","","pseudo","w","","" +"FSCALE","FSCALE","fscale","D9 FD","V","V","","","","","" +"FSETPM287_NOP","FSETPM287_NOP","fsetpm287_nop","DB E4","V","V","","","","","" +"FSIN","FSIN","fsin","D9 FE","V","V","","","","","" +"FSINCOS","FSINCOS","fsincos","D9 FB","V","V","","","","","" +"FSQRT","FSQRT","fsqrt","D9 FA","V","V","","","","","" +"FST ST(i), ST(0)","FST ST(0), ST(i)","fst ST(0), ST(i)","DD D0+i","V","V","","","w,r","Y","" +"FSTCW m2byte","FSTCW m2byte","fstcw m2byte","9B D9 /7","V","V","","pseudo","w","","" +"FSTENV m14/28byte","FSTENV m14/28byte","fstenv m14/28byte","9B D9 /6","V","V","","pseudo","w","","" +"FST m64fp, ST(0)","FSTL ST(0), m64fp","fstl ST(0), m64fp","DD /2","V","V","","","w,r","Y","64" +"FSTP ST(i), ST(0)","FSTP ST(0), ST(i)","fstp ST(0), ST(i)","DD D8+i","V","V","","","w,r","Y","" +"FSTP ST(i), ST(0)","FSTP ST(0), ST(i)","fstp ST(0), ST(i)","DF D0+i","V","V","","","w,r","Y","" +"FSTP ST(i), ST(0)","FSTP ST(0), ST(i)","fstp ST(0), ST(i)","DF D8+i","V","V","","","w,r","Y","" +"FSTP m64fp, ST(0)","FSTPL ST(0), m64fp","fstpl ST(0), m64fp","DD /3","V","V","","","w,r","Y","64" +"FSTPNCE ST(i), ST(0)","FSTPNCE ST(0), ST(i)","fstpnce ST(0), ST(i)","D9 D8+i","V","V","","","w,r","","" +"FSTP m32fp, ST(0)","FSTPS ST(0), m32fp","fstps ST(0), m32fp","D9 /3","V","V","","","w,r","Y","32" +"FSTP m80fp, ST(0)","FSTPT ST(0), m80fp","fstpt ST(0), m80fp","DB /7","V","V","","","w,r","Y","80" +"FST m32fp, ST(0)","FSTS ST(0), m32fp","fsts ST(0), m32fp","D9 /2","V","V","","","w,r","Y","32" +"FSTSW AX","FSTSW AX","fstsw AX","9B DF E0","V","V","","pseudo","w","","" +"FSTSW m2byte","FSTSW m2byte","fstsw m2byte","9B DD /7","V","V","","pseudo","w","","" +"FSUBR ST(i), ST(0)","FSUB ST(0), ST(i)","fsub ST(0), ST(i)","DC E0+i","V","V","","","rw,r","Y","" +"FSUB ST(0), ST(i)","FSUB ST(i), ST(0)","fsub ST(i), ST(0)","D8 E0+i","V","V","","","rw,r","Y","" +"FSUB ST(0), m64fp","FSUBL m64fp, ST(0)","fsubl m64fp, ST(0)","DC /4","V","V","","","rw,r","Y","64" +"FSUBP","FSUBP","fsubp","DE E9","V","V","","pseudo","","","" +"FSUBRP ST(i), ST(0)","FSUBP ST(0), ST(i)","fsubp ST(0), ST(i)","DE E0+i","V","V","","","rw,r","","" +"FSUB ST(i), ST(0)","FSUBR ST(0), ST(i)","fsubr ST(0), ST(i)","DC E8+i","V","V","","","rw,r","Y","" +"FSUBR ST(0), ST(i)","FSUBR ST(i), ST(0)","fsubr ST(i), ST(0)","D8 E8+i","V","V","","","rw,r","Y","" +"FSUBR ST(0), m64fp","FSUBRL m64fp, ST(0)","fsubrl m64fp, ST(0)","DC /5","V","V","","","rw,r","Y","64" +"FSUBRP","FSUBRP","fsubrp","DE E1","V","V","","pseudo","","","" +"FSUBP ST(i), ST(0)","FSUBRP ST(0), ST(i)","fsubrp ST(0), ST(i)","DE E8+i","V","V","","","rw,r","","" +"FSUBR ST(0), m32fp","FSUBRS m32fp, ST(0)","fsubrs m32fp, ST(0)","D8 /5","V","V","","","rw,r","Y","32" +"FSUB ST(0), m32fp","FSUBS m32fp, ST(0)","fsubs m32fp, ST(0)","D8 /4","V","V","","","rw,r","Y","32" +"FTST","FTST","ftst","D9 E4","V","V","","","","","" +"FUCOM","FUCOM","fucom","DD E1","V","V","","pseudo","","","" +"FUCOM ST(0), ST(i)","FUCOM ST(i), ST(0)","fucom ST(i), ST(0)","DD E0+i","V","V","","","r,r","","" +"FUCOMI ST(0), ST(i)","FUCOMI ST(i), ST(0)","fucomi ST(i), ST(0)","DB E8+i","V","V","PPRO","P6","r,r","","" +"FUCOMIP ST(0), ST(i)","FUCOMIP ST(i), ST(0)","fucomip ST(i), ST(0)","DF E8+i","V","V","PPRO","P6","r,r","","" +"FUCOMP","FUCOMP","fucomp","DD E9","V","V","","pseudo","","","" +"FUCOMP ST(0), ST(i)","FUCOMP ST(i), ST(0)","fucomp ST(i), ST(0)","DD E8+i","V","V","","","r,r","","" +"FUCOMPP","FUCOMPP","fucompp","DA E9","V","V","","","","","" +"FWAIT","FWAIT","fwait","9B","V","V","","","","","" +"FXAM","FXAM","fxam","D9 E5","V","V","","","","","" +"FXCH","FXCH","fxch","D9 C9","V","V","","pseudo","","","" +"FXCH ST(0), ST(i)","FXCH ST(i), ST(0)","fxch ST(i), ST(0)","D9 C8+i","V","V","","","rw,rw","","" +"FXCH_ALIAS1 ST(0), ST(i)","FXCH_ALIAS1 ST(i), ST(0)","fxch_alias1 ST(i), ST(0)","DD C8+i","V","V","","","rw,rw","","" +"FXCH_ALIAS2 ST(0), ST(i)","FXCH_ALIAS2 ST(i), ST(0)","fxch_alias2 ST(i), ST(0)","DF C8+i","V","V","","","rw,rw","","" +"FXRSTOR m512byte","FXRSTOR m512byte","fxrstor m512byte","0F AE /1","V","V","","modrm_memonly,operand16,operand32","r","","" +"FXRSTOR64 m512byte","FXRSTOR64 m512byte","fxrstor64 m512byte","REX.W 0F AE /1","N.S.","V","","modrm_memonly","r","","" +"FXSAVE m512byte","FXSAVE m512byte","fxsave m512byte","0F AE /0","V","V","","modrm_memonly,operand16,operand32","w","","" +"FXSAVE64 m512byte","FXSAVE64 m512byte","fxsave64 m512byte","REX.W 0F AE /0","N.S.","V","","modrm_memonly","w","","" +"FXTRACT","FXTRACT","fxtract","D9 F4","V","V","","","","","" +"FYL2X","FYL2X","fyl2x","D9 F1","V","V","","","","","" +"FYL2XP1","FYL2XP1","fyl2xp1","D9 F9","V","V","","","","","" +"GETSEC","GETSEC","getsec","0F 37","V","V","SMX","","","","" +"GF2P8AFFINEINVQB xmm1, xmm2/m128, imm8u","GF2P8AFFINEINVQB imm8u, xmm2/m128, xmm1","gf2p8affineinvqb imm8u, xmm2/m128, xmm1","66 0F 3A CF /r ib","V","V","GFNI","","rw,r,r","","" +"GF2P8AFFINEQB xmm1, xmm2/m128, imm8u","GF2P8AFFINEQB imm8u, xmm2/m128, xmm1","gf2p8affineqb imm8u, xmm2/m128, xmm1","66 0F 3A CE /r ib","V","V","GFNI","","rw,r,r","","" +"GF2P8MULB xmm1, xmm2/m128","GF2P8MULB xmm2/m128, xmm1","gf2p8mulb xmm2/m128, xmm1","66 0F 38 CF /r","V","V","GFNI","","rw,r","","" +"HADDPD xmm1, xmm2/m128","HADDPD xmm2/m128, xmm1","haddpd xmm2/m128, xmm1","66 0F 7C /r","V","V","SSE3","","rw,r","","" +"HADDPS xmm1, xmm2/m128","HADDPS xmm2/m128, xmm1","haddps xmm2/m128, xmm1","F2 0F 7C /r","V","V","SSE3","","rw,r","","" +"HLT","HLT","hlt","F4","V","V","","","","","" +"HSUBPD xmm1, xmm2/m128","HSUBPD xmm2/m128, xmm1","hsubpd xmm2/m128, xmm1","66 0F 7D /r","V","V","SSE3","","rw,r","","" +"HSUBPS xmm1, xmm2/m128","HSUBPS xmm2/m128, xmm1","hsubps xmm2/m128, xmm1","F2 0F 7D /r","V","V","SSE3","","rw,r","","" +"ICEBP","ICEBP","icebp","F1","V","V","","","","","" +"IDIV r/m8","IDIVB r/m8","idivb r/m8","F6 /7","V","V","","","r","Y","8" +"IDIV r/m8","IDIVB r/m8","idivb r/m8","REX F6 /7","N.E.","V","","pseudo64","r","Y","8" +"IDIV r/m32","IDIVL r/m32","idivl r/m32","F7 /7","V","V","","operand32","r","Y","32" +"IDIV r/m64","IDIVQ r/m64","idivq r/m64","REX.W F7 /7","N.S.","V","","","r","Y","64" +"IDIV r/m16","IDIVW r/m16","idivw r/m16","F7 /7","V","V","","operand16","r","Y","16" +"IMUL r32, r/m32, imm32","IMUL3 imm32, r/m32, r32","imull imm32, r/m32, r32","69 /r id","V","V","","operand32","w,r,r","Y","32" +"IMUL r64, r/m64, imm32","IMUL3 imm32, r/m64, r64","imulq imm32, r/m64, r64","REX.W 69 /r id","N.S.","V","","","w,r,r","Y","64" +"IMUL r16, r/m16, imm8","IMUL3 imm8, r/m16, r16","imulw imm8, r/m16, r16","6B /r ib","V","V","","operand16","w,r,r","Y","16" +"IMUL r32, r/m32, imm8","IMUL3 imm8, r/m32, r32","imull imm8, r/m32, r32","6B /r ib","V","V","","operand32","w,r,r","Y","32" +"IMUL r64, r/m64, imm8","IMUL3 imm8, r/m64, r64","imulq imm8, r/m64, r64","REX.W 6B /r ib","N.S.","V","","","w,r,r","Y","64" +"IMUL r/m8","IMULB r/m8","imulb r/m8","F6 /5","V","V","","","r","Y","8" +"IMUL r/m32","IMULL r/m32","imull r/m32","F7 /5","V","V","","operand32","r","Y","32" +"IMUL r32, r/m32","IMULL r/m32, r32","imull r/m32, r32","0F AF /r","V","V","","operand32","rw,r","Y","32" +"IMUL r/m64","IMULQ r/m64","imulq r/m64","REX.W F7 /5","N.S.","V","","","r","Y","64" +"IMUL r64, r/m64","IMULQ r/m64, r64","imulq r/m64, r64","REX.W 0F AF /r","N.S.","V","","","rw,r","Y","64" +"IMUL r16, r/m16, imm16","IMULW imm16, r/m16, r16","imulw imm16, r/m16, r16","69 /r iw","V","V","","operand16","w,r,r","Y","16" +"IMUL r/m16","IMULW r/m16","imulw r/m16","F7 /5","V","V","","operand16","r","Y","16" +"IMUL r16, r/m16","IMULW r/m16, r16","imulw r/m16, r16","0F AF /r","V","V","","operand16","rw,r","Y","16" +"IN AL, DX","INB DX, AL","inb DX, AL","EC","V","V","","","w,r","Y","8" +"IN AL, imm8u","INB imm8u, AL","inb imm8u, AL","E4 ib","V","V","","","w,r","Y","8" +"INC r/m8","INCB r/m8","incb r/m8","FE /0","V","V","","","rw","Y","8" +"INC r/m8","INCB r/m8","incb r/m8","REX FE /0","N.E.","V","","pseudo64","rw","Y","8" +"INC r/m32","INCL r/m32","incl r/m32","FF /0","V","V","","operand32","rw","Y","32" +"INC r32op","INCL r32op","incl r32op","40+rd","V","N.S.","","operand32","rw","Y","32" +"INC r/m64","INCQ r/m64","incq r/m64","REX.W FF /0","N.S.","V","","","rw","Y","64" +"INCSSPD rmr32","INCSSPD rmr32","incsspd rmr32","F3 0F AE /5","V","V","CET","modrm_regonly,operand16,operand32","r","","" +"INCSSPQ rmr64","INCSSPQ rmr64","incsspq rmr64","F3 REX.W 0F AE /5","N.S.","V","CET","modrm_regonly","r","","" +"INC r/m16","INCW r/m16","incw r/m16","FF /0","V","V","","operand16","rw","Y","16" +"INC r16op","INCW r16op","incw r16op","40+rw","V","N.S.","","operand16","rw","Y","16" +"IN EAX, DX","INL DX, EAX","inl DX, EAX","ED","V","V","","operand32,operand64","w,r","Y","32" +"IN EAX, imm8u","INL imm8u, EAX","inl imm8u, EAX","E5 ib","V","V","","operand32,operand64","w,r","Y","32" +"INSB","INSB","insb","6C","V","V","","","","","" +"INSERTPS xmm1, xmm2/m32, imm8u","INSERTPS imm8u, xmm2/m32, xmm1","insertps imm8u, xmm2/m32, xmm1","66 0F 3A 21 /r ib","V","V","SSE4_1","","rw,r,r","","" +"INSERTQ xmm1, xmm2, imm8u, imm8u","INSERTQ imm8u, imm8u, xmm2, xmm1","insertq imm8u, imm8u, xmm2, xmm1","F2 0F 78 /r ib ib","V","V","SSE4a","amd,modrm_regonly","w,r,r,r","","" +"INSERTQ xmm1, xmm2","INSERTQ xmm2, xmm1","insertq xmm2, xmm1","F2 0F 79 /r","V","V","SSE4a","amd,modrm_regonly","w,r","","" +"INSD","INSL","insl","6D","V","V","","operand32,operand64","","","" +"INSW","INSW","insw","6D","V","V","","operand16","","","" +"INT 3","INT 3","int 3","CC","V","V","","","r","","" +"INT imm8u","INT imm8u","int imm8u","CD ib","V","V","","","r","","" +"INTO","INTO","into","CE","V","N.S.","","","","","" +"INVD","INVD","invd","0F 08","V","V","486","","","","" +"INVEPT r32, m128","INVEPT m128, r32","invept m128, r32","66 0F 38 80 /r","V","N.S.","VTX","modrm_memonly","r,r","","" +"INVEPT r64, m128","INVEPT m128, r64","invept m128, r64","66 0F 38 80 /r","N.S.","V","VTX","default64,modrm_memonly","r,r","","" +"INVLPG m","INVLPG m","invlpg m","0F 01 /7","V","V","486","modrm_memonly","r","","" +"INVLPGA EAX, ECX","INVLPGAL ECX, EAX","invlpgal ECX, EAX","0F 01 DF","V","V","SVM","amd,modrm_regonly,operand32","r,r","Y","32" +"INVLPGA RAX, ECX","INVLPGAQ ECX, RAX","invlpgaq ECX, RAX","REX.W 0F 01 DF","N.S.","V","SVM","amd,modrm_regonly","r,r","Y","64" +"INVLPGA AX, ECX","INVLPGAW ECX, AX","invlpgaw ECX, AX","0F 01 DF","V","V","SVM","amd,modrm_regonly,operand16","r,r","Y","16" +"INVPCID r32, m128","INVPCID m128, r32","invpcid m128, r32","66 0F 38 82 /r","V","N.S.","INVPCID","modrm_memonly","r,r","","" +"INVPCID r64, m128","INVPCID m128, r64","invpcid m128, r64","66 0F 38 82 /r","N.S.","V","INVPCID","default64,modrm_memonly","r,r","","" +"INVVPID r32, m128","INVVPID m128, r32","invvpid m128, r32","66 0F 38 81 /r","V","N.S.","VTX","modrm_memonly","r,r","","" +"INVVPID r64, m128","INVVPID m128, r64","invvpid m128, r64","66 0F 38 81 /r","N.S.","V","VTX","default64,modrm_memonly","r,r","","" +"IN AX, DX","INW DX, AX","inw DX, AX","ED","V","V","","operand16","w,r","Y","16" +"IN AX, imm8u","INW imm8u, AX","inw imm8u, AX","E5 ib","V","V","","operand16","w,r","Y","16" +"IRETD","IRETL","iretl","CF","V","V","","operand32","","","" +"IRETQ","IRETQ","iretq","REX.W CF","N.S.","V","","","","","" +"IRET","IRETW","iretw","CF","V","V","","operand16","","","" +"JA rel16","JA rel16","ja rel16","0F 87 cw","V","N.S.","","operand16","r","","" +"JA rel32","JA rel32","ja rel32","0F 87 cd","V","N.S.","","operand32","r","","" +"JA rel32","JA rel32","ja rel32","0F 87 cd","N.S.","V","","default64","r","","" +"JA rel8","JA rel8","ja rel8","77 cb","N.S.","V","","default64","r","","" +"JA rel8","JA rel8","ja rel8","77 cb","V","N.S.","","","r","","" +"JAE rel16","JAE rel16","jae rel16","0F 83 cw","V","N.S.","","operand16","r","","" +"JAE rel32","JAE rel32","jae rel32","0F 83 cd","N.S.","V","","default64","r","","" +"JAE rel32","JAE rel32","jae rel32","0F 83 cd","V","N.S.","","operand32","r","","" +"JAE rel8","JAE rel8","jae rel8","73 cb","V","N.S.","","","r","","" +"JAE rel8","JAE rel8","jae rel8","73 cb","N.S.","V","","default64","r","","" +"JB rel16","JB rel16","jb rel16","0F 82 cw","V","N.S.","","operand16","r","","" +"JB rel32","JB rel32","jb rel32","0F 82 cd","V","N.S.","","operand32","r","","" +"JB rel32","JB rel32","jb rel32","0F 82 cd","N.S.","V","","default64","r","","" +"JB rel8","JB rel8","jb rel8","72 cb","N.S.","V","","default64","r","","" +"JB rel8","JB rel8","jb rel8","72 cb","V","N.S.","","","r","","" +"JBE rel16","JBE rel16","jbe rel16","0F 86 cw","V","N.S.","","operand16","r","","" +"JBE rel32","JBE rel32","jbe rel32","0F 86 cd","V","N.S.","","operand32","r","","" +"JBE rel32","JBE rel32","jbe rel32","0F 86 cd","N.S.","V","","default64","r","","" +"JBE rel8","JBE rel8","jbe rel8","76 cb","V","N.S.","","","r","","" +"JBE rel8","JBE rel8","jbe rel8","76 cb","N.S.","V","","default64","r","","" +"JC rel16","JC rel16","jc rel16","0F 82 cw","V","N.S.","","pseudo","r","","" +"JC rel32","JC rel32","jc rel32","0F 82 cd","V","V","","pseudo","r","","" +"JC rel8","JC rel8","jc rel8","72 cb","V","V","","pseudo","r","","" +"JCXZ rel8","JCXZ rel8","jcxz rel8","E3 cb","V","N.S.","","address16","r","","" +"JE rel16","JE rel16","je rel16","0F 84 cw","V","N.S.","","operand16","r","","" +"JE rel32","JE rel32","je rel32","0F 84 cd","V","N.S.","","operand32","r","","" +"JE rel32","JE rel32","je rel32","0F 84 cd","N.S.","V","","default64","r","","" +"JE rel8","JE rel8","je rel8","74 cb","N.S.","V","","default64","r","","" +"JE rel8","JE rel8","je rel8","74 cb","V","N.S.","","","r","","" +"JECXZ rel8","JECXZ rel8","jecxz rel8","E3 cb","V","V","","address32","r","","" +"JG rel16","JG rel16","jg rel16","0F 8F cw","V","N.S.","","operand16","r","","" +"JG rel32","JG rel32","jg rel32","0F 8F cd","N.S.","V","","default64","r","","" +"JG rel32","JG rel32","jg rel32","0F 8F cd","V","N.S.","","operand32","r","","" +"JG rel8","JG rel8","jg rel8","7F cb","V","N.S.","","","r","","" +"JG rel8","JG rel8","jg rel8","7F cb","N.S.","V","","default64","r","","" +"JGE rel16","JGE rel16","jge rel16","0F 8D cw","V","N.S.","","operand16","r","","" +"JGE rel32","JGE rel32","jge rel32","0F 8D cd","V","N.S.","","operand32","r","","" +"JGE rel32","JGE rel32","jge rel32","0F 8D cd","N.S.","V","","default64","r","","" +"JGE rel8","JGE rel8","jge rel8","7D cb","N.S.","V","","default64","r","","" +"JGE rel8","JGE rel8","jge rel8","7D cb","V","N.S.","","","r","","" +"JL rel16","JL rel16","jl rel16","0F 8C cw","V","N.S.","","operand16","r","","" +"JL rel32","JL rel32","jl rel32","0F 8C cd","V","N.S.","","operand32","r","","" +"JL rel32","JL rel32","jl rel32","0F 8C cd","N.S.","V","","default64","r","","" +"JL rel8","JL rel8","jl rel8","7C cb","V","N.S.","","","r","","" +"JL rel8","JL rel8","jl rel8","7C cb","N.S.","V","","default64","r","","" +"JLE rel16","JLE rel16","jle rel16","0F 8E cw","V","N.S.","","operand16","r","","" +"JLE rel32","JLE rel32","jle rel32","0F 8E cd","V","N.S.","","operand32","r","","" +"JLE rel32","JLE rel32","jle rel32","0F 8E cd","N.S.","V","","default64","r","","" +"JLE rel8","JLE rel8","jle rel8","7E cb","N.S.","V","","default64","r","","" +"JLE rel8","JLE rel8","jle rel8","7E cb","V","N.S.","","","r","","" +"JMP rel16","JMP rel16","jmp rel16","E9 cw","V","N.S.","","operand16","r","Y","" +"JMP rel32","JMP rel32","jmp rel32","E9 cd","N.S.","V","","default64","r","Y","" +"JMP rel32","JMP rel32","jmp rel32","E9 cd","V","N.S.","","operand32","r","Y","" +"JMP rel8","JMP rel8","jmp rel8","EB cb","N.S.","V","","default64","r","Y","" +"JMP rel8","JMP rel8","jmp rel8","EB cb","V","N.S.","","","r","Y","" +"JMP r/m32","JMPL* r/m32","jmpl* r/m32","FF /4","V","N.S.","","operand32","r","Y","32" +"JMP r/m64","JMPQ* r/m64","jmpq* r/m64","FF /4","N.S.","V","","","r","Y","64" +"JMP r/m16","JMPW* r/m16","jmpw* r/m16","FF /4","V","N.S.","","operand16","r","Y","16" +"JNA rel16","JNA rel16","jna rel16","0F 86 cw","V","N.S.","","pseudo","r","","" +"JNA rel32","JNA rel32","jna rel32","0F 86 cd","V","V","","pseudo","r","","" +"JNA rel8","JNA rel8","jna rel8","76 cb","V","V","","pseudo","r","","" +"JNAE rel16","JNAE rel16","jnae rel16","0F 82 cw","V","N.S.","","pseudo","r","","" +"JNAE rel32","JNAE rel32","jnae rel32","0F 82 cd","V","V","","pseudo","r","","" +"JNAE rel8","JNAE rel8","jnae rel8","72 cb","V","V","","pseudo","r","","" +"JNB rel16","JNB rel16","jnb rel16","0F 83 cw","V","N.S.","","pseudo","r","","" +"JNB rel32","JNB rel32","jnb rel32","0F 83 cd","V","V","","pseudo","r","","" +"JNB rel8","JNB rel8","jnb rel8","73 cb","V","V","","pseudo","r","","" +"JNBE rel16","JNBE rel16","jnbe rel16","0F 87 cw","V","N.S.","","pseudo","r","","" +"JNBE rel32","JNBE rel32","jnbe rel32","0F 87 cd","V","V","","pseudo","r","","" +"JNBE rel8","JNBE rel8","jnbe rel8","77 cb","V","V","","pseudo","r","","" +"JNC rel16","JNC rel16","jnc rel16","0F 83 cw","V","N.S.","","pseudo","r","","" +"JNC rel32","JNC rel32","jnc rel32","0F 83 cd","V","V","","pseudo","r","","" +"JNC rel8","JNC rel8","jnc rel8","73 cb","V","V","","pseudo","r","","" +"JNE rel16","JNE rel16","jne rel16","0F 85 cw","V","N.S.","","operand16","r","","" +"JNE rel32","JNE rel32","jne rel32","0F 85 cd","N.S.","V","","default64","r","","" +"JNE rel32","JNE rel32","jne rel32","0F 85 cd","V","N.S.","","operand32","r","","" +"JNE rel8","JNE rel8","jne rel8","75 cb","V","N.S.","","","r","","" +"JNE rel8","JNE rel8","jne rel8","75 cb","N.S.","V","","default64","r","","" +"JNG rel16","JNG rel16","jng rel16","0F 8E cw","V","N.S.","","pseudo","r","","" +"JNG rel32","JNG rel32","jng rel32","0F 8E cd","V","V","","pseudo","r","","" +"JNG rel8","JNG rel8","jng rel8","7E cb","V","V","","pseudo","r","","" +"JNGE rel16","JNGE rel16","jnge rel16","0F 8C cw","V","N.S.","","pseudo","r","","" +"JNGE rel32","JNGE rel32","jnge rel32","0F 8C cd","V","V","","pseudo","r","","" +"JNGE rel8","JNGE rel8","jnge rel8","7C cb","V","V","","pseudo","r","","" +"JNL rel16","JNL rel16","jnl rel16","0F 8D cw","V","N.S.","","pseudo","r","","" +"JNL rel32","JNL rel32","jnl rel32","0F 8D cd","V","V","","pseudo","r","","" +"JNL rel8","JNL rel8","jnl rel8","7D cb","V","V","","pseudo","r","","" +"JNLE rel16","JNLE rel16","jnle rel16","0F 8F cw","V","N.S.","","pseudo","r","","" +"JNLE rel32","JNLE rel32","jnle rel32","0F 8F cd","V","V","","pseudo","r","","" +"JNLE rel8","JNLE rel8","jnle rel8","7F cb","V","V","","pseudo","r","","" +"JNO rel16","JNO rel16","jno rel16","0F 81 cw","V","N.S.","","operand16","r","","" +"JNO rel32","JNO rel32","jno rel32","0F 81 cd","V","N.S.","","operand32","r","","" +"JNO rel32","JNO rel32","jno rel32","0F 81 cd","N.S.","V","","default64","r","","" +"JNO rel8","JNO rel8","jno rel8","71 cb","V","N.S.","","","r","","" +"JNO rel8","JNO rel8","jno rel8","71 cb","N.S.","V","","default64","r","","" +"JNP rel16","JNP rel16","jnp rel16","0F 8B cw","V","N.S.","","operand16","r","","" +"JNP rel32","JNP rel32","jnp rel32","0F 8B cd","V","N.S.","","operand32","r","","" +"JNP rel32","JNP rel32","jnp rel32","0F 8B cd","N.S.","V","","default64","r","","" +"JNP rel8","JNP rel8","jnp rel8","7B cb","N.S.","V","","default64","r","","" +"JNP rel8","JNP rel8","jnp rel8","7B cb","V","N.S.","","","r","","" +"JNS rel16","JNS rel16","jns rel16","0F 89 cw","V","N.S.","","operand16","r","","" +"JNS rel32","JNS rel32","jns rel32","0F 89 cd","N.S.","V","","default64","r","","" +"JNS rel32","JNS rel32","jns rel32","0F 89 cd","V","N.S.","","operand32","r","","" +"JNS rel8","JNS rel8","jns rel8","79 cb","V","N.S.","","","r","","" +"JNS rel8","JNS rel8","jns rel8","79 cb","N.S.","V","","default64","r","","" +"JNZ rel16","JNZ rel16","jnz rel16","0F 85 cw","V","N.S.","","pseudo","r","","" +"JNZ rel32","JNZ rel32","jnz rel32","0F 85 cd","V","V","","pseudo","r","","" +"JNZ rel8","JNZ rel8","jnz rel8","75 cb","V","V","","pseudo","r","","" +"JO rel16","JO rel16","jo rel16","0F 80 cw","V","N.S.","","operand16","r","","" +"JO rel32","JO rel32","jo rel32","0F 80 cd","V","N.S.","","operand32","r","","" +"JO rel32","JO rel32","jo rel32","0F 80 cd","N.S.","V","","default64","r","","" +"JO rel8","JO rel8","jo rel8","70 cb","V","N.S.","","","r","","" +"JO rel8","JO rel8","jo rel8","70 cb","N.S.","V","","default64","r","","" +"JP rel16","JP rel16","jp rel16","0F 8A cw","V","N.S.","","operand16","r","","" +"JP rel32","JP rel32","jp rel32","0F 8A cd","N.S.","V","","default64","r","","" +"JP rel32","JP rel32","jp rel32","0F 8A cd","V","N.S.","","operand32","r","","" +"JP rel8","JP rel8","jp rel8","7A cb","N.S.","V","","default64","r","","" +"JP rel8","JP rel8","jp rel8","7A cb","V","N.S.","","","r","","" +"JPE rel16","JPE rel16","jpe rel16","0F 8A cw","V","N.S.","","pseudo","r","","" +"JPE rel32","JPE rel32","jpe rel32","0F 8A cd","V","V","","pseudo","r","","" +"JPE rel8","JPE rel8","jpe rel8","7A cb","V","V","","pseudo","r","","" +"JPO rel16","JPO rel16","jpo rel16","0F 8B cw","V","N.S.","","pseudo","r","","" +"JPO rel32","JPO rel32","jpo rel32","0F 8B cd","V","V","","pseudo","r","","" +"JPO rel8","JPO rel8","jpo rel8","7B cb","V","V","","pseudo","r","","" +"JRCXZ rel8","JRCXZ rel8","jrcxz rel8","E3 cb","N.S.","V","","address64","r","","" +"JS rel16","JS rel16","js rel16","0F 88 cw","V","N.S.","","operand16","r","","" +"JS rel32","JS rel32","js rel32","0F 88 cd","V","N.S.","","operand32","r","","" +"JS rel32","JS rel32","js rel32","0F 88 cd","N.S.","V","","default64","r","","" +"JS rel8","JS rel8","js rel8","78 cb","V","N.S.","","","r","","" +"JS rel8","JS rel8","js rel8","78 cb","N.S.","V","","default64","r","","" +"JZ rel16","JZ rel16","jz rel16","0F 84 cw","V","N.S.","","operand16,pseudo","r","","" +"JZ rel32","JZ rel32","jz rel32","0F 84 cd","V","V","","operand32,pseudo","r","","" +"JZ rel8","JZ rel8","jz rel8","74 cb","V","V","","pseudo","r","","" +"KADDB k1, kV, k2","KADDB k2, kV, k1","kaddb k2, kV, k1","VEX.NDS.256.66.0F.W0 4A /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KADDD k1, kV, k2","KADDD k2, kV, k1","kaddd k2, kV, k1","VEX.NDS.256.66.0F.W1 4A /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KADDQ k1, kV, k2","KADDQ k2, kV, k1","kaddq k2, kV, k1","VEX.NDS.256.0F.W1 4A /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KADDW k1, kV, k2","KADDW k2, kV, k1","kaddw k2, kV, k1","VEX.NDS.256.0F.W0 4A /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KANDB k1, kV, k2","KANDB k2, kV, k1","kandb k2, kV, k1","VEX.NDS.256.66.0F.W0 41 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KANDD k1, kV, k2","KANDD k2, kV, k1","kandd k2, kV, k1","VEX.NDS.256.66.0F.W1 41 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KANDNB k1, kV, k2","KANDNB k2, kV, k1","kandnb k2, kV, k1","VEX.NDS.256.66.0F.W0 42 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KANDND k1, kV, k2","KANDND k2, kV, k1","kandnd k2, kV, k1","VEX.NDS.256.66.0F.W1 42 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KANDNQ k1, kV, k2","KANDNQ k2, kV, k1","kandnq k2, kV, k1","VEX.NDS.256.0F.W1 42 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KANDNW k1, kV, k2","KANDNW k2, kV, k1","kandnw k2, kV, k1","VEX.NDS.256.0F.W0 42 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"KANDQ k1, kV, k2","KANDQ k2, kV, k1","kandq k2, kV, k1","VEX.NDS.256.0F.W1 41 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KANDW k1, kV, k2","KANDW k2, kV, k1","kandw k2, kV, k1","VEX.NDS.256.0F.W0 41 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"KMOVB m8, k1","KMOVB k1, m8","kmovb k1, m8","VEX.128.66.0F.W0 91 /r","V","V","AVX512DQ","modrm_memonly","w,r","","" +"KMOVB r32, k2","KMOVB k2, r32","kmovb k2, r32","VEX.128.66.0F.W0 93 /r","V","V","AVX512DQ","modrm_regonly","w,r","","" +"KMOVB k1, k2/m8","KMOVB k2/m8, k1","kmovb k2/m8, k1","VEX.128.66.0F.W0 90 /r","V","V","AVX512DQ","","w,r","","" +"KMOVB k1, rmr32","KMOVB rmr32, k1","kmovb rmr32, k1","VEX.128.66.0F.W0 92 /r","V","V","AVX512DQ","modrm_regonly","w,r","","" +"KMOVD m32, k1","KMOVD k1, m32","kmovd k1, m32","VEX.128.66.0F.W1 91 /r","V","V","AVX512BW","modrm_memonly","w,r","","" +"KMOVD r32, k2","KMOVD k2, r32","kmovd k2, r32","VEX.128.F2.0F.W0 93 /r","V","V","AVX512BW","modrm_regonly","w,r","","" +"KMOVD k1, k2/m32","KMOVD k2/m32, k1","kmovd k2/m32, k1","VEX.128.66.0F.W1 90 /r","V","V","AVX512BW","","w,r","","" +"KMOVD k1, rmr32","KMOVD rmr32, k1","kmovd rmr32, k1","VEX.128.F2.0F.W0 92 /r","V","V","AVX512BW","modrm_regonly","w,r","","" +"KMOVQ m64, k1","KMOVQ k1, m64","kmovq k1, m64","VEX.128.0F.W1 91 /r","V","V","AVX512BW","modrm_memonly","w,r","","" +"KMOVQ r64, k2","KMOVQ k2, r64","kmovq k2, r64","VEX.128.F2.0F.W1 93 /r","N.S.","V","AVX512BW","modrm_regonly","w,r","","" +"KMOVQ k1, k2/m64","KMOVQ k2/m64, k1","kmovq k2/m64, k1","VEX.128.0F.W1 90 /r","V","V","AVX512BW","","w,r","","" +"KMOVQ k1, rmr64","KMOVQ rmr64, k1","kmovq rmr64, k1","VEX.128.F2.0F.W1 92 /r","N.S.","V","AVX512BW","modrm_regonly","w,r","","" +"KMOVW m16, k1","KMOVW k1, m16","kmovw k1, m16","VEX.128.0F.W0 91 /r","V","V","AVX512F","modrm_memonly","w,r","","" +"KMOVW r32, k2","KMOVW k2, r32","kmovw k2, r32","VEX.128.0F.W0 93 /r","V","V","AVX512F","modrm_regonly","w,r","","" +"KMOVW k1, k2/m16","KMOVW k2/m16, k1","kmovw k2/m16, k1","VEX.128.0F.W0 90 /r","V","V","AVX512F","","w,r","","" +"KMOVW k1, rmr32","KMOVW rmr32, k1","kmovw rmr32, k1","VEX.128.0F.W0 92 /r","V","V","AVX512F","modrm_regonly","w,r","","" +"KNOTB k1, k2","KNOTB k2, k1","knotb k2, k1","VEX.128.66.0F.W0 44 /r","V","V","AVX512DQ","modrm_regonly","w,r","","" +"KNOTD k1, k2","KNOTD k2, k1","knotd k2, k1","VEX.128.66.0F.W1 44 /r","V","V","AVX512BW","modrm_regonly","w,r","","" +"KNOTQ k1, k2","KNOTQ k2, k1","knotq k2, k1","VEX.128.0F.W1 44 /r","V","V","AVX512BW","modrm_regonly","w,r","","" +"KNOTW k1, k2","KNOTW k2, k1","knotw k2, k1","VEX.128.0F.W0 44 /r","V","V","AVX512F","modrm_regonly","w,r","","" +"KORB k1, kV, k2","KORB k2, kV, k1","korb k2, kV, k1","VEX.NDS.256.66.0F.W0 45 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KORD k1, kV, k2","KORD k2, kV, k1","kord k2, kV, k1","VEX.NDS.256.66.0F.W1 45 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KORQ k1, kV, k2","KORQ k2, kV, k1","korq k2, kV, k1","VEX.NDS.256.0F.W1 45 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KORTESTB k1, k2","KORTESTB k2, k1","kortestb k2, k1","VEX.128.66.0F.W0 98 /r","V","V","AVX512DQ","modrm_regonly","r,r","","" +"KORTESTD k1, k2","KORTESTD k2, k1","kortestd k2, k1","VEX.128.66.0F.W1 98 /r","V","V","AVX512BW","modrm_regonly","r,r","","" +"KORTESTQ k1, k2","KORTESTQ k2, k1","kortestq k2, k1","VEX.128.0F.W1 98 /r","V","V","AVX512BW","modrm_regonly","r,r","","" +"KORTESTW k1, k2","KORTESTW k2, k1","kortestw k2, k1","VEX.128.0F.W0 98 /r","V","V","AVX512F","modrm_regonly","r,r","","" +"KORW k1, kV, k2","KORW k2, kV, k1","korw k2, kV, k1","VEX.NDS.256.0F.W0 45 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"KSHIFTLB k1, k2, imm8u","KSHIFTLB imm8u, k2, k1","kshiftlb imm8u, k2, k1","VEX.128.66.0F3A.W0 32 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KSHIFTLD k1, k2, imm8u","KSHIFTLD imm8u, k2, k1","kshiftld imm8u, k2, k1","VEX.128.66.0F3A.W0 33 /r ib","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KSHIFTLQ k1, k2, imm8u","KSHIFTLQ imm8u, k2, k1","kshiftlq imm8u, k2, k1","VEX.128.66.0F3A.W1 33 /r ib","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KSHIFTLW k1, k2, imm8u","KSHIFTLW imm8u, k2, k1","kshiftlw imm8u, k2, k1","VEX.128.66.0F3A.W1 32 /r ib","V","V","AVX512F","modrm_regonly","w,r,r","","" +"KSHIFTRB k1, k2, imm8u","KSHIFTRB imm8u, k2, k1","kshiftrb imm8u, k2, k1","VEX.128.66.0F3A.W0 30 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KSHIFTRD k1, k2, imm8u","KSHIFTRD imm8u, k2, k1","kshiftrd imm8u, k2, k1","VEX.128.66.0F3A.W0 31 /r ib","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KSHIFTRQ k1, k2, imm8u","KSHIFTRQ imm8u, k2, k1","kshiftrq imm8u, k2, k1","VEX.128.66.0F3A.W1 31 /r ib","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KSHIFTRW k1, k2, imm8u","KSHIFTRW imm8u, k2, k1","kshiftrw imm8u, k2, k1","VEX.128.66.0F3A.W1 30 /r ib","V","V","AVX512F","modrm_regonly","w,r,r","","" +"KTESTB k1, k2","KTESTB k2, k1","ktestb k2, k1","VEX.128.66.0F.W0 99 /r","V","V","AVX512DQ","modrm_regonly","r,r","","" +"KTESTD k1, k2","KTESTD k2, k1","ktestd k2, k1","VEX.128.66.0F.W1 99 /r","V","V","AVX512BW","modrm_regonly","r,r","","" +"KTESTQ k1, k2","KTESTQ k2, k1","ktestq k2, k1","VEX.128.0F.W1 99 /r","V","V","AVX512BW","modrm_regonly","r,r","","" +"KTESTW k1, k2","KTESTW k2, k1","ktestw k2, k1","VEX.128.0F.W0 99 /r","V","V","AVX512DQ","modrm_regonly","r,r","","" +"KUNPCKBW k1, kV, k2","KUNPCKBW k2, kV, k1","kunpckbw k2, kV, k1","VEX.NDS.256.66.0F.W0 4B /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"KUNPCKDQ k1, kV, k2","KUNPCKDQ k2, kV, k1","kunpckdq k2, kV, k1","VEX.NDS.256.0F.W1 4B /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KUNPCKWD k1, kV, k2","KUNPCKWD k2, kV, k1","kunpckwd k2, kV, k1","VEX.NDS.256.0F.W0 4B /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KXNORB k1, kV, k2","KXNORB k2, kV, k1","kxnorb k2, kV, k1","VEX.NDS.256.66.0F.W0 46 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KXNORD k1, kV, k2","KXNORD k2, kV, k1","kxnord k2, kV, k1","VEX.NDS.256.66.0F.W1 46 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KXNORQ k1, kV, k2","KXNORQ k2, kV, k1","kxnorq k2, kV, k1","VEX.NDS.256.0F.W1 46 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KXNORW k1, kV, k2","KXNORW k2, kV, k1","kxnorw k2, kV, k1","VEX.NDS.256.0F.W0 46 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"KXORB k1, kV, k2","KXORB k2, kV, k1","kxorb k2, kV, k1","VEX.NDS.256.66.0F.W0 47 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"KXORD k1, kV, k2","KXORD k2, kV, k1","kxord k2, kV, k1","VEX.NDS.256.66.0F.W1 47 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KXORQ k1, kV, k2","KXORQ k2, kV, k1","kxorq k2, kV, k1","VEX.NDS.256.0F.W1 47 /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"KXORW k1, kV, k2","KXORW k2, kV, k1","kxorw k2, kV, k1","VEX.NDS.256.0F.W0 47 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"LAHF","LAHF","lahf","9F","V","V","LAHFSAHF","","","","" +"LAR r32, r32/m16","LARL r32/m16, r32","larl r32/m16, r32","0F 02 /r","V","V","","operand32","rw,r","Y","32" +"LAR r64, r64/m16","LARQ r64/m16, r64","larq r64/m16, r64","REX.W 0F 02 /r","N.S.","V","","","rw,r","Y","64" +"LAR r16, r/m16","LARW r/m16, r16","larw r/m16, r16","0F 02 /r","V","V","","operand16","rw,r","Y","16" +"CALL_FAR ptr16:32","LCALLL ptr16:32","lcalll ptr16:32","9A cd iw","V","N.S.","","operand32","r","Y","" +"CALL_FAR m16:32","LCALLL* m16:32","lcalll* m16:32","FF /3","V","V","","modrm_memonly,operand32","r","Y","" +"CALL_FAR m16:64","LCALLQ* m16:64","lcallq* m16:64","REX.W FF /3","N.S.","V","","modrm_memonly","r","Y","" +"CALL_FAR ptr16:16","LCALLW ptr16:16","lcallw ptr16:16","9A cw iw","V","N.S.","","operand16","r","Y","" +"CALL_FAR m16:16","LCALLW* m16:16","lcallw* m16:16","FF /3","V","V","","modrm_memonly,operand16","r","Y","" +"LDDQU xmm1, m128","LDDQU m128, xmm1","lddqu m128, xmm1","F2 0F F0 /r","V","V","SSE3","modrm_memonly","w,r","","" +"LDMXCSR m32","LDMXCSR m32","ldmxcsr m32","0F AE /2","V","V","SSE","modrm_memonly","r","","" +"LDS r32, m16:32","LDSL m16:32, r32","ldsl m16:32, r32","C5 /r","V","N.S.","","modrm_memonly,operand32","w,r","Y","32" +"LDS r16, m16:16","LDSW m16:16, r16","ldsw m16:16, r16","C5 /r","V","N.S.","","modrm_memonly,operand16","w,r","Y","16" +"LEA r32, m","LEAL m, r32","leal m, r32","8D /r","V","V","","modrm_memonly,operand32","w,r","Y","32" +"LEA r64, m","LEAQ m, r64","leaq m, r64","REX.W 8D /r","N.S.","V","","modrm_memonly","w,r","Y","64" +"LEAVE","LEAVEW/LEAVEL/LEAVEQ","leavew/leavel/leaveq","C9","N.S.","V","","default64","","Y","" +"LEAVE","LEAVEW/LEAVEL/LEAVEQ","leavew/leavel/leaveq","C9","V","N.S.","","operand32","","Y","" +"LEAVE","LEAVEW/LEAVEL/LEAVEQ","leavew/leavel/leaveq","C9","V","V","","operand16","","Y","" +"LEA r16, m","LEAW m, r16","leaw m, r16","8D /r","V","V","","modrm_memonly,operand16","w,r","Y","16" +"LES r32, m16:32","LESL m16:32, r32","lesl m16:32, r32","C4 /r","V","N.S.","","modrm_memonly,operand32","w,r","Y","32" +"LES r16, m16:16","LESW m16:16, r16","lesw m16:16, r16","C4 /r","V","N.S.","","modrm_memonly,operand16","w,r","Y","16" +"LFENCE","LFENCE","lfence","0F AE /5","V","V","SSE2","","","","" +"LFS r32, m16:32","LFSL m16:32, r32","lfsl m16:32, r32","0F B4 /r","V","V","","modrm_memonly,operand32","w,r","Y","32" +"LFS r64, m16:64","LFSQ m16:64, r64","lfsq m16:64, r64","REX.W 0F B4 /r","N.S.","V","","modrm_memonly","w,r","Y","64" +"LFS r16, m16:16","LFSW m16:16, r16","lfsw m16:16, r16","0F B4 /r","V","V","","modrm_memonly,operand16","w,r","Y","16" +"LGDT m16&64","LGDT m16&64","lgdt m16&64","0F 01 /2","N.S.","V","","default64,modrm_memonly","r","","" +"LGDT m16&32","LGDTW/LGDTL m16&32","lgdtw/lgdtl m16&32","0F 01 /2","V","N.S.","","modrm_memonly","r","","" +"LGS r32, m16:32","LGSL m16:32, r32","lgsl m16:32, r32","0F B5 /r","V","V","","modrm_memonly,operand32","w,r","Y","32" +"LGS r64, m16:64","LGSQ m16:64, r64","lgsq m16:64, r64","REX.W 0F B5 /r","N.S.","V","","modrm_memonly","w,r","Y","64" +"LGS r16, m16:16","LGSW m16:16, r16","lgsw m16:16, r16","0F B5 /r","V","V","","modrm_memonly,operand16","w,r","Y","16" +"LIDT m16&64","LIDT m16&64","lidt m16&64","0F 01 /3","N.S.","V","","default64,modrm_memonly","r","","" +"LIDT m16&32","LIDTW/LIDTL m16&32","lidtw/lidtl m16&32","0F 01 /3","V","N.S.","","modrm_memonly","r","","" +"JMP_FAR ptr16:32","LJMPL ptr16:32","ljmpl ptr16:32","EA cd iw","V","N.S.","","operand32","r","Y","" +"JMP_FAR m16:32","LJMPL* m16:32","ljmpl* m16:32","FF /5","V","V","","modrm_memonly,operand32","r","Y","" +"JMP_FAR m16:64","LJMPQ* m16:64","ljmpq* m16:64","REX.W FF /5","N.S.","V","","modrm_memonly","r","Y","" +"JMP_FAR ptr16:16","LJMPW ptr16:16","ljmpw ptr16:16","EA cw iw","V","N.S.","","operand16","r","Y","" +"JMP_FAR m16:16","LJMPW* m16:16","ljmpw* m16:16","FF /5","V","V","","modrm_memonly,operand16","r","Y","" +"LLDT r/m16","LLDT r/m16","lldt r/m16","0F 00 /2","V","V","","","r","","" +"LLWPCB rmr32","LLWPCBL rmr32","llwpcbl rmr32","XOP.128.09.W0 12 /0","V","V","XOP","amd,modrm_regonly,operand16,operand32","w","Y","32" +"LLWPCB rmr64","LLWPCBQ rmr64","llwpcbq rmr64","XOP.128.09.W0 12 /0","N.S.","V","XOP","amd,modrm_regonly,operand64","w","Y","64" +"LMSW r/m16","LMSW r/m16","lmsw r/m16","0F 01 /6","V","V","","","r","","" +"LOCK","LOCK","lock","F0","V","V","","pseudo","","","" +"LODSB","LODSB","lodsb","AC","V","V","","","","","" +"LODSD","LODSL","lodsl","AD","V","V","","operand32","","","" +"LODSQ","LODSQ","lodsq","REX.W AD","N.S.","V","","","","","" +"LODSW","LODSW","lodsw","AD","V","V","","operand16","","","" +"LOOP rel8","LOOP rel8","loop rel8","E2 cb","V","V","","","r","","" +"LOOPE rel8","LOOPEQ rel8","loope rel8","E1 cb","V","V","","","r","","" +"LOOPNE rel8","LOOPNE rel8","loopne rel8","E0 cb","V","V","","","r","","" +"LSL r32, r32/m16","LSLL r32/m16, r32","lsll r32/m16, r32","0F 03 /r","V","V","","operand32","rw,r","Y","32" +"LSL r64, r32/m16","LSLQ r32/m16, r64","lslq r32/m16, r64","REX.W 0F 03 /r","N.S.","V","","","rw,r","Y","64" +"LSL r16, r/m16","LSLW r/m16, r16","lslw r/m16, r16","0F 03 /r","V","V","","operand16","rw,r","Y","16" +"LSS r32, m16:32","LSSL m16:32, r32","lssl m16:32, r32","0F B2 /r","V","V","","modrm_memonly,operand32","w,r","Y","32" +"LSS r64, m16:64","LSSQ m16:64, r64","lssq m16:64, r64","REX.W 0F B2 /r","N.S.","V","","modrm_memonly","w,r","Y","64" +"LSS r16, m16:16","LSSW m16:16, r16","lssw m16:16, r16","0F B2 /r","V","V","","modrm_memonly,operand16","w,r","Y","16" +"LTR r/m16","LTR r/m16","ltr r/m16","0F 00 /3","V","V","","","r","","" +"LWPINS r32V, r/m32, imm32u","LWPINS imm32u, r/m32, r32V","lwpins imm32u, r/m32, r32V","XOP.NDD.128.0A.W0 12 /0","V","V","XOP","amd,operand16,operand32","w,r,r","","" +"LWPINS r64V, r64/m32, imm32u","LWPINS imm32u, r64/m32, r64V","lwpins imm32u, r64/m32, r64V","XOP.NDD.128.0A.W0 12 /0","N.S.","V","XOP","amd,operand64","w,r,r","","" +"LWPVAL r32V, r/m32, imm32u","LWPVAL imm32u, r/m32, r32V","lwpval imm32u, r/m32, r32V","XOP.NDD.128.0A.W0 12 /1","V","V","XOP","amd,operand16,operand32","w,r,r","","" +"LWPVAL r64V, r64/m32, imm32u","LWPVAL imm32u, r64/m32, r64V","lwpval imm32u, r64/m32, r64V","XOP.NDD.128.0A.W0 12 /1","N.S.","V","XOP","amd,operand64","w,r,r","","" +"LZCNT r32, r/m32","LZCNTL r/m32, r32","lzcntl r/m32, r32","F3 0F BD /r","V","V","LZCNT","operand32","w,r","Y","32" +"LZCNT r32, r/m32","LZCNTL r/m32, r32","lzcntl r/m32, r32","F3 0F BD /r","V","V","AMD","amd,operand32","w,r","Y","32" +"LZCNT r64, r/m64","LZCNTQ r/m64, r64","lzcntq r/m64, r64","F3 REX.W 0F BD /r","N.S.","V","AMD","amd","w,r","Y","64" +"LZCNT r64, r/m64","LZCNTQ r/m64, r64","lzcntq r/m64, r64","F3 REX.W 0F BD /r","N.S.","V","LZCNT","","w,r","Y","64" +"LZCNT r16, r/m16","LZCNTW r/m16, r16","lzcntw r/m16, r16","F3 0F BD /r","V","V","AMD","amd,operand16","w,r","Y","16" +"LZCNT r16, r/m16","LZCNTW r/m16, r16","lzcntw r/m16, r16","F3 0F BD /r","V","V","LZCNT","operand16","w,r","Y","16" +"MASKMOVDQU xmm1, xmm2","MASKMOVOU xmm2, xmm1","maskmovdqu xmm2, xmm1","66 0F F7 /r","V","V","SSE2","modrm_regonly","r,r","","" +"MASKMOVQ mm1, mm2","MASKMOVQ mm2, mm1","maskmovq mm2, mm1","0F F7 /r","V","V","MMX","modrm_regonly","r,r","","" +"MAXPD xmm1, xmm2/m128","MAXPD xmm2/m128, xmm1","maxpd xmm2/m128, xmm1","66 0F 5F /r","V","V","SSE2","","rw,r","","" +"MAXPS xmm1, xmm2/m128","MAXPS xmm2/m128, xmm1","maxps xmm2/m128, xmm1","0F 5F /r","V","V","SSE","","rw,r","","" +"MAXSD xmm1, xmm2/m64","MAXSD xmm2/m64, xmm1","maxsd xmm2/m64, xmm1","F2 0F 5F /r","V","V","SSE2","","rw,r","","" +"MAXSS xmm1, xmm2/m32","MAXSS xmm2/m32, xmm1","maxss xmm2/m32, xmm1","F3 0F 5F /r","V","V","SSE","","rw,r","","" +"MFENCE","MFENCE","mfence","0F AE /6","V","V","SSE2","","","","" +"MINPD xmm1, xmm2/m128","MINPD xmm2/m128, xmm1","minpd xmm2/m128, xmm1","66 0F 5D /r","V","V","SSE2","","rw,r","","" +"MINPS xmm1, xmm2/m128","MINPS xmm2/m128, xmm1","minps xmm2/m128, xmm1","0F 5D /r","V","V","SSE","","rw,r","","" +"MINSD xmm1, xmm2/m64","MINSD xmm2/m64, xmm1","minsd xmm2/m64, xmm1","F2 0F 5D /r","V","V","SSE2","","rw,r","","" +"MINSS xmm1, xmm2/m32","MINSS xmm2/m32, xmm1","minss xmm2/m32, xmm1","F3 0F 5D /r","V","V","SSE","","rw,r","","" +"MONITOR","MONITOR","monitor","0F 01 C8","V","V","MONITOR","","","","" +"MOVAPD xmm2/m128, xmm1","MOVAPD xmm1, xmm2/m128","movapd xmm1, xmm2/m128","66 0F 29 /r","V","V","SSE2","","w,r","","" +"MOVAPD xmm1, xmm2/m128","MOVAPD xmm2/m128, xmm1","movapd xmm2/m128, xmm1","66 0F 28 /r","V","V","SSE2","","w,r","","" +"MOVAPS xmm2/m128, xmm1","MOVAPS xmm1, xmm2/m128","movaps xmm1, xmm2/m128","0F 29 /r","V","V","SSE","","w,r","","" +"MOVAPS xmm1, xmm2/m128","MOVAPS xmm2/m128, xmm1","movaps xmm2/m128, xmm1","0F 28 /r","V","V","SSE","","w,r","","" +"MOV r/m8, imm8u","MOVB imm8u, r/m8","movb imm8u, r/m8","C6 /0 ib","V","V","","","w,r","Y","8" +"MOV r/m8, imm8u","MOVB imm8u, r/m8","movb imm8u, r/m8","REX C6 /0 ib","N.E.","V","","pseudo64","w,r","Y","8" +"MOV r8op, imm8u","MOVB imm8u, r8op","movb imm8u, r8op","B0+rb ib","V","V","","","w,r","Y","8" +"MOV r8op, imm8u","MOVB imm8u, r8op","movb imm8u, r8op","REX B0+rb ib","N.E.","V","","pseudo64","w,r","Y","8" +"MOV r8, r/m8","MOVB r/m8, r8","movb r/m8, r8","8A /r","V","V","","","w,r","Y","8" +"MOV r8, r/m8","MOVB r/m8, r8","movb r/m8, r8","REX 8A /r","N.E.","V","","pseudo64","w,r","Y","8" +"MOV r/m8, r8","MOVB r8, r/m8","movb r8, r/m8","88 /r","V","V","","","w,r","Y","8" +"MOV r/m8, r8","MOVB r8, r/m8","movb r8, r/m8","REX 88 /r","N.E.","V","","pseudo64","w,r","Y","8" +"MOV moffs8, AL","MOVB/MOVB/MOVABSB AL, moffs8","movb/movb/movabsb AL, moffs8","A2 cm","V","V","","","w,r","Y","8" +"MOV moffs8, AL","MOVB/MOVB/MOVABSB AL, moffs8","movb/movb/movabsb AL, moffs8","REX.W A2 cm","N.E.","V","","pseudo","w,r","Y","8" +"MOV AL, moffs8","MOVB/MOVB/MOVABSB moffs8, AL","movb/movb/movabsb moffs8, AL","A0 cm","V","V","","","w,r","Y","8" +"MOV AL, moffs8","MOVB/MOVB/MOVABSB moffs8, AL","movb/movb/movabsb moffs8, AL","REX.W A0 cm","N.E.","V","","pseudo","w,r","Y","8" +"MOVBE r32, m32","MOVBELL m32, r32","movbell m32, r32","0F 38 F0 /r","V","V","MOVBE","modrm_memonly,operand32","w,r","Y","32" +"MOVBE m32, r32","MOVBELL r32, m32","movbell r32, m32","0F 38 F1 /r","V","V","MOVBE","modrm_memonly,operand32","w,r","Y","32" +"MOVBE r64, m64","MOVBEQQ m64, r64","movbeqq m64, r64","REX.W 0F 38 F0 /r","N.S.","V","MOVBE","modrm_memonly","w,r","Y","64" +"MOVBE m64, r64","MOVBEQQ r64, m64","movbeqq r64, m64","REX.W 0F 38 F1 /r","N.S.","V","MOVBE","modrm_memonly","w,r","Y","64" +"MOVBE r16, m16","MOVBEWW m16, r16","movbeww m16, r16","0F 38 F0 /r","V","V","MOVBE","modrm_memonly,operand16","w,r","Y","16" +"MOVBE m16, r16","MOVBEWW r16, m16","movbeww r16, m16","0F 38 F1 /r","V","V","MOVBE","modrm_memonly,operand16","w,r","Y","16" +"MOVSX r32, r/m8","MOVBLSX r/m8, r32","movsbl r/m8, r32","0F BE /r","V","V","","operand32","w,r","Y","32" +"MOVZX r32, r/m8","MOVBLZX r/m8, r32","movzbl r/m8, r32","0F B6 /r","V","V","","operand32","w,r","Y","32" +"MOVSX r64, r/m8","MOVBQSX r/m8, r64","movsbq r/m8, r64","REX.W 0F BE /r","N.S.","V","","","w,r","Y","64" +"MOVZX r64, r/m8","MOVBQZX r/m8, r64","movzbq r/m8, r64","REX.W 0F B6 /r","N.S.","V","","","w,r","Y","64" +"MOVSX r16, r/m8","MOVBWSX r/m8, r16","movsbw r/m8, r16","0F BE /r","V","V","","operand16","w,r","Y","16" +"MOVZX r16, r/m8","MOVBWZX r/m8, r16","movzbw r/m8, r16","0F B6 /r","V","V","","operand16","w,r","Y","16" +"MOVD r/m32, mm1","MOVD mm1, r/m32","movd mm1, r/m32","0F 7E /r","V","V","MMX","operand16,operand32","w,r","","" +"MOVD mm1, r/m32","MOVD r/m32, mm1","movd r/m32, mm1","0F 6E /r","V","V","MMX","operand16,operand32","w,r","","" +"MOVD xmm1, r/m32","MOVD r/m32, xmm1","movd r/m32, xmm1","66 0F 6E /r","V","V","SSE2","operand16,operand32","w,r","","" +"MOVD r/m32, xmm1","MOVD xmm1, r/m32","movd xmm1, r/m32","66 0F 7E /r","V","V","SSE2","operand16,operand32","w,r","","" +"MOVDDUP xmm1, xmm2/m64","MOVDDUP xmm2/m64, xmm1","movddup xmm2/m64, xmm1","F2 0F 12 /r","V","V","SSE3","","w,r","","" +"MOVHLPS xmm1, xmm2","MOVHLPS xmm2, xmm1","movhlps xmm2, xmm1","0F 12 /r","V","V","SSE","modrm_regonly","w,r","","" +"MOVHPD xmm1, m64","MOVHPD m64, xmm1","movhpd m64, xmm1","66 0F 16 /r","V","V","SSE2","modrm_memonly","w,r","","" +"MOVHPD m64, xmm1","MOVHPD xmm1, m64","movhpd xmm1, m64","66 0F 17 /r","V","V","SSE2","modrm_memonly","w,r","","" +"MOVHPS xmm1, m64","MOVHPS m64, xmm1","movhps m64, xmm1","0F 16 /r","V","V","SSE","modrm_memonly","w,r","","" +"MOVHPS m64, xmm1","MOVHPS xmm1, m64","movhps xmm1, m64","0F 17 /r","V","V","SSE","modrm_memonly","w,r","","" +"MOV rmr32, CR0-CR7","MOVL CR0-CR7, rmr32","movl CR0-CR7, rmr32","0F 20 /r","V","N.S.","","","w,r","Y","32" +"MOV rmr32, DR0-DR7","MOVL DR0-DR7, rmr32","movl DR0-DR7, rmr32","0F 21 /r","V","N.S.","","","w,r","Y","32" +"MOV moffs32, EAX","MOVL EAX, moffs32","movl EAX, moffs32","A3 cm","V","V","","operand32","w,r","Y","32" +"MOV r/m32, imm32","MOVL imm32, r/m32","movl imm32, r/m32","C7 /0 id","V","V","","operand32","w,r","Y","32" +"MOV r32op, imm32u","MOVL imm32u, r32op","movl imm32u, r32op","B8+rd id","V","V","","operand32","w,r","Y","32" +"MOV EAX, moffs32","MOVL moffs32, EAX","movl moffs32, EAX","A1 cm","V","V","","operand32","w,r","Y","32" +"MOV r32, r/m32","MOVL r/m32, r32","movl r/m32, r32","8B /r","V","V","","operand32","w,r","Y","32" +"MOV r/m32, r32","MOVL r32, r/m32","movl r32, r/m32","89 /r","V","V","","operand32","w,r","Y","32" +"MOV CR0-CR7, rmr32","MOVL rmr32, CR0-CR7","movl rmr32, CR0-CR7","0F 22 /r","V","N.S.","","","w,r","Y","32" +"MOV DR0-DR7, rmr32","MOVL rmr32, DR0-DR7","movl rmr32, DR0-DR7","0F 23 /r","V","N.S.","","","w,r","Y","32" +"MOVLHPS xmm1, xmm2","MOVLHPS xmm2, xmm1","movlhps xmm2, xmm1","0F 16 /r","V","V","SSE","modrm_regonly","w,r","","" +"MOVLPD xmm1, m64","MOVLPD m64, xmm1","movlpd m64, xmm1","66 0F 12 /r","V","V","SSE2","modrm_memonly","w,r","","" +"MOVLPD m64, xmm1","MOVLPD xmm1, m64","movlpd xmm1, m64","66 0F 13 /r","V","V","SSE2","modrm_memonly","w,r","","" +"MOVLPS xmm1, m64","MOVLPS m64, xmm1","movlps m64, xmm1","0F 12 /r","V","V","SSE","modrm_memonly","w,r","","" +"MOVLPS m64, xmm1","MOVLPS xmm1, m64","movlps xmm1, m64","0F 13 /r","V","V","SSE","modrm_memonly","w,r","","" +"MOVSXD r32, r/m32","MOVLQSX r/m32, r32","movsxdl r/m32, r32","63 /r","N.S.","V","","operand32","w,r","Y","32" +"MOVSXD r64, r/m32","MOVLQSX r/m32, r64","movslq r/m32, r64","REX.W 63 /r","N.S.","V","","","w,r","Y","64" +"MOVMSKPD r32, xmm2","MOVMSKPD xmm2, r32","movmskpd xmm2, r32","66 0F 50 /r","V","V","SSE2","modrm_regonly","w,r","","" +"MOVMSKPS r32, xmm2","MOVMSKPS xmm2, r32","movmskps xmm2, r32","0F 50 /r","V","V","SSE","modrm_regonly","w,r","","" +"MOVNTDQA xmm1, m128","MOVNTDQA m128, xmm1","movntdqa m128, xmm1","66 0F 38 2A /r","V","V","SSE4_1","modrm_memonly","w,r","","" +"MOVNTI m32, r32","MOVNTIL r32, m32","movntil r32, m32","0F C3 /r","V","V","SSE2","modrm_memonly,operand16,operand32","w,r","Y","32" +"MOVNTI m64, r64","MOVNTIQ r64, m64","movntiq r64, m64","REX.W 0F C3 /r","N.S.","V","SSE2","modrm_memonly","w,r","Y","64" +"MOVNTDQ m128, xmm1","MOVNTO xmm1, m128","movntdq xmm1, m128","66 0F E7 /r","V","V","SSE2","modrm_memonly","w,r","","" +"MOVNTPD m128, xmm1","MOVNTPD xmm1, m128","movntpd xmm1, m128","66 0F 2B /r","V","V","SSE2","modrm_memonly","w,r","","" +"MOVNTPS m128, xmm1","MOVNTPS xmm1, m128","movntps xmm1, m128","0F 2B /r","V","V","SSE","modrm_memonly","w,r","","" +"MOVNTQ m64, mm1","MOVNTQ mm1, m64","movntq mm1, m64","0F E7 /r","V","V","MMX","modrm_memonly","w,r","","" +"MOVNTSD m64, xmm1","MOVNTSD xmm1, m64","movntsd xmm1, m64","F2 0F 2B /r","V","V","SSE4a","amd,modrm_memonly","w,r","","" +"MOVNTSS m32, xmm1","MOVNTSS xmm1, m32","movntss xmm1, m32","F3 0F 2B /r","V","V","SSE4a","amd,modrm_memonly","w,r","","" +"MOVDQA xmm2/m128, xmm1","MOVO xmm1, xmm2/m128","movdqa xmm1, xmm2/m128","66 0F 7F /r","V","V","SSE2","","w,r","","" +"MOVDQA xmm1, xmm2/m128","MOVO xmm2/m128, xmm1","movdqa xmm2/m128, xmm1","66 0F 6F /r","V","V","SSE2","","w,r","","" +"MOVDQU xmm2/m128, xmm1","MOVOU xmm1, xmm2/m128","movdqu xmm1, xmm2/m128","F3 0F 7F /r","V","V","SSE2","","w,r","","" +"MOVDQU xmm1, xmm2/m128","MOVOU xmm2/m128, xmm1","movdqu xmm2/m128, xmm1","F3 0F 6F /r","V","V","SSE2","","w,r","","" +"MOV rmr64, CR0-CR7","MOVQ CR0-CR7, rmr64","movq CR0-CR7, rmr64","0F 20 /r","N.S.","V","","default64","w,r","Y","64" +"MOV rmr64, CR8","MOVQ CR8, rmr64","movq CR8, rmr64","REX.R + 0F 20 /0","N.E.","V","","modrm_regonly,pseudo","w,r","Y","64" +"MOV rmr64, DR0-DR7","MOVQ DR0-DR7, rmr64","movq DR0-DR7, rmr64","0F 21 /r","N.S.","V","","default64","w,r","Y","64" +"MOV moffs64, RAX","MOVQ RAX, moffs64","movabsq RAX, moffs64","REX.W A3 cm","N.S.","V","","","w,r","Y","64" +"MOV r/m64, imm32","MOVQ imm32, r/m64","movq imm32, r/m64","REX.W C7 /0 id","N.S.","V","","","w,r","Y","64" +"MOV r64op, imm64u","MOVQ imm64u, r64op","movq imm64u, r64op","REX.W B8+ro io","N.S.","V","","","w,r","Y","64" +"MOVQ mm2/m64, mm1","MOVQ mm1, mm2/m64","movq mm1, mm2/m64","0F 7F /r","V","V","MMX","","w,r","","" +"MOVQ r/m64, mm1","MOVQ mm1, r/m64","movq mm1, r/m64","REX.W 0F 7E /r","N.S.","V","MMX","","w,r","","" +"MOVQ mm1, mm2/m64","MOVQ mm2/m64, mm1","movq mm2/m64, mm1","0F 6F /r","V","V","MMX","","w,r","","" +"MOV RAX, moffs64","MOVQ moffs64, RAX","movabsq moffs64, RAX","REX.W A1 cm","N.S.","V","","","w,r","Y","64" +"MOVQ mm1, r/m64","MOVQ r/m64, mm1","movq r/m64, mm1","REX.W 0F 6E /r","N.S.","V","MMX","","w,r","","" +"MOV r64, r/m64","MOVQ r/m64, r64","movq r/m64, r64","REX.W 8B /r","N.S.","V","","","w,r","Y","64" +"MOVQ xmm1, r/m64","MOVQ r/m64, xmm1","movq r/m64, xmm1","66 REX.W 0F 6E /r","N.S.","V","SSE2","","w,r","","" +"MOV r/m64, r64","MOVQ r64, r/m64","movq r64, r/m64","REX.W 89 /r","N.S.","V","","","w,r","Y","64" +"MOV CR0-CR7, rmr64","MOVQ rmr64, CR0-CR7","movq rmr64, CR0-CR7","0F 22 /r","N.S.","V","","default64","w,r","Y","64" +"MOV CR8, rmr64","MOVQ rmr64, CR8","movq rmr64, CR8","REX.R + 0F 22 /0","N.E.","V","","modrm_regonly,pseudo","w,r","Y","64" +"MOV DR0-DR7, rmr64","MOVQ rmr64, DR0-DR7","movq rmr64, DR0-DR7","0F 23 /r","N.S.","V","","default64","w,r","Y","64" +"MOVQ r/m64, xmm1","MOVQ xmm1, r/m64","movq xmm1, r/m64","66 REX.W 0F 7E /r","N.S.","V","SSE2","","w,r","","" +"MOVQ xmm2/m64, xmm1","MOVQ xmm1, xmm2/m64","movq xmm1, xmm2/m64","66 0F D6 /r","V","V","SSE2","","w,r","","" +"MOVDQ2Q mm1, xmm2","MOVQ xmm2, mm1","movdq2q xmm2, mm1","F2 0F D6 /r","V","V","SSE2","modrm_regonly","w,r","","" +"MOVQ xmm1, xmm2/m64","MOVQ xmm2/m64, xmm1","movq xmm2/m64, xmm1","F3 0F 7E /r","V","V","SSE2","","w,r","","" +"MOVQ2DQ xmm1, mm2","MOVQOZX mm2, xmm1","movq2dq mm2, xmm1","F3 0F D6 /r","V","V","SSE2","modrm_regonly","w,r","","" +"MOVSB","MOVSB","movsb","A4","V","V","","","","","" +"MOVSD xmm2/m64, xmm1","MOVSD xmm1, xmm2/m64","movsd xmm1, xmm2/m64","F2 0F 11 /r","V","V","SSE2","","w,r","","" +"MOVSD xmm1, xmm2/m64","MOVSD xmm2/m64, xmm1","movsd xmm2/m64, xmm1","F2 0F 10 /r","V","V","SSE2","","w,r","","" +"MOVSHDUP xmm1, xmm2/m128","MOVSHDUP xmm2/m128, xmm1","movshdup xmm2/m128, xmm1","F3 0F 16 /r","V","V","SSE3","","w,r","","" +"MOVSD","MOVSL","movsl","A5","V","V","","operand32","","","" +"MOVSLDUP xmm1, xmm2/m128","MOVSLDUP xmm2/m128, xmm1","movsldup xmm2/m128, xmm1","F3 0F 12 /r","V","V","SSE3","","w,r","","" +"MOVSQ","MOVSQ","movsq","REX.W A5","N.S.","V","","","","","" +"MOVSS xmm2/m32, xmm1","MOVSS xmm1, xmm2/m32","movss xmm1, xmm2/m32","F3 0F 11 /r","V","V","SSE","","w,r","","" +"MOVSS xmm1, xmm2/m32","MOVSS xmm2/m32, xmm1","movss xmm2/m32, xmm1","F3 0F 10 /r","V","V","SSE","","w,r","","" +"MOVSW","MOVSW","movsw","A5","V","V","","operand16","","","" +"MOVSX r16, r/m16","MOVSWW r/m16, r16","movsww r/m16, r16","0F BF /r","V","V","","operand16","w,r","Y","16" +"MOVUPD xmm2/m128, xmm1","MOVUPD xmm1, xmm2/m128","movupd xmm1, xmm2/m128","66 0F 11 /r","V","V","SSE2","","w,r","","" +"MOVUPD xmm1, xmm2/m128","MOVUPD xmm2/m128, xmm1","movupd xmm2/m128, xmm1","66 0F 10 /r","V","V","SSE2","","w,r","","" +"MOVUPS xmm2/m128, xmm1","MOVUPS xmm1, xmm2/m128","movups xmm1, xmm2/m128","0F 11 /r","V","V","SSE","","w,r","","" +"MOVUPS xmm1, xmm2/m128","MOVUPS xmm2/m128, xmm1","movups xmm2/m128, xmm1","0F 10 /r","V","V","SSE","","w,r","","" +"MOV moffs16, AX","MOVW AX, moffs16","movw AX, moffs16","A3 cm","V","V","","operand16","w,r","Y","16" +"MOV r/m16, Sreg","MOVW Sreg, r/m16","movw Sreg, r/m16","8C /r","V","V","","operand16","w,r","Y","16" +"MOV r/m16, imm16","MOVW imm16, r/m16","movw imm16, r/m16","C7 /0 iw","V","V","","operand16","w,r","Y","16" +"MOV r16op, imm16u","MOVW imm16u, r16op","movw imm16u, r16op","B8+rw iw","V","V","","operand16","w,r","Y","16" +"MOV AX, moffs16","MOVW moffs16, AX","movw moffs16, AX","A1 cm","V","V","","operand16","w,r","Y","16" +"MOV Sreg, r/m16","MOVW r/m16, Sreg","movw r/m16, Sreg","8E /r","V","V","","","w,r","Y","16" +"MOV r16, r/m16","MOVW r/m16, r16","movw r/m16, r16","8B /r","V","V","","operand16","w,r","Y","16" +"MOV r/m16, r16","MOVW r16, r/m16","movw r16, r/m16","89 /r","V","V","","operand16","w,r","Y","16" +"MOVSX r32, r/m16","MOVWLSX r/m16, r32","movswl r/m16, r32","0F BF /r","V","V","","operand32","w,r","Y","32" +"MOVZX r32, r/m16","MOVWLZX r/m16, r32","movzwl r/m16, r32","0F B7 /r","V","V","","operand32","w,r","Y","32" +"MOVSX r64, r/m16","MOVWQSX r/m16, r64","movswq r/m16, r64","REX.W 0F BF /r","N.S.","V","","","w,r","Y","64" +"MOVSXD r16, r/m32","MOVWQSX r/m32, r16","movsxdw r/m32, r16","63 /r","N.S.","V","","operand16","w,r","Y","16" +"MOVZX r64, r/m16","MOVWQZX r/m16, r64","movzwq r/m16, r64","REX.W 0F B7 /r","N.S.","V","","","w,r","Y","64" +"MOVZX r16, r/m16","MOVZWW r/m16, r16","movzww r/m16, r16","0F B7 /r","V","V","","operand16","w,r","Y","16" +"MOV r32/m16, Sreg","MOV{L/W} Sreg, r32/m16","mov{l/w} Sreg, r32/m16","8C /r","V","V","","operand32","w,r","Y","" +"MOV r64/m16, Sreg","MOV{Q/W} Sreg, r64/m16","mov{q/w} Sreg, r64/m16","REX.W 8C /r","N.S.","V","","","w,r","Y","" +"MPSADBW xmm1, xmm2/m128, imm8u","MPSADBW imm8u, xmm2/m128, xmm1","mpsadbw imm8u, xmm2/m128, xmm1","66 0F 3A 42 /r ib","V","V","SSE4_1","","rw,r,r","","" +"MUL r/m8","MULB r/m8","mulb r/m8","F6 /4","V","V","","","r","Y","8" +"MUL r/m8","MULB r/m8","mulb r/m8","REX F6 /4","N.E.","V","","pseudo64","r","Y","8" +"MUL r/m32","MULL r/m32","mull r/m32","F7 /4","V","V","","operand32","r","Y","32" +"MULPD xmm1, xmm2/m128","MULPD xmm2/m128, xmm1","mulpd xmm2/m128, xmm1","66 0F 59 /r","V","V","SSE2","","rw,r","","" +"MULPS xmm1, xmm2/m128","MULPS xmm2/m128, xmm1","mulps xmm2/m128, xmm1","0F 59 /r","V","V","SSE","","rw,r","","" +"MUL r/m64","MULQ r/m64","mulq r/m64","REX.W F7 /4","N.S.","V","","","r","Y","64" +"MULSD xmm1, xmm2/m64","MULSD xmm2/m64, xmm1","mulsd xmm2/m64, xmm1","F2 0F 59 /r","V","V","SSE2","","rw,r","","" +"MULSS xmm1, xmm2/m32","MULSS xmm2/m32, xmm1","mulss xmm2/m32, xmm1","F3 0F 59 /r","V","V","SSE","","rw,r","","" +"MUL r/m16","MULW r/m16","mulw r/m16","F7 /4","V","V","","operand16","r","Y","16" +"MULX r32, r32V, r/m32","MULXL r/m32, r32V, r32","mulxl r/m32, r32V, r32","VEX.NDD.128.F2.0F38.W0 F6 /r","V","V","BMI2","","w,w,r","Y","32" +"MULX r64, r64V, r/m64","MULXQ r/m64, r64V, r64","mulxq r/m64, r64V, r64","VEX.NDD.128.F2.0F38.W1 F6 /r","N.S.","V","BMI2","","w,w,r","Y","64" +"MWAIT","MWAIT","mwait","0F 01 C9","V","V","MONITOR","","","","" +"NEG r/m8","NEGB r/m8","negb r/m8","F6 /3","V","V","","","rw","Y","8" +"NEG r/m8","NEGB r/m8","negb r/m8","REX F6 /3","N.E.","V","","pseudo64","rw","Y","8" +"NEG r/m32","NEGL r/m32","negl r/m32","F7 /3","V","V","","operand32","rw","Y","32" +"NEG r/m64","NEGQ r/m64","negq r/m64","REX.W F7 /3","N.S.","V","","","rw","Y","64" +"NEG r/m16","NEGW r/m16","negw r/m16","F7 /3","V","V","","operand16","rw","Y","16" +"NOP","NOP","nop","90","V","V","","pseudo","","Y","" +"NOP","NOP","nop","90+rd","V","V","","operand32,operand64","","Y","" +"NOP","NOP","nop","90+rw","V","V","","operand16,operand64","","Y","" +"NOP","NOP","nop","F3 90+rd","V","V","","operand32","","Y","" +"NOP","NOP","nop","F3 90+rw","V","V","","operand16","","Y","" +"NOP r/m32","NOPL r/m32","nopl r/m32","0F 18 /4","V","V","","operand32","r","Y","32" +"NOP r/m32","NOPL r/m32","nopl r/m32","0F 18 /5","V","V","","operand32","r","Y","32" +"NOP r/m32","NOPL r/m32","nopl r/m32","0F 18 /6","V","V","","operand32","r","Y","32" +"NOP r/m32","NOPL r/m32","nopl r/m32","0F 18 /7","V","V","","operand32","r","Y","32" +"NOP r/m32, r32","NOPL r32, r/m32","nopl r32, r/m32","0F 19 /r","V","V","","operand32","r,r","Y","32" +"NOP r/m32, r32","NOPL r32, r/m32","nopl r32, r/m32","0F 1A /r","V","V","","operand32","r,r","Y","32" +"NOP r/m32, r32","NOPL r32, r/m32","nopl r32, r/m32","0F 1B /r","V","V","","operand32","r,r","Y","32" +"NOP r/m32, r32","NOPL r32, r/m32","nopl r32, r/m32","0F 1C /r","V","V","","operand32","r,r","Y","32" +"NOP r/m32, r32","NOPL r32, r/m32","nopl r32, r/m32","0F 1D /r","V","V","","operand32","r,r","Y","32" +"NOP r/m32, r32","NOPL r32, r/m32","nopl r32, r/m32","0F 1E /r","V","V","PPRO","operand32","r,r","Y","32" +"NOP r/m32, r32","NOPL r32, r/m32","nopl r32, r/m32","0F 1E /r","V","V","","operand32","r,r","Y","32" +"NOP r/m32, r32","NOPL r32, r/m32","nopl r32, r/m32","0F 1F /r","V","V","","operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","0F 0D /r","V","V","PRFCHW","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","0F 1A /r","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","0F 1B /r","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","66 0F 1E /r","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F2 0F 1E /r","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1B /r","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E /0","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E /1","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E /2","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E /3","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E /4","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E /5","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E /6","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E F8","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E F9","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E FA","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E FB","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E FC","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E FD","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E FE","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32, r32","NOPL r32, rmr32","nopl r32, rmr32","F3 0F 1E FF","V","V","PPRO","modrm_regonly,operand32","r,r","Y","32" +"NOP rmr32","NOPL rmr32","nopl rmr32","0F 18 /0","V","V","","modrm_regonly,operand32","r","Y","32" +"NOP rmr32","NOPL rmr32","nopl rmr32","0F 18 /1","V","V","","modrm_regonly,operand32","r","Y","32" +"NOP rmr32","NOPL rmr32","nopl rmr32","0F 18 /2","V","V","","modrm_regonly,operand32","r","Y","32" +"NOP rmr32","NOPL rmr32","nopl rmr32","0F 18 /3","V","V","","modrm_regonly,operand32","r","Y","32" +"NOP r/m64","NOPQ r/m64","nopq r/m64","REX.W 0F 18 /4","N.S.","V","","","r","Y","64" +"NOP r/m64","NOPQ r/m64","nopq r/m64","REX.W 0F 18 /5","N.S.","V","","","r","Y","64" +"NOP r/m64","NOPQ r/m64","nopq r/m64","REX.W 0F 18 /6","N.S.","V","","","r","Y","64" +"NOP r/m64","NOPQ r/m64","nopq r/m64","REX.W 0F 18 /7","N.S.","V","","","r","Y","64" +"NOP r/m64, r64","NOPQ r64, r/m64","nopq r64, r/m64","REX.W 0F 19 /r","N.S.","V","","","r,r","Y","64" +"NOP r/m64, r64","NOPQ r64, r/m64","nopq r64, r/m64","REX.W 0F 1A /r","N.S.","V","","","r,r","Y","64" +"NOP r/m64, r64","NOPQ r64, r/m64","nopq r64, r/m64","REX.W 0F 1B /r","N.S.","V","","","r,r","Y","64" +"NOP r/m64, r64","NOPQ r64, r/m64","nopq r64, r/m64","REX.W 0F 1C /r","N.S.","V","","","r,r","Y","64" +"NOP r/m64, r64","NOPQ r64, r/m64","nopq r64, r/m64","REX.W 0F 1D /r","N.S.","V","","","r,r","Y","64" +"NOP r/m64, r64","NOPQ r64, r/m64","nopq r64, r/m64","REX.W 0F 1E /r","N.S.","V","","","r,r","Y","64" +"NOP r/m64, r64","NOPQ r64, r/m64","nopq r64, r/m64","REX.W 0F 1E /r","N.S.","V","PPRO","","r,r","Y","64" +"NOP r/m64, r64","NOPQ r64, r/m64","nopq r64, r/m64","REX.W 0F 1F /r","N.S.","V","","","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","66 REX.W 0F 1E /r","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F2 REX.W 0F 1E /r","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1B /r","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E /0","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E /1","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E /2","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E /3","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E /4","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E /5","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E /6","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E F8","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E F9","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E FA","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E FB","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E FC","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E FD","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E FE","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","F3 REX.W 0F 1E FF","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","REX.W 0F 0D /r","N.S.","V","PRFCHW","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","REX.W 0F 1A /r","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64, r64","NOPQ r64, rmr64","nopq r64, rmr64","REX.W 0F 1B /r","N.S.","V","PPRO","modrm_regonly","r,r","Y","64" +"NOP rmr64","NOPQ rmr64","nopq rmr64","REX.W 0F 18 /0","N.S.","V","","modrm_regonly","r","Y","64" +"NOP rmr64","NOPQ rmr64","nopq rmr64","REX.W 0F 18 /1","N.S.","V","","modrm_regonly","r","Y","64" +"NOP rmr64","NOPQ rmr64","nopq rmr64","REX.W 0F 18 /2","N.S.","V","","modrm_regonly","r","Y","64" +"NOP rmr64","NOPQ rmr64","nopq rmr64","REX.W 0F 18 /3","N.S.","V","","modrm_regonly","r","Y","64" +"NOP r/m16","NOPW r/m16","nopw r/m16","0F 18 /4","V","V","","operand16","r","Y","16" +"NOP r/m16","NOPW r/m16","nopw r/m16","0F 18 /5","V","V","","operand16","r","Y","16" +"NOP r/m16","NOPW r/m16","nopw r/m16","0F 18 /6","V","V","","operand16","r","Y","16" +"NOP r/m16","NOPW r/m16","nopw r/m16","0F 18 /7","V","V","","operand16","r","Y","16" +"NOP r/m16, r16","NOPW r16, r/m16","nopw r16, r/m16","0F 19 /r","V","V","","operand16","r,r","Y","16" +"NOP r/m16, r16","NOPW r16, r/m16","nopw r16, r/m16","0F 1A /r","V","V","","operand16","r,r","Y","16" +"NOP r/m16, r16","NOPW r16, r/m16","nopw r16, r/m16","0F 1B /r","V","V","","operand16","r,r","Y","16" +"NOP r/m16, r16","NOPW r16, r/m16","nopw r16, r/m16","0F 1C /r","V","V","","operand16","r,r","Y","16" +"NOP r/m16, r16","NOPW r16, r/m16","nopw r16, r/m16","0F 1D /r","V","V","","operand16","r,r","Y","16" +"NOP r/m16, r16","NOPW r16, r/m16","nopw r16, r/m16","0F 1E /r","V","V","","operand16","r,r","Y","16" +"NOP r/m16, r16","NOPW r16, r/m16","nopw r16, r/m16","0F 1E /r","V","V","PPRO","operand16","r,r","Y","16" +"NOP r/m16, r16","NOPW r16, r/m16","nopw r16, r/m16","0F 1F /r","V","V","","operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","0F 0D /r","V","V","PRFCHW","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","0F 1A /r","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","0F 1B /r","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","66 0F 1E /r","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F2 0F 1E /r","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1B /r","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E /0","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E /1","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E /2","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E /3","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E /4","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E /5","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E /6","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E F8","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E F9","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E FA","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E FB","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E FC","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E FD","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E FE","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16, r16","NOPW r16, rmr16","nopw r16, rmr16","F3 0F 1E FF","V","V","PPRO","modrm_regonly,operand16","r,r","Y","16" +"NOP rmr16","NOPW rmr16","nopw rmr16","0F 18 /0","V","V","","modrm_regonly,operand16","r","Y","16" +"NOP rmr16","NOPW rmr16","nopw rmr16","0F 18 /1","V","V","","modrm_regonly,operand16","r","Y","16" +"NOP rmr16","NOPW rmr16","nopw rmr16","0F 18 /2","V","V","","modrm_regonly,operand16","r","Y","16" +"NOP rmr16","NOPW rmr16","nopw rmr16","0F 18 /3","V","V","","modrm_regonly,operand16","r","Y","16" +"NOT r/m8","NOTB r/m8","notb r/m8","F6 /2","V","V","","","rw","Y","8" +"NOT r/m8","NOTB r/m8","notb r/m8","REX F6 /2","N.E.","V","","pseudo64","rw","Y","8" +"NOT r/m32","NOTL r/m32","notl r/m32","F7 /2","V","V","","operand32","rw","Y","32" +"NOT r/m64","NOTQ r/m64","notq r/m64","REX.W F7 /2","N.S.","V","","","rw","Y","64" +"NOT r/m16","NOTW r/m16","notw r/m16","F7 /2","V","V","","operand16","rw","Y","16" +"OR r/m8, imm8","ORB imm8, r/m8","orb imm8, r/m8","80 /1 ib","V","V","","","rw,r","Y","8" +"OR r/m8, imm8","ORB imm8, r/m8","orb imm8, r/m8","82 /1 ib","V","N.S.","","","rw,r","Y","8" +"OR r/m8, imm8","ORB imm8, r/m8","orb imm8, r/m8","REX 80 /1 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"OR AL, imm8u","ORB imm8u, AL","orb imm8u, AL","0C ib","V","V","","","rw,r","Y","8" +"OR r8, r/m8","ORB r/m8, r8","orb r/m8, r8","0A /r","V","V","","","rw,r","Y","8" +"OR r8, r/m8","ORB r/m8, r8","orb r/m8, r8","REX 0A /r","N.E.","V","","pseudo64","rw,r","Y","8" +"OR r/m8, r8","ORB r8, r/m8","orb r8, r/m8","08 /r","V","V","","","rw,r","Y","8" +"OR r/m8, r8","ORB r8, r/m8","orb r8, r/m8","REX 08 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"OR EAX, imm32","ORL imm32, EAX","orl imm32, EAX","0D id","V","V","","operand32","rw,r","Y","32" +"OR r/m32, imm32","ORL imm32, r/m32","orl imm32, r/m32","81 /1 id","V","V","","operand32","rw,r","Y","32" +"OR r/m32, imm8","ORL imm8, r/m32","orl imm8, r/m32","83 /1 ib","V","V","","operand32","rw,r","Y","32" +"OR r32, r/m32","ORL r/m32, r32","orl r/m32, r32","0B /r","V","V","","operand32","rw,r","Y","32" +"OR r/m32, r32","ORL r32, r/m32","orl r32, r/m32","09 /r","V","V","","operand32","rw,r","Y","32" +"ORPD xmm1, xmm2/m128","ORPD xmm2/m128, xmm1","orpd xmm2/m128, xmm1","66 0F 56 /r","V","V","SSE2","","rw,r","","" +"ORPS xmm1, xmm2/m128","ORPS xmm2/m128, xmm1","orps xmm2/m128, xmm1","0F 56 /r","V","V","SSE","","rw,r","","" +"OR RAX, imm32","ORQ imm32, RAX","orq imm32, RAX","REX.W 0D id","N.S.","V","","","rw,r","Y","64" +"OR r/m64, imm32","ORQ imm32, r/m64","orq imm32, r/m64","REX.W 81 /1 id","N.S.","V","","","rw,r","Y","64" +"OR r/m64, imm8","ORQ imm8, r/m64","orq imm8, r/m64","REX.W 83 /1 ib","N.S.","V","","","rw,r","Y","64" +"OR r64, r/m64","ORQ r/m64, r64","orq r/m64, r64","REX.W 0B /r","N.S.","V","","","rw,r","Y","64" +"OR r/m64, r64","ORQ r64, r/m64","orq r64, r/m64","REX.W 09 /r","N.S.","V","","","rw,r","Y","64" +"OR AX, imm16","ORW imm16, AX","orw imm16, AX","0D iw","V","V","","operand16","rw,r","Y","16" +"OR r/m16, imm16","ORW imm16, r/m16","orw imm16, r/m16","81 /1 iw","V","V","","operand16","rw,r","Y","16" +"OR r/m16, imm8","ORW imm8, r/m16","orw imm8, r/m16","83 /1 ib","V","V","","operand16","rw,r","Y","16" +"OR r16, r/m16","ORW r/m16, r16","orw r/m16, r16","0B /r","V","V","","operand16","rw,r","Y","16" +"OR r/m16, r16","ORW r16, r/m16","orw r16, r/m16","09 /r","V","V","","operand16","rw,r","Y","16" +"OUT DX, AL","OUTB AL, DX","outb AL, DX","EE","V","V","","","r,r","Y","8" +"OUT imm8u, AL","OUTB AL, imm8u","outb AL, imm8u","E6 ib","V","V","","","r,r","Y","8" +"OUT DX, EAX","OUTL EAX, DX","outl EAX, DX","EF","V","V","","operand32,operand64","r,r","Y","32" +"OUT imm8u, EAX","OUTL EAX, imm8u","outl EAX, imm8u","E7 ib","V","V","","operand32,operand64","r,r","Y","32" +"OUTSB","OUTSB","outsb","6E","V","V","","","","","" +"OUTSD","OUTSL","outsl","6F","V","V","","operand32,operand64","","","" +"OUTSW","OUTSW","outsw","6F","V","V","","operand16","","","" +"OUT DX, AX","OUTW AX, DX","outw AX, DX","EF","V","V","","operand16","r,r","Y","16" +"OUT imm8u, AX","OUTW AX, imm8u","outw AX, imm8u","E7 ib","V","V","","operand16","r,r","Y","16" +"PABSB mm1, mm2/m64","PABSB mm2/m64, mm1","pabsb mm2/m64, mm1","0F 38 1C /r","V","V","SSSE3","","w,r","","" +"PABSB xmm1, xmm2/m128","PABSB xmm2/m128, xmm1","pabsb xmm2/m128, xmm1","66 0F 38 1C /r","V","V","SSSE3","","w,r","","" +"PABSD mm1, mm2/m64","PABSD mm2/m64, mm1","pabsd mm2/m64, mm1","0F 38 1E /r","V","V","SSSE3","","w,r","","" +"PABSD xmm1, xmm2/m128","PABSD xmm2/m128, xmm1","pabsd xmm2/m128, xmm1","66 0F 38 1E /r","V","V","SSSE3","","w,r","","" +"PABSW mm1, mm2/m64","PABSW mm2/m64, mm1","pabsw mm2/m64, mm1","0F 38 1D /r","V","V","SSSE3","","w,r","","" +"PABSW xmm1, xmm2/m128","PABSW xmm2/m128, xmm1","pabsw xmm2/m128, xmm1","66 0F 38 1D /r","V","V","SSSE3","","w,r","","" +"PACKSSDW mm1, mm2/m64","PACKSSLW mm2/m64, mm1","packssdw mm2/m64, mm1","0F 6B /r","V","V","MMX","","rw,r","","" +"PACKSSDW xmm1, xmm2/m128","PACKSSLW xmm2/m128, xmm1","packssdw xmm2/m128, xmm1","66 0F 6B /r","V","V","SSE2","","rw,r","","" +"PACKSSWB mm1, mm2/m64","PACKSSWB mm2/m64, mm1","packsswb mm2/m64, mm1","0F 63 /r","V","V","MMX","","rw,r","","" +"PACKSSWB xmm1, xmm2/m128","PACKSSWB xmm2/m128, xmm1","packsswb xmm2/m128, xmm1","66 0F 63 /r","V","V","SSE2","","rw,r","","" +"PACKUSDW xmm1, xmm2/m128","PACKUSDW xmm2/m128, xmm1","packusdw xmm2/m128, xmm1","66 0F 38 2B /r","V","V","SSE4_1","","rw,r","","" +"PACKUSWB mm1, mm2/m64","PACKUSWB mm2/m64, mm1","packuswb mm2/m64, mm1","0F 67 /r","V","V","MMX","","rw,r","","" +"PACKUSWB xmm1, xmm2/m128","PACKUSWB xmm2/m128, xmm1","packuswb xmm2/m128, xmm1","66 0F 67 /r","V","V","SSE2","","rw,r","","" +"PADDB mm1, mm2/m64","PADDB mm2/m64, mm1","paddb mm2/m64, mm1","0F FC /r","V","V","MMX","","rw,r","","" +"PADDB xmm1, xmm2/m128","PADDB xmm2/m128, xmm1","paddb xmm2/m128, xmm1","66 0F FC /r","V","V","SSE2","","rw,r","","" +"PADDD mm1, mm2/m64","PADDL mm2/m64, mm1","paddd mm2/m64, mm1","0F FE /r","V","V","MMX","","rw,r","","" +"PADDD xmm1, xmm2/m128","PADDL xmm2/m128, xmm1","paddd xmm2/m128, xmm1","66 0F FE /r","V","V","SSE2","","rw,r","","" +"PADDQ mm1, mm2/m64","PADDQ mm2/m64, mm1","paddq mm2/m64, mm1","0F D4 /r","V","V","SSE2","","rw,r","","" +"PADDQ xmm1, xmm2/m128","PADDQ xmm2/m128, xmm1","paddq xmm2/m128, xmm1","66 0F D4 /r","V","V","SSE2","","rw,r","","" +"PADDSB mm1, mm2/m64","PADDSB mm2/m64, mm1","paddsb mm2/m64, mm1","0F EC /r","V","V","MMX","","rw,r","","" +"PADDSB xmm1, xmm2/m128","PADDSB xmm2/m128, xmm1","paddsb xmm2/m128, xmm1","66 0F EC /r","V","V","SSE2","","rw,r","","" +"PADDSW mm1, mm2/m64","PADDSW mm2/m64, mm1","paddsw mm2/m64, mm1","0F ED /r","V","V","MMX","","rw,r","","" +"PADDSW xmm1, xmm2/m128","PADDSW xmm2/m128, xmm1","paddsw xmm2/m128, xmm1","66 0F ED /r","V","V","SSE2","","rw,r","","" +"PADDUSB mm1, mm2/m64","PADDUSB mm2/m64, mm1","paddusb mm2/m64, mm1","0F DC /r","V","V","MMX","","rw,r","","" +"PADDUSB xmm1, xmm2/m128","PADDUSB xmm2/m128, xmm1","paddusb xmm2/m128, xmm1","66 0F DC /r","V","V","SSE2","","rw,r","","" +"PADDUSW mm1, mm2/m64","PADDUSW mm2/m64, mm1","paddusw mm2/m64, mm1","0F DD /r","V","V","MMX","","rw,r","","" +"PADDUSW xmm1, xmm2/m128","PADDUSW xmm2/m128, xmm1","paddusw xmm2/m128, xmm1","66 0F DD /r","V","V","SSE2","","rw,r","","" +"PADDW mm1, mm2/m64","PADDW mm2/m64, mm1","paddw mm2/m64, mm1","0F FD /r","V","V","MMX","","rw,r","","" +"PADDW xmm1, xmm2/m128","PADDW xmm2/m128, xmm1","paddw xmm2/m128, xmm1","66 0F FD /r","V","V","SSE2","","rw,r","","" +"PALIGNR mm1, mm2/m64, imm8u","PALIGNR imm8u, mm2/m64, mm1","palignr imm8u, mm2/m64, mm1","0F 3A 0F /r ib","V","V","SSSE3","","rw,r,r","","" +"PALIGNR xmm1, xmm2/m128, imm8u","PALIGNR imm8u, xmm2/m128, xmm1","palignr imm8u, xmm2/m128, xmm1","66 0F 3A 0F /r ib","V","V","SSSE3","","rw,r,r","","" +"PAND mm1, mm2/m64","PAND mm2/m64, mm1","pand mm2/m64, mm1","0F DB /r","V","V","MMX","","rw,r","","" +"PAND xmm1, xmm2/m128","PAND xmm2/m128, xmm1","pand xmm2/m128, xmm1","66 0F DB /r","V","V","SSE2","","rw,r","","" +"PANDN mm1, mm2/m64","PANDN mm2/m64, mm1","pandn mm2/m64, mm1","0F DF /r","V","V","MMX","","rw,r","","" +"PANDN xmm1, xmm2/m128","PANDN xmm2/m128, xmm1","pandn xmm2/m128, xmm1","66 0F DF /r","V","V","SSE2","","rw,r","","" +"PAUSE","PAUSE","pause","F3 90","V","V","","pseudo","","","" +"PAUSE","PAUSE","pause","F3 90+rd","V","V","","operand32","","Y","" +"PAUSE","PAUSE","pause","F3 90+rw","V","V","","operand16,operand64","","Y","" +"PAVGB mm1, mm2/m64","PAVGB mm2/m64, mm1","pavgb mm2/m64, mm1","0F E0 /r","V","V","MMX","","rw,r","","" +"PAVGB xmm1, xmm2/m128","PAVGB xmm2/m128, xmm1","pavgb xmm2/m128, xmm1","66 0F E0 /r","V","V","SSE2","","rw,r","","" +"PAVGUSB mm1, mm2/m64","PAVGUSB mm2/m64, mm1","pavgusb mm2/m64, mm1","0F 0F BF /r","V","V","3DNOW","amd","rw,r","","" +"PAVGW mm1, mm2/m64","PAVGW mm2/m64, mm1","pavgw mm2/m64, mm1","0F E3 /r","V","V","MMX","","rw,r","","" +"PAVGW xmm1, xmm2/m128","PAVGW xmm2/m128, xmm1","pavgw xmm2/m128, xmm1","66 0F E3 /r","V","V","SSE2","","rw,r","","" +"PBLENDVB xmm1, xmm2/m128, ","PBLENDVB , xmm2/m128, xmm1","pblendvb , xmm2/m128, xmm1","66 0F 38 10 /r","V","V","SSE4_1","","rw,r,r","","" +"PBLENDW xmm1, xmm2/m128, imm8u","PBLENDW imm8u, xmm2/m128, xmm1","pblendw imm8u, xmm2/m128, xmm1","66 0F 3A 0E /r ib","V","V","SSE4_1","","rw,r,r","","" +"PCLMULQDQ xmm1, xmm2/m128, imm8u","PCLMULQDQ imm8u, xmm2/m128, xmm1","pclmulqdq imm8u, xmm2/m128, xmm1","66 0F 3A 44 /r ib","V","V","PCLMULQDQ","","rw,r,r","","" +"PCMPEQB mm1, mm2/m64","PCMPEQB mm2/m64, mm1","pcmpeqb mm2/m64, mm1","0F 74 /r","V","V","MMX","","rw,r","","" +"PCMPEQB xmm1, xmm2/m128","PCMPEQB xmm2/m128, xmm1","pcmpeqb xmm2/m128, xmm1","66 0F 74 /r","V","V","SSE2","","rw,r","","" +"PCMPEQD mm1, mm2/m64","PCMPEQL mm2/m64, mm1","pcmpeqd mm2/m64, mm1","0F 76 /r","V","V","MMX","","rw,r","","" +"PCMPEQD xmm1, xmm2/m128","PCMPEQL xmm2/m128, xmm1","pcmpeqd xmm2/m128, xmm1","66 0F 76 /r","V","V","SSE2","","rw,r","","" +"PCMPEQQ xmm1, xmm2/m128","PCMPEQQ xmm2/m128, xmm1","pcmpeqq xmm2/m128, xmm1","66 0F 38 29 /r","V","V","SSE4_1","","rw,r","","" +"PCMPEQW mm1, mm2/m64","PCMPEQW mm2/m64, mm1","pcmpeqw mm2/m64, mm1","0F 75 /r","V","V","MMX","","rw,r","","" +"PCMPEQW xmm1, xmm2/m128","PCMPEQW xmm2/m128, xmm1","pcmpeqw xmm2/m128, xmm1","66 0F 75 /r","V","V","SSE2","","rw,r","","" +"PCMPESTRI xmm1, xmm2/m128, imm8u","PCMPESTRI imm8u, xmm2/m128, xmm1","pcmpestri imm8u, xmm2/m128, xmm1","66 0F 3A 61 /r ib","V","V","SSE4_2","","r,r,r","","" +"PCMPESTRM xmm1, xmm2/m128, imm8u","PCMPESTRM imm8u, xmm2/m128, xmm1","pcmpestrm imm8u, xmm2/m128, xmm1","66 0F 3A 60 /r ib","V","V","SSE4_2","","r,r,r","","" +"PCMPGTB mm1, mm2/m64","PCMPGTB mm2/m64, mm1","pcmpgtb mm2/m64, mm1","0F 64 /r","V","V","MMX","","rw,r","","" +"PCMPGTB xmm1, xmm2/m128","PCMPGTB xmm2/m128, xmm1","pcmpgtb xmm2/m128, xmm1","66 0F 64 /r","V","V","SSE2","","rw,r","","" +"PCMPGTD mm1, mm2/m64","PCMPGTL mm2/m64, mm1","pcmpgtd mm2/m64, mm1","0F 66 /r","V","V","MMX","","rw,r","","" +"PCMPGTD xmm1, xmm2/m128","PCMPGTL xmm2/m128, xmm1","pcmpgtd xmm2/m128, xmm1","66 0F 66 /r","V","V","SSE2","","rw,r","","" +"PCMPGTQ xmm1, xmm2/m128","PCMPGTQ xmm2/m128, xmm1","pcmpgtq xmm2/m128, xmm1","66 0F 38 37 /r","V","V","SSE4_2","","rw,r","","" +"PCMPGTW mm1, mm2/m64","PCMPGTW mm2/m64, mm1","pcmpgtw mm2/m64, mm1","0F 65 /r","V","V","MMX","","rw,r","","" +"PCMPGTW xmm1, xmm2/m128","PCMPGTW xmm2/m128, xmm1","pcmpgtw xmm2/m128, xmm1","66 0F 65 /r","V","V","SSE2","","rw,r","","" +"PCMPISTRI xmm1, xmm2/m128, imm8u","PCMPISTRI imm8u, xmm2/m128, xmm1","pcmpistri imm8u, xmm2/m128, xmm1","66 0F 3A 63 /r ib","V","V","SSE4_2","","r,r,r","","" +"PCMPISTRM xmm1, xmm2/m128, imm8u","PCMPISTRM imm8u, xmm2/m128, xmm1","pcmpistrm imm8u, xmm2/m128, xmm1","66 0F 3A 62 /r ib","V","V","SSE4_2","","r,r,r","","" +"PDEP r32, r32V, r/m32","PDEPL r/m32, r32V, r32","pdepl r/m32, r32V, r32","VEX.DDS.128.F2.0F38.W0 F5 /r","V","V","BMI2","","rw,r,r","Y","32" +"PDEP r64, r64V, r/m64","PDEPQ r/m64, r64V, r64","pdepq r/m64, r64V, r64","VEX.DDS.128.F2.0F38.W1 F5 /r","N.S.","V","BMI2","","rw,r,r","Y","64" +"PEXT r32, r32V, r/m32","PEXTL r/m32, r32V, r32","pextl r/m32, r32V, r32","VEX.DDS.128.F3.0F38.W0 F5 /r","V","V","BMI2","","rw,r,r","Y","32" +"PEXT r64, r64V, r/m64","PEXTQ r/m64, r64V, r64","pextq r/m64, r64V, r64","VEX.DDS.128.F3.0F38.W1 F5 /r","N.S.","V","BMI2","","rw,r,r","Y","64" +"PEXTRB r32/m8, xmm1, imm8u","PEXTRB imm8u, xmm1, r32/m8","pextrb imm8u, xmm1, r32/m8","66 0F 3A 14 /r ib","V","V","SSE4_1","","w,r,r","","" +"PEXTRD r/m32, xmm1, imm8u","PEXTRD imm8u, xmm1, r/m32","pextrd imm8u, xmm1, r/m32","66 0F 3A 16 /r ib","V","V","SSE4_1","operand16,operand32","w,r,r","","" +"PEXTRQ r/m64, xmm1, imm8u","PEXTRQ imm8u, xmm1, r/m64","pextrq imm8u, xmm1, r/m64","66 REX.W 0F 3A 16 /r ib","N.S.","V","SSE4_1","","w,r,r","","" +"PEXTRW r32, mm2, imm8u","PEXTRW imm8u, mm2, r32","pextrw imm8u, mm2, r32","0F C5 /r ib","V","V","MMX","modrm_regonly","w,r,r","","" +"PEXTRW r32/m16, xmm1, imm8u","PEXTRW imm8u, xmm1, r32/m16","pextrw imm8u, xmm1, r32/m16","66 0F 3A 15 /r ib","V","V","SSE4_1","","w,r,r","","" +"PEXTRW r32, xmm2, imm8u","PEXTRW imm8u, xmm2, r32","pextrw imm8u, xmm2, r32","66 0F C5 /r ib","V","V","SSE2","modrm_regonly","w,r,r","","" +"PF2ID mm1, mm2/m64","PF2ID mm2/m64, mm1","pf2id mm2/m64, mm1","0F 0F 1D /r","V","V","3DNOW","amd","rw,r","","" +"PF2IW mm1, mm2/m64","PF2IW mm2/m64, mm1","pf2iw mm2/m64, mm1","0F 0F 1C /r","V","V","3DNOW","amd","rw,r","","" +"PFACC mm1, mm2/m64","PFACC mm2/m64, mm1","pfacc mm2/m64, mm1","0F 0F AE /r","V","V","3DNOW","amd","rw,r","","" +"PFADD mm1, mm2/m64","PFADD mm2/m64, mm1","pfadd mm2/m64, mm1","0F 0F 9E /r","V","V","3DNOW","amd","rw,r","","" +"PFCMPEQ mm1, mm2/m64","PFCMPEQ mm2/m64, mm1","pfcmpeq mm2/m64, mm1","0F 0F B0 /r","V","V","3DNOW","amd","rw,r","","" +"PFCMPGE mm1, mm2/m64","PFCMPGE mm2/m64, mm1","pfcmpge mm2/m64, mm1","0F 0F 90 /r","V","V","3DNOW","amd","rw,r","","" +"PFCMPGT mm1, mm2/m64","PFCMPGT mm2/m64, mm1","pfcmpgt mm2/m64, mm1","0F 0F A0 /r","V","V","3DNOW","amd","rw,r","","" +"PFMAX mm1, mm2/m64","PFMAX mm2/m64, mm1","pfmax mm2/m64, mm1","0F 0F A4 /r","V","V","3DNOW","amd","rw,r","","" +"PFMIN mm1, mm2/m64","PFMIN mm2/m64, mm1","pfmin mm2/m64, mm1","0F 0F 94 /r","V","V","3DNOW","amd","rw,r","","" +"PFMUL mm1, mm2/m64","PFMUL mm2/m64, mm1","pfmul mm2/m64, mm1","0F 0F B4 /r","V","V","3DNOW","amd","rw,r","","" +"PFNACC mm1, mm2/m64","PFNACC mm2/m64, mm1","pfnacc mm2/m64, mm1","0F 0F 8A /r","V","V","3DNOW","amd","rw,r","","" +"PFPNACC mm1, mm2/m64","PFPNACC mm2/m64, mm1","pfpnacc mm2/m64, mm1","0F 0F 8E /r","V","V","3DNOW","amd","rw,r","","" +"PFRCP mm1, mm2/m64","PFRCP mm2/m64, mm1","pfrcp mm2/m64, mm1","0F 0F 96 /r","V","V","3DNOW","amd","rw,r","","" +"PFRCPIT1 mm1, mm2/m64","PFRCPIT1 mm2/m64, mm1","pfrcpit1 mm2/m64, mm1","0F 0F A6 /r","V","V","3DNOW","amd","rw,r","","" +"PFRCPIT2 mm1, mm2/m64","PFRCPIT2 mm2/m64, mm1","pfrcpit2 mm2/m64, mm1","0F 0F B6 /r","V","V","3DNOW","amd","rw,r","","" +"PFRSQIT1 mm1, mm2/m64","PFRSQIT1 mm2/m64, mm1","pfrsqit1 mm2/m64, mm1","0F 0F A7 /r","V","V","3DNOW","amd","rw,r","","" +"PFRSQRT mm1, mm2/m64","PFRSQRT mm2/m64, mm1","pfrsqrt mm2/m64, mm1","0F 0F 97 /r","V","V","3DNOW","amd","rw,r","","" +"PFSUB mm1, mm2/m64","PFSUB mm2/m64, mm1","pfsub mm2/m64, mm1","0F 0F 9A /r","V","V","3DNOW","amd","rw,r","","" +"PFSUBR mm1, mm2/m64","PFSUBR mm2/m64, mm1","pfsubr mm2/m64, mm1","0F 0F AA /r","V","V","3DNOW","amd","rw,r","","" +"PHADDD mm1, mm2/m64","PHADDD mm2/m64, mm1","phaddd mm2/m64, mm1","0F 38 02 /r","V","V","SSSE3","","rw,r","","" +"PHADDD xmm1, xmm2/m128","PHADDD xmm2/m128, xmm1","phaddd xmm2/m128, xmm1","66 0F 38 02 /r","V","V","SSSE3","","rw,r","","" +"PHADDSW mm1, mm2/m64","PHADDSW mm2/m64, mm1","phaddsw mm2/m64, mm1","0F 38 03 /r","V","V","SSSE3","","rw,r","","" +"PHADDSW xmm1, xmm2/m128","PHADDSW xmm2/m128, xmm1","phaddsw xmm2/m128, xmm1","66 0F 38 03 /r","V","V","SSSE3","","rw,r","","" +"PHADDW mm1, mm2/m64","PHADDW mm2/m64, mm1","phaddw mm2/m64, mm1","0F 38 01 /r","V","V","SSSE3","","rw,r","","" +"PHADDW xmm1, xmm2/m128","PHADDW xmm2/m128, xmm1","phaddw xmm2/m128, xmm1","66 0F 38 01 /r","V","V","SSSE3","","rw,r","","" +"PHMINPOSUW xmm1, xmm2/m128","PHMINPOSUW xmm2/m128, xmm1","phminposuw xmm2/m128, xmm1","66 0F 38 41 /r","V","V","SSE4_1","","w,r","","" +"PHSUBD mm1, mm2/m64","PHSUBD mm2/m64, mm1","phsubd mm2/m64, mm1","0F 38 06 /r","V","V","SSSE3","","rw,r","","" +"PHSUBD xmm1, xmm2/m128","PHSUBD xmm2/m128, xmm1","phsubd xmm2/m128, xmm1","66 0F 38 06 /r","V","V","SSSE3","","rw,r","","" +"PHSUBSW mm1, mm2/m64","PHSUBSW mm2/m64, mm1","phsubsw mm2/m64, mm1","0F 38 07 /r","V","V","SSSE3","","rw,r","","" +"PHSUBSW xmm1, xmm2/m128","PHSUBSW xmm2/m128, xmm1","phsubsw xmm2/m128, xmm1","66 0F 38 07 /r","V","V","SSSE3","","rw,r","","" +"PHSUBW mm1, mm2/m64","PHSUBW mm2/m64, mm1","phsubw mm2/m64, mm1","0F 38 05 /r","V","V","SSSE3","","rw,r","","" +"PHSUBW xmm1, xmm2/m128","PHSUBW xmm2/m128, xmm1","phsubw xmm2/m128, xmm1","66 0F 38 05 /r","V","V","SSSE3","","rw,r","","" +"PI2FD mm1, mm2/m64","PI2FD mm2/m64, mm1","pi2fd mm2/m64, mm1","0F 0F 0D /r","V","V","3DNOW","amd","rw,r","","" +"PI2FW mm1, mm2/m64","PI2FW mm2/m64, mm1","pi2fw mm2/m64, mm1","0F 0F 0C /r","V","V","3DNOW","amd","rw,r","","" +"PINSRB xmm1, r32/m8, imm8u","PINSRB imm8u, r32/m8, xmm1","pinsrb imm8u, r32/m8, xmm1","66 0F 3A 20 /r ib","V","V","SSE4_1","","rw,r,r","","" +"PINSRD xmm1, r/m32, imm8u","PINSRD imm8u, r/m32, xmm1","pinsrd imm8u, r/m32, xmm1","66 0F 3A 22 /r ib","V","V","SSE4_1","operand16,operand32","rw,r,r","","" +"PINSRQ xmm1, r/m64, imm8u","PINSRQ imm8u, r/m64, xmm1","pinsrq imm8u, r/m64, xmm1","66 REX.W 0F 3A 22 /r ib","N.S.","V","SSE4_1","","rw,r,r","","" +"PINSRW mm1, r32/m16, imm8u","PINSRW imm8u, r32/m16, mm1","pinsrw imm8u, r32/m16, mm1","0F C4 /r ib","V","V","MMX","","rw,r,r","","" +"PINSRW xmm1, r32/m16, imm8u","PINSRW imm8u, r32/m16, xmm1","pinsrw imm8u, r32/m16, xmm1","66 0F C4 /r ib","V","V","SSE2","","rw,r,r","","" +"PMADDUBSW mm1, mm2/m64","PMADDUBSW mm2/m64, mm1","pmaddubsw mm2/m64, mm1","0F 38 04 /r","V","V","SSSE3","","rw,r","","" +"PMADDUBSW xmm1, xmm2/m128","PMADDUBSW xmm2/m128, xmm1","pmaddubsw xmm2/m128, xmm1","66 0F 38 04 /r","V","V","SSSE3","","rw,r","","" +"PMADDWD mm1, mm2/m64","PMADDWL mm2/m64, mm1","pmaddwd mm2/m64, mm1","0F F5 /r","V","V","MMX","","rw,r","","" +"PMADDWD xmm1, xmm2/m128","PMADDWL xmm2/m128, xmm1","pmaddwd xmm2/m128, xmm1","66 0F F5 /r","V","V","SSE2","","rw,r","","" +"PMAXSB xmm1, xmm2/m128","PMAXSB xmm2/m128, xmm1","pmaxsb xmm2/m128, xmm1","66 0F 38 3C /r","V","V","SSE4_1","","rw,r","","" +"PMAXSD xmm1, xmm2/m128","PMAXSD xmm2/m128, xmm1","pmaxsd xmm2/m128, xmm1","66 0F 38 3D /r","V","V","SSE4_1","","rw,r","","" +"PMAXSW mm1, mm2/m64","PMAXSW mm2/m64, mm1","pmaxsw mm2/m64, mm1","0F EE /r","V","V","MMX","","rw,r","","" +"PMAXSW xmm1, xmm2/m128","PMAXSW xmm2/m128, xmm1","pmaxsw xmm2/m128, xmm1","66 0F EE /r","V","V","SSE2","","rw,r","","" +"PMAXUB mm1, mm2/m64","PMAXUB mm2/m64, mm1","pmaxub mm2/m64, mm1","0F DE /r","V","V","MMX","","rw,r","","" +"PMAXUB xmm1, xmm2/m128","PMAXUB xmm2/m128, xmm1","pmaxub xmm2/m128, xmm1","66 0F DE /r","V","V","SSE2","","rw,r","","" +"PMAXUD xmm1, xmm2/m128","PMAXUD xmm2/m128, xmm1","pmaxud xmm2/m128, xmm1","66 0F 38 3F /r","V","V","SSE4_1","","rw,r","","" +"PMAXUW xmm1, xmm2/m128","PMAXUW xmm2/m128, xmm1","pmaxuw xmm2/m128, xmm1","66 0F 38 3E /r","V","V","SSE4_1","","rw,r","","" +"PMINSB xmm1, xmm2/m128","PMINSB xmm2/m128, xmm1","pminsb xmm2/m128, xmm1","66 0F 38 38 /r","V","V","SSE4_1","","rw,r","","" +"PMINSD xmm1, xmm2/m128","PMINSD xmm2/m128, xmm1","pminsd xmm2/m128, xmm1","66 0F 38 39 /r","V","V","SSE4_1","","rw,r","","" +"PMINSW mm1, mm2/m64","PMINSW mm2/m64, mm1","pminsw mm2/m64, mm1","0F EA /r","V","V","MMX","","rw,r","","" +"PMINSW xmm1, xmm2/m128","PMINSW xmm2/m128, xmm1","pminsw xmm2/m128, xmm1","66 0F EA /r","V","V","SSE2","","rw,r","","" +"PMINUB mm1, mm2/m64","PMINUB mm2/m64, mm1","pminub mm2/m64, mm1","0F DA /r","V","V","MMX","","rw,r","","" +"PMINUB xmm1, xmm2/m128","PMINUB xmm2/m128, xmm1","pminub xmm2/m128, xmm1","66 0F DA /r","V","V","SSE2","","rw,r","","" +"PMINUD xmm1, xmm2/m128","PMINUD xmm2/m128, xmm1","pminud xmm2/m128, xmm1","66 0F 38 3B /r","V","V","SSE4_1","","rw,r","","" +"PMINUW xmm1, xmm2/m128","PMINUW xmm2/m128, xmm1","pminuw xmm2/m128, xmm1","66 0F 38 3A /r","V","V","SSE4_1","","rw,r","","" +"PMOVMSKB r32, mm2","PMOVMSKB mm2, r32","pmovmskb mm2, r32","0F D7 /r","V","V","SSE","modrm_regonly","w,r","","" +"PMOVMSKB r32, xmm2","PMOVMSKB xmm2, r32","pmovmskb xmm2, r32","66 0F D7 /r","V","V","SSE2","modrm_regonly","w,r","","" +"PMOVSXBD xmm1, xmm2/m32","PMOVSXBD xmm2/m32, xmm1","pmovsxbd xmm2/m32, xmm1","66 0F 38 21 /r","V","V","SSE4_1","","w,r","","" +"PMOVSXBQ xmm1, xmm2/m16","PMOVSXBQ xmm2/m16, xmm1","pmovsxbq xmm2/m16, xmm1","66 0F 38 22 /r","V","V","SSE4_1","","w,r","","" +"PMOVSXBW xmm1, xmm2/m64","PMOVSXBW xmm2/m64, xmm1","pmovsxbw xmm2/m64, xmm1","66 0F 38 20 /r","V","V","SSE4_1","","w,r","","" +"PMOVSXDQ xmm1, xmm2/m64","PMOVSXDQ xmm2/m64, xmm1","pmovsxdq xmm2/m64, xmm1","66 0F 38 25 /r","V","V","SSE4_1","","w,r","","" +"PMOVSXWD xmm1, xmm2/m64","PMOVSXWD xmm2/m64, xmm1","pmovsxwd xmm2/m64, xmm1","66 0F 38 23 /r","V","V","SSE4_1","","w,r","","" +"PMOVSXWQ xmm1, xmm2/m32","PMOVSXWQ xmm2/m32, xmm1","pmovsxwq xmm2/m32, xmm1","66 0F 38 24 /r","V","V","SSE4_1","","w,r","","" +"PMOVZXBD xmm1, xmm2/m32","PMOVZXBD xmm2/m32, xmm1","pmovzxbd xmm2/m32, xmm1","66 0F 38 31 /r","V","V","SSE4_1","","w,r","","" +"PMOVZXBQ xmm1, xmm2/m16","PMOVZXBQ xmm2/m16, xmm1","pmovzxbq xmm2/m16, xmm1","66 0F 38 32 /r","V","V","SSE4_1","","w,r","","" +"PMOVZXBW xmm1, xmm2/m64","PMOVZXBW xmm2/m64, xmm1","pmovzxbw xmm2/m64, xmm1","66 0F 38 30 /r","V","V","SSE4_1","","w,r","","" +"PMOVZXDQ xmm1, xmm2/m64","PMOVZXDQ xmm2/m64, xmm1","pmovzxdq xmm2/m64, xmm1","66 0F 38 35 /r","V","V","SSE4_1","","w,r","","" +"PMOVZXWD xmm1, xmm2/m64","PMOVZXWD xmm2/m64, xmm1","pmovzxwd xmm2/m64, xmm1","66 0F 38 33 /r","V","V","SSE4_1","","w,r","","" +"PMOVZXWQ xmm1, xmm2/m32","PMOVZXWQ xmm2/m32, xmm1","pmovzxwq xmm2/m32, xmm1","66 0F 38 34 /r","V","V","SSE4_1","","w,r","","" +"PMULDQ xmm1, xmm2/m128","PMULDQ xmm2/m128, xmm1","pmuldq xmm2/m128, xmm1","66 0F 38 28 /r","V","V","SSE4_1","","rw,r","","" +"PMULHRSW mm1, mm2/m64","PMULHRSW mm2/m64, mm1","pmulhrsw mm2/m64, mm1","0F 38 0B /r","V","V","SSSE3","","rw,r","","" +"PMULHRSW xmm1, xmm2/m128","PMULHRSW xmm2/m128, xmm1","pmulhrsw xmm2/m128, xmm1","66 0F 38 0B /r","V","V","SSSE3","","rw,r","","" +"PMULHRW mm1, mm2/m64","PMULHRW mm2/m64, mm1","pmulhrw mm2/m64, mm1","0F 0F B7 /r","V","V","3DNOW","amd","rw,r","","" +"PMULHUW mm1, mm2/m64","PMULHUW mm2/m64, mm1","pmulhuw mm2/m64, mm1","0F E4 /r","V","V","MMX","","rw,r","","" +"PMULHUW xmm1, xmm2/m128","PMULHUW xmm2/m128, xmm1","pmulhuw xmm2/m128, xmm1","66 0F E4 /r","V","V","SSE2","","rw,r","","" +"PMULHW mm1, mm2/m64","PMULHW mm2/m64, mm1","pmulhw mm2/m64, mm1","0F E5 /r","V","V","MMX","","rw,r","","" +"PMULHW xmm1, xmm2/m128","PMULHW xmm2/m128, xmm1","pmulhw xmm2/m128, xmm1","66 0F E5 /r","V","V","SSE2","","rw,r","","" +"PMULLD xmm1, xmm2/m128","PMULLD xmm2/m128, xmm1","pmulld xmm2/m128, xmm1","66 0F 38 40 /r","V","V","SSE4_1","","rw,r","","" +"PMULLW mm1, mm2/m64","PMULLW mm2/m64, mm1","pmullw mm2/m64, mm1","0F D5 /r","V","V","MMX","","rw,r","","" +"PMULLW xmm1, xmm2/m128","PMULLW xmm2/m128, xmm1","pmullw xmm2/m128, xmm1","66 0F D5 /r","V","V","SSE2","","rw,r","","" +"PMULUDQ mm1, mm2/m64","PMULULQ mm2/m64, mm1","pmuludq mm2/m64, mm1","0F F4 /r","V","V","SSE2","","rw,r","","" +"PMULUDQ xmm1, xmm2/m128","PMULULQ xmm2/m128, xmm1","pmuludq xmm2/m128, xmm1","66 0F F4 /r","V","V","SSE2","","rw,r","","" +"POPAD","POPAL","popal","61","V","N.S.","","operand32","","","" +"POPA","POPAW","popaw","61","V","N.S.","","operand16","","","" +"POPCNT r32, r/m32","POPCNTL r/m32, r32","popcntl r/m32, r32","F3 0F B8 /r","V","V","POPCNT","operand32","w,r","Y","32" +"POPCNT r64, r/m64","POPCNTQ r/m64, r64","popcntq r/m64, r64","F3 REX.W 0F B8 /r","N.S.","V","POPCNT","","w,r","Y","64" +"POPCNT r16, r/m16","POPCNTW r/m16, r16","popcntw r/m16, r16","F3 0F B8 /r","V","V","POPCNT","operand16","w,r","Y","16" +"POPFD","POPFL","popfl","9D","V","N.S.","","operand32","","","" +"POPFQ","POPFQ","popfq","9D","N.S.","V","","default64","","","" +"POPF","POPFW","popfw","9D","V","V","","operand16","","","" +"POP r/m32","POPL r/m32","popl r/m32","8F /0","V","N.S.","","operand32","w","Y","32" +"POP r32op","POPL r32op","popl r32op","58+rd","V","N.S.","","operand32","w","Y","32" +"POP r/m64","POPQ r/m64","popq r/m64","8F /0","N.S.","V","","default64","w","Y","64" +"POP r64op","POPQ r64op","popq r64op","58+ro","N.S.","V","","default64","w","Y","64" +"POP r/m16","POPW r/m16","popw r/m16","8F /0","V","V","","operand16","w","Y","16" +"POP r16op","POPW r16op","popw r16op","58+rw","V","V","","operand16","w","Y","16" +"POP DS","POPW/POPL/POPQ DS","popw/popl/popq DS","1F","V","N.S.","","","w","Y","" +"POP ES","POPW/POPL/POPQ ES","popw/popl/popq ES","07","V","N.S.","","","w","Y","" +"POP FS","POPW/POPL/POPQ FS","popw/popl/popq FS","0F A1","N.S.","V","","default64","w","Y","" +"POP FS","POPW/POPL/POPQ FS","popw/popl/popq FS","0F A1","V","N.S.","","operand32","w","Y","" +"POP FS","POPW/POPL/POPQ FS","popw/popl/popq FS","0F A1","V","V","","operand16","w","Y","" +"POP GS","POPW/POPL/POPQ GS","popw/popl/popq GS","0F A9","N.S.","V","","default64","w","Y","" +"POP GS","POPW/POPL/POPQ GS","popw/popl/popq GS","0F A9","V","V","","operand16","w","Y","" +"POP GS","POPW/POPL/POPQ GS","popw/popl/popq GS","0F A9","V","N.S.","","operand32","w","Y","" +"POP SS","POPW/POPL/POPQ SS","popw/popl/popq SS","17","V","N.S.","","","w","Y","" +"POR mm1, mm2/m64","POR mm2/m64, mm1","por mm2/m64, mm1","0F EB /r","V","V","MMX","","rw,r","","" +"POR xmm1, xmm2/m128","POR xmm2/m128, xmm1","por xmm2/m128, xmm1","66 0F EB /r","V","V","SSE2","","rw,r","","" +"PREFETCHNTA m8","PREFETCHNTA m8","prefetchnta m8","0F 18 /0","V","V","","modrm_memonly","r","","" +"PREFETCHT0 m8","PREFETCHT0 m8","prefetcht0 m8","0F 18 /1","V","V","","modrm_memonly","r","","" +"PREFETCHT1 m8","PREFETCHT1 m8","prefetcht1 m8","0F 18 /2","V","V","","modrm_memonly","r","","" +"PREFETCHT2 m8","PREFETCHT2 m8","prefetcht2 m8","0F 18 /3","V","V","","modrm_memonly","r","","" +"PREFETCHW m8","PREFETCHW m8","prefetchw m8","0F 0D /1","V","V","PRFCHW","modrm_memonly","r","","" +"PREFETCHWT1 m8","PREFETCHWT1 m8","prefetchwt1 m8","0F 0D /2","V","V","PREFETCHWT1","modrm_memonly","r","","" +"PREFETCHW_ALIAS m8","PREFETCHW_ALIAS m8","prefetchw_alias m8","0F 0D /3","V","V","PRFCHW","modrm_memonly","r","","" +"PREFETCH_EXCLUSIVE m8","PREFETCH_EXCLUSIVE m8","prefetch_exclusive m8","0F 0D /0","V","V","PRFCHW","modrm_memonly","r","","" +"PREFETCH_RESERVED m8","PREFETCH_RESERVED m8","prefetch_reserved m8","0F 0D /2","V","V","PRFCHW","modrm_memonly","r","Y","" +"PREFETCH_RESERVED m8","PREFETCH_RESERVED m8","prefetch_reserved m8","0F 0D /4","V","V","PRFCHW","modrm_memonly","r","Y","" +"PREFETCH_RESERVED m8","PREFETCH_RESERVED m8","prefetch_reserved m8","0F 0D /5","V","V","PRFCHW","modrm_memonly","r","Y","" +"PREFETCH_RESERVED m8","PREFETCH_RESERVED m8","prefetch_reserved m8","0F 0D /6","V","V","PRFCHW","modrm_memonly","r","Y","" +"PREFETCH_RESERVED m8","PREFETCH_RESERVED m8","prefetch_reserved m8","0F 0D /7","V","V","PRFCHW","modrm_memonly","r","Y","" +"PSADBW mm1, mm2/m64","PSADBW mm2/m64, mm1","psadbw mm2/m64, mm1","0F F6 /r","V","V","MMX","","rw,r","","" +"PSADBW xmm1, xmm2/m128","PSADBW xmm2/m128, xmm1","psadbw xmm2/m128, xmm1","66 0F F6 /r","V","V","SSE2","","rw,r","","" +"PSHUFB mm1, mm2/m64","PSHUFB mm2/m64, mm1","pshufb mm2/m64, mm1","0F 38 00 /r","V","V","SSSE3","","rw,r","","" +"PSHUFB xmm1, xmm2/m128","PSHUFB xmm2/m128, xmm1","pshufb xmm2/m128, xmm1","66 0F 38 00 /r","V","V","SSSE3","","rw,r","","" +"PSHUFD xmm1, xmm2/m128, imm8u","PSHUFD imm8u, xmm2/m128, xmm1","pshufd imm8u, xmm2/m128, xmm1","66 0F 70 /r ib","V","V","SSE2","","w,r,r","","" +"PSHUFHW xmm1, xmm2/m128, imm8u","PSHUFHW imm8u, xmm2/m128, xmm1","pshufhw imm8u, xmm2/m128, xmm1","F3 0F 70 /r ib","V","V","SSE2","","w,r,r","","" +"PSHUFLW xmm1, xmm2/m128, imm8u","PSHUFLW imm8u, xmm2/m128, xmm1","pshuflw imm8u, xmm2/m128, xmm1","F2 0F 70 /r ib","V","V","SSE2","","w,r,r","","" +"PSHUFW mm1, mm2/m64, imm8u","PSHUFW imm8u, mm2/m64, mm1","pshufw imm8u, mm2/m64, mm1","0F 70 /r ib","V","V","MMX","","w,r,r","","" +"PSIGNB mm1, mm2/m64","PSIGNB mm2/m64, mm1","psignb mm2/m64, mm1","0F 38 08 /r","V","V","SSSE3","","rw,r","","" +"PSIGNB xmm1, xmm2/m128","PSIGNB xmm2/m128, xmm1","psignb xmm2/m128, xmm1","66 0F 38 08 /r","V","V","SSSE3","","rw,r","","" +"PSIGND mm1, mm2/m64","PSIGND mm2/m64, mm1","psignd mm2/m64, mm1","0F 38 0A /r","V","V","SSSE3","","rw,r","","" +"PSIGND xmm1, xmm2/m128","PSIGND xmm2/m128, xmm1","psignd xmm2/m128, xmm1","66 0F 38 0A /r","V","V","SSSE3","","rw,r","","" +"PSIGNW mm1, mm2/m64","PSIGNW mm2/m64, mm1","psignw mm2/m64, mm1","0F 38 09 /r","V","V","SSSE3","","rw,r","","" +"PSIGNW xmm1, xmm2/m128","PSIGNW xmm2/m128, xmm1","psignw xmm2/m128, xmm1","66 0F 38 09 /r","V","V","SSSE3","","rw,r","","" +"PSLLD mm2, imm8u","PSLLL imm8u, mm2","pslld imm8u, mm2","0F 72 /6 ib","V","V","MMX","modrm_regonly","rw,r","","" +"PSLLD xmm2, imm8u","PSLLL imm8u, xmm2","pslld imm8u, xmm2","66 0F 72 /6 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSLLD mm1, mm2/m64","PSLLL mm2/m64, mm1","pslld mm2/m64, mm1","0F F2 /r","V","V","MMX","","rw,r","","" +"PSLLD xmm1, xmm2/m128","PSLLL xmm2/m128, xmm1","pslld xmm2/m128, xmm1","66 0F F2 /r","V","V","SSE2","","rw,r","","" +"PSLLDQ xmm2, imm8u","PSLLO imm8u, xmm2","pslldq imm8u, xmm2","66 0F 73 /7 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSLLQ mm2, imm8u","PSLLQ imm8u, mm2","psllq imm8u, mm2","0F 73 /6 ib","V","V","MMX","modrm_regonly","rw,r","","" +"PSLLQ xmm2, imm8u","PSLLQ imm8u, xmm2","psllq imm8u, xmm2","66 0F 73 /6 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSLLQ mm1, mm2/m64","PSLLQ mm2/m64, mm1","psllq mm2/m64, mm1","0F F3 /r","V","V","MMX","","rw,r","","" +"PSLLQ xmm1, xmm2/m128","PSLLQ xmm2/m128, xmm1","psllq xmm2/m128, xmm1","66 0F F3 /r","V","V","SSE2","","rw,r","","" +"PSLLW mm2, imm8u","PSLLW imm8u, mm2","psllw imm8u, mm2","0F 71 /6 ib","V","V","MMX","modrm_regonly","rw,r","","" +"PSLLW xmm2, imm8u","PSLLW imm8u, xmm2","psllw imm8u, xmm2","66 0F 71 /6 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSLLW mm1, mm2/m64","PSLLW mm2/m64, mm1","psllw mm2/m64, mm1","0F F1 /r","V","V","MMX","","rw,r","","" +"PSLLW xmm1, xmm2/m128","PSLLW xmm2/m128, xmm1","psllw xmm2/m128, xmm1","66 0F F1 /r","V","V","SSE2","","rw,r","","" +"PSRAD mm2, imm8u","PSRAL imm8u, mm2","psrad imm8u, mm2","0F 72 /4 ib","V","V","MMX","modrm_regonly","rw,r","","" +"PSRAD xmm2, imm8u","PSRAL imm8u, xmm2","psrad imm8u, xmm2","66 0F 72 /4 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSRAD mm1, mm2/m64","PSRAL mm2/m64, mm1","psrad mm2/m64, mm1","0F E2 /r","V","V","MMX","","rw,r","","" +"PSRAD xmm1, xmm2/m128","PSRAL xmm2/m128, xmm1","psrad xmm2/m128, xmm1","66 0F E2 /r","V","V","SSE2","","rw,r","","" +"PSRAW mm2, imm8u","PSRAW imm8u, mm2","psraw imm8u, mm2","0F 71 /4 ib","V","V","MMX","modrm_regonly","rw,r","","" +"PSRAW xmm2, imm8u","PSRAW imm8u, xmm2","psraw imm8u, xmm2","66 0F 71 /4 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSRAW mm1, mm2/m64","PSRAW mm2/m64, mm1","psraw mm2/m64, mm1","0F E1 /r","V","V","MMX","","rw,r","","" +"PSRAW xmm1, xmm2/m128","PSRAW xmm2/m128, xmm1","psraw xmm2/m128, xmm1","66 0F E1 /r","V","V","SSE2","","rw,r","","" +"PSRLD mm2, imm8u","PSRLL imm8u, mm2","psrld imm8u, mm2","0F 72 /2 ib","V","V","MMX","modrm_regonly","rw,r","","" +"PSRLD xmm2, imm8u","PSRLL imm8u, xmm2","psrld imm8u, xmm2","66 0F 72 /2 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSRLD mm1, mm2/m64","PSRLL mm2/m64, mm1","psrld mm2/m64, mm1","0F D2 /r","V","V","MMX","","rw,r","","" +"PSRLD xmm1, xmm2/m128","PSRLL xmm2/m128, xmm1","psrld xmm2/m128, xmm1","66 0F D2 /r","V","V","SSE2","","rw,r","","" +"PSRLDQ xmm2, imm8u","PSRLO imm8u, xmm2","psrldq imm8u, xmm2","66 0F 73 /3 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSRLQ mm2, imm8u","PSRLQ imm8u, mm2","psrlq imm8u, mm2","0F 73 /2 ib","V","V","MMX","modrm_regonly","rw,r","","" +"PSRLQ xmm2, imm8u","PSRLQ imm8u, xmm2","psrlq imm8u, xmm2","66 0F 73 /2 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSRLQ mm1, mm2/m64","PSRLQ mm2/m64, mm1","psrlq mm2/m64, mm1","0F D3 /r","V","V","MMX","","rw,r","","" +"PSRLQ xmm1, xmm2/m128","PSRLQ xmm2/m128, xmm1","psrlq xmm2/m128, xmm1","66 0F D3 /r","V","V","SSE2","","rw,r","","" +"PSRLW mm2, imm8u","PSRLW imm8u, mm2","psrlw imm8u, mm2","0F 71 /2 ib","V","V","MMX","modrm_regonly","rw,r","","" +"PSRLW xmm2, imm8u","PSRLW imm8u, xmm2","psrlw imm8u, xmm2","66 0F 71 /2 ib","V","V","SSE2","modrm_regonly","rw,r","","" +"PSRLW mm1, mm2/m64","PSRLW mm2/m64, mm1","psrlw mm2/m64, mm1","0F D1 /r","V","V","MMX","","rw,r","","" +"PSRLW xmm1, xmm2/m128","PSRLW xmm2/m128, xmm1","psrlw xmm2/m128, xmm1","66 0F D1 /r","V","V","SSE2","","rw,r","","" +"PSUBB mm1, mm2/m64","PSUBB mm2/m64, mm1","psubb mm2/m64, mm1","0F F8 /r","V","V","MMX","","rw,r","","" +"PSUBB xmm1, xmm2/m128","PSUBB xmm2/m128, xmm1","psubb xmm2/m128, xmm1","66 0F F8 /r","V","V","SSE2","","rw,r","","" +"PSUBD mm1, mm2/m64","PSUBL mm2/m64, mm1","psubd mm2/m64, mm1","0F FA /r","V","V","MMX","","rw,r","","" +"PSUBD xmm1, xmm2/m128","PSUBL xmm2/m128, xmm1","psubd xmm2/m128, xmm1","66 0F FA /r","V","V","SSE2","","rw,r","","" +"PSUBQ mm1, mm2/m64","PSUBQ mm2/m64, mm1","psubq mm2/m64, mm1","0F FB /r","V","V","SSE2","","rw,r","","" +"PSUBQ xmm1, xmm2/m128","PSUBQ xmm2/m128, xmm1","psubq xmm2/m128, xmm1","66 0F FB /r","V","V","SSE2","","rw,r","","" +"PSUBSB mm1, mm2/m64","PSUBSB mm2/m64, mm1","psubsb mm2/m64, mm1","0F E8 /r","V","V","MMX","","rw,r","","" +"PSUBSB xmm1, xmm2/m128","PSUBSB xmm2/m128, xmm1","psubsb xmm2/m128, xmm1","66 0F E8 /r","V","V","SSE2","","rw,r","","" +"PSUBSW mm1, mm2/m64","PSUBSW mm2/m64, mm1","psubsw mm2/m64, mm1","0F E9 /r","V","V","MMX","","rw,r","","" +"PSUBSW xmm1, xmm2/m128","PSUBSW xmm2/m128, xmm1","psubsw xmm2/m128, xmm1","66 0F E9 /r","V","V","SSE2","","rw,r","","" +"PSUBUSB mm1, mm2/m64","PSUBUSB mm2/m64, mm1","psubusb mm2/m64, mm1","0F D8 /r","V","V","MMX","","rw,r","","" +"PSUBUSB xmm1, xmm2/m128","PSUBUSB xmm2/m128, xmm1","psubusb xmm2/m128, xmm1","66 0F D8 /r","V","V","SSE2","","rw,r","","" +"PSUBUSW mm1, mm2/m64","PSUBUSW mm2/m64, mm1","psubusw mm2/m64, mm1","0F D9 /r","V","V","MMX","","rw,r","","" +"PSUBUSW xmm1, xmm2/m128","PSUBUSW xmm2/m128, xmm1","psubusw xmm2/m128, xmm1","66 0F D9 /r","V","V","SSE2","","rw,r","","" +"PSUBW mm1, mm2/m64","PSUBW mm2/m64, mm1","psubw mm2/m64, mm1","0F F9 /r","V","V","MMX","","rw,r","","" +"PSUBW xmm1, xmm2/m128","PSUBW xmm2/m128, xmm1","psubw xmm2/m128, xmm1","66 0F F9 /r","V","V","SSE2","","rw,r","","" +"PSWAPD mm1, mm2/m64","PSWAPD mm2/m64, mm1","pswapd mm2/m64, mm1","0F 0F BB /r","V","V","3DNOW","amd","rw,r","","" +"PTEST xmm1, xmm2/m128","PTEST xmm2/m128, xmm1","ptest xmm2/m128, xmm1","66 0F 38 17 /r","V","V","SSE4_1","","r,r","","" +"PTWRITE r/m32","PTWRITEL r/m32","ptwritel r/m32","F3 0F AE /4","V","V","","operand16,operand32","r","Y","32" +"PTWRITE r/m64","PTWRITEQ r/m64","ptwriteq r/m64","F3 REX.W 0F AE /4","N.S.","V","","","r","Y","64" +"PUNPCKHBW mm1, mm2/m64","PUNPCKHBW mm2/m64, mm1","punpckhbw mm2/m64, mm1","0F 68 /r","V","V","MMX","","rw,r","","" +"PUNPCKHBW xmm1, xmm2/m128","PUNPCKHBW xmm2/m128, xmm1","punpckhbw xmm2/m128, xmm1","66 0F 68 /r","V","V","SSE2","","rw,r","","" +"PUNPCKHDQ mm1, mm2/m64","PUNPCKHLQ mm2/m64, mm1","punpckhdq mm2/m64, mm1","0F 6A /r","V","V","MMX","","rw,r","","" +"PUNPCKHDQ xmm1, xmm2/m128","PUNPCKHLQ xmm2/m128, xmm1","punpckhdq xmm2/m128, xmm1","66 0F 6A /r","V","V","SSE2","","rw,r","","" +"PUNPCKHQDQ xmm1, xmm2/m128","PUNPCKHQDQ xmm2/m128, xmm1","punpckhqdq xmm2/m128, xmm1","66 0F 6D /r","V","V","SSE2","","rw,r","","" +"PUNPCKHWD mm1, mm2/m64","PUNPCKHWL mm2/m64, mm1","punpckhwd mm2/m64, mm1","0F 69 /r","V","V","MMX","","rw,r","","" +"PUNPCKHWD xmm1, xmm2/m128","PUNPCKHWL xmm2/m128, xmm1","punpckhwd xmm2/m128, xmm1","66 0F 69 /r","V","V","SSE2","","rw,r","","" +"PUNPCKLBW mm1, mm2/m32","PUNPCKLBW mm2/m32, mm1","punpcklbw mm2/m32, mm1","0F 60 /r","V","V","MMX","","rw,r","","" +"PUNPCKLBW xmm1, xmm2/m128","PUNPCKLBW xmm2/m128, xmm1","punpcklbw xmm2/m128, xmm1","66 0F 60 /r","V","V","SSE2","","rw,r","","" +"PUNPCKLDQ mm1, mm2/m32","PUNPCKLLQ mm2/m32, mm1","punpckldq mm2/m32, mm1","0F 62 /r","V","V","MMX","","rw,r","","" +"PUNPCKLDQ xmm1, xmm2/m128","PUNPCKLLQ xmm2/m128, xmm1","punpckldq xmm2/m128, xmm1","66 0F 62 /r","V","V","SSE2","","rw,r","","" +"PUNPCKLQDQ xmm1, xmm2/m128","PUNPCKLQDQ xmm2/m128, xmm1","punpcklqdq xmm2/m128, xmm1","66 0F 6C /r","V","V","SSE2","","rw,r","","" +"PUNPCKLWD mm1, mm2/m32","PUNPCKLWL mm2/m32, mm1","punpcklwd mm2/m32, mm1","0F 61 /r","V","V","MMX","","rw,r","","" +"PUNPCKLWD xmm1, xmm2/m128","PUNPCKLWL xmm2/m128, xmm1","punpcklwd xmm2/m128, xmm1","66 0F 61 /r","V","V","SSE2","","rw,r","","" +"PUSHAD","PUSHAL","pushal","60","V","N.S.","","operand32","","","" +"PUSHA","PUSHAW","pushaw","60","V","N.S.","","operand16","","","" +"PUSHFD","PUSHFL","pushfl","9C","V","N.S.","","operand32","","","" +"PUSHFQ","PUSHFQ","pushfq","9C","N.S.","V","","default64","","","" +"PUSHF","PUSHFW","pushfw","9C","V","V","","operand16","","","" +"PUSH r/m32","PUSHL r/m32","pushl r/m32","FF /6","V","N.S.","","operand32","r","Y","32" +"PUSH r32op","PUSHL r32op","pushl r32op","50+rd","V","N.S.","","operand32","r","Y","32" +"PUSH r/m64","PUSHQ r/m64","pushq r/m64","FF /6","N.S.","V","","default64","r","Y","64" +"PUSH r64op","PUSHQ r64op","pushq r64op","50+ro","N.S.","V","","default64","r","Y","64" +"PUSH imm16","PUSHW imm16","pushw imm16","68 iw","V","V","","operand16","r","Y","" +"PUSH r/m16","PUSHW r/m16","pushw r/m16","FF /6","V","V","","operand16","r","Y","16" +"PUSH r16op","PUSHW r16op","pushw r16op","50+rw","V","V","","operand16","r","Y","16" +"PUSH CS","PUSHW/PUSHL/PUSHQ CS","pushw/pushl/pushq CS","0E","V","N.S.","","","r","Y","" +"PUSH DS","PUSHW/PUSHL/PUSHQ DS","pushw/pushl/pushq DS","1E","V","N.S.","","","r","Y","" +"PUSH ES","PUSHW/PUSHL/PUSHQ ES","pushw/pushl/pushq ES","06","V","N.S.","","","r","Y","" +"PUSH FS","PUSHW/PUSHL/PUSHQ FS","pushw/pushl/pushq FS","0F A0","V","V","","operand16","r","Y","" +"PUSH FS","PUSHW/PUSHL/PUSHQ FS","pushw/pushl/pushq FS","0F A0","N.S.","V","","default64","r","Y","" +"PUSH FS","PUSHW/PUSHL/PUSHQ FS","pushw/pushl/pushq FS","0F A0","V","N.S.","","operand32","r","Y","" +"PUSH GS","PUSHW/PUSHL/PUSHQ GS","pushw/pushl/pushq GS","0F A8","N.S.","V","","default64","r","Y","" +"PUSH GS","PUSHW/PUSHL/PUSHQ GS","pushw/pushl/pushq GS","0F A8","V","N.S.","","operand32","r","Y","" +"PUSH GS","PUSHW/PUSHL/PUSHQ GS","pushw/pushl/pushq GS","0F A8","V","V","","operand16","r","Y","" +"PUSH SS","PUSHW/PUSHL/PUSHQ SS","pushw/pushl/pushq SS","16","V","N.S.","","","r","Y","" +"PUSH imm8","PUSHW/PUSHL/PUSHQ imm8","pushw/pushl/pushq imm8","6A ib","V","N.S.","","operand32","r","Y","" +"PUSH imm8","PUSHW/PUSHL/PUSHQ imm8","pushw/pushl/pushq imm8","6A ib","N.S.","V","","default64","r","Y","" +"PUSH imm8","PUSHW/PUSHL/PUSHQ imm8","pushw/pushl/pushq imm8","6A ib","V","V","","operand16","r","Y","" +"PXOR mm1, mm2/m64","PXOR mm2/m64, mm1","pxor mm2/m64, mm1","0F EF /r","V","V","MMX","","rw,r","","" +"PXOR xmm1, xmm2/m128","PXOR xmm2/m128, xmm1","pxor xmm2/m128, xmm1","66 0F EF /r","V","V","SSE2","","rw,r","","" +"RCL r/m8, 1","RCLB 1, r/m8","rclb 1, r/m8","D0 /2","V","V","","","rw,r","Y","8" +"RCL r/m8, 1","RCLB 1, r/m8","rclb 1, r/m8","REX D0 /2","N.E.","V","","pseudo64","w,r","Y","8" +"RCL r/m8, CL","RCLB CL, r/m8","rclb CL, r/m8","D2 /2","V","V","","","rw,r","Y","8" +"RCL r/m8, CL","RCLB CL, r/m8","rclb CL, r/m8","REX D2 /2","N.E.","V","","pseudo64","w,r","Y","8" +"RCL r/m8, imm8","RCLB imm8, r/m8","rclb imm8, r/m8","REX C0 /2 ib","N.E.","V","","pseudo64","w,r","Y","8" +"RCL r/m8, imm8u","RCLB imm8u, r/m8","rclb imm8u, r/m8","C0 /2 ib","V","V","","","rw,r","Y","8" +"RCL r/m32, 1","RCLL 1, r/m32","rcll 1, r/m32","D1 /2","V","V","","operand32","rw,r","Y","32" +"RCL r/m32, CL","RCLL CL, r/m32","rcll CL, r/m32","D3 /2","V","V","","operand32","rw,r","Y","32" +"RCL r/m32, imm8u","RCLL imm8u, r/m32","rcll imm8u, r/m32","C1 /2 ib","V","V","","operand32","rw,r","Y","32" +"RCL r/m64, 1","RCLQ 1, r/m64","rclq 1, r/m64","REX.W D1 /2","N.S.","V","","","rw,r","Y","64" +"RCL r/m64, CL","RCLQ CL, r/m64","rclq CL, r/m64","REX.W D3 /2","N.S.","V","","","rw,r","Y","64" +"RCL r/m64, imm8u","RCLQ imm8u, r/m64","rclq imm8u, r/m64","REX.W C1 /2 ib","N.S.","V","","","rw,r","Y","64" +"RCL r/m16, 1","RCLW 1, r/m16","rclw 1, r/m16","D1 /2","V","V","","operand16","rw,r","Y","16" +"RCL r/m16, CL","RCLW CL, r/m16","rclw CL, r/m16","D3 /2","V","V","","operand16","rw,r","Y","16" +"RCL r/m16, imm8u","RCLW imm8u, r/m16","rclw imm8u, r/m16","C1 /2 ib","V","V","","operand16","rw,r","Y","16" +"RCPPS xmm1, xmm2/m128","RCPPS xmm2/m128, xmm1","rcpps xmm2/m128, xmm1","0F 53 /r","V","V","SSE","","w,r","","" +"RCPSS xmm1, xmm2/m32","RCPSS xmm2/m32, xmm1","rcpss xmm2/m32, xmm1","F3 0F 53 /r","V","V","SSE","","w,r","","" +"RCR r/m8, 1","RCRB 1, r/m8","rcrb 1, r/m8","D0 /3","V","V","","","rw,r","Y","8" +"RCR r/m8, 1","RCRB 1, r/m8","rcrb 1, r/m8","REX D0 /3","N.E.","V","","pseudo64","w,r","Y","8" +"RCR r/m8, CL","RCRB CL, r/m8","rcrb CL, r/m8","D2 /3","V","V","","","rw,r","Y","8" +"RCR r/m8, CL","RCRB CL, r/m8","rcrb CL, r/m8","REX D2 /3","N.E.","V","","pseudo64","w,r","Y","8" +"RCR r/m8, imm8","RCRB imm8, r/m8","rcrb imm8, r/m8","REX C0 /3 ib","N.E.","V","","pseudo64","w,r","Y","8" +"RCR r/m8, imm8u","RCRB imm8u, r/m8","rcrb imm8u, r/m8","C0 /3 ib","V","V","","","rw,r","Y","8" +"RCR r/m32, 1","RCRL 1, r/m32","rcrl 1, r/m32","D1 /3","V","V","","operand32","rw,r","Y","32" +"RCR r/m32, CL","RCRL CL, r/m32","rcrl CL, r/m32","D3 /3","V","V","","operand32","rw,r","Y","32" +"RCR r/m32, imm8u","RCRL imm8u, r/m32","rcrl imm8u, r/m32","C1 /3 ib","V","V","","operand32","rw,r","Y","32" +"RCR r/m64, 1","RCRQ 1, r/m64","rcrq 1, r/m64","REX.W D1 /3","N.S.","V","","","rw,r","Y","64" +"RCR r/m64, CL","RCRQ CL, r/m64","rcrq CL, r/m64","REX.W D3 /3","N.S.","V","","","rw,r","Y","64" +"RCR r/m64, imm8u","RCRQ imm8u, r/m64","rcrq imm8u, r/m64","REX.W C1 /3 ib","N.S.","V","","","rw,r","Y","64" +"RCR r/m16, 1","RCRW 1, r/m16","rcrw 1, r/m16","D1 /3","V","V","","operand16","rw,r","Y","16" +"RCR r/m16, CL","RCRW CL, r/m16","rcrw CL, r/m16","D3 /3","V","V","","operand16","rw,r","Y","16" +"RCR r/m16, imm8u","RCRW imm8u, r/m16","rcrw imm8u, r/m16","C1 /3 ib","V","V","","operand16","rw,r","Y","16" +"RDFSBASE rmr32","RDFSBASEL rmr32","rdfsbase rmr32","F3 0F AE /0","N.S.","V","FSGSBASE","modrm_regonly,operand16,operand32","w","Y","32" +"RDFSBASE rmr64","RDFSBASEQ rmr64","rdfsbase rmr64","F3 REX.W 0F AE /0","N.S.","V","FSGSBASE","modrm_regonly","w","Y","64" +"RDGSBASE rmr32","RDGSBASEL rmr32","rdgsbase rmr32","F3 0F AE /1","N.S.","V","FSGSBASE","modrm_regonly,operand16,operand32","w","Y","32" +"RDGSBASE rmr64","RDGSBASEQ rmr64","rdgsbase rmr64","F3 REX.W 0F AE /1","N.S.","V","FSGSBASE","modrm_regonly","w","Y","64" +"RDMSR","RDMSR","rdmsr","0F 32","V","V","Pentium","","","","" +"RDPKRU","RDPKRU","rdpkru","0F 01 EE","V","V","PKU","","","","" +"RDPMC","RDPMC","rdpmc","0F 33","V","V","","","","","" +"RDRAND rmr32","RDRANDL rmr32","rdrand rmr32","0F C7 /6","V","V","RDRAND","modrm_regonly,operand32","w","Y","32" +"RDRAND rmr64","RDRANDQ rmr64","rdrand rmr64","REX.W 0F C7 /6","N.S.","V","RDRAND","modrm_regonly","w","Y","64" +"RDRAND rmr16","RDRANDW rmr16","rdrand rmr16","0F C7 /6","V","V","RDRAND","modrm_regonly,operand16","w","Y","16" +"RDSEED rmr32","RDSEEDL rmr32","rdseed rmr32","0F C7 /7","V","V","RDSEED","modrm_regonly,operand32","w","Y","32" +"RDSEED rmr64","RDSEEDQ rmr64","rdseed rmr64","REX.W 0F C7 /7","N.S.","V","RDSEED","modrm_regonly","w","Y","64" +"RDSEED rmr16","RDSEEDW rmr16","rdseed rmr16","0F C7 /7","V","V","RDSEED","modrm_regonly,operand16","w","Y","16" +"RDSSPD rmr32","RDSSPD rmr32","rdsspd rmr32","F3 0F 1E /1","V","V","CET","modrm_regonly,operand16,operand32","w","","" +"RDSSPQ rmr64","RDSSPQ rmr64","rdsspq rmr64","F3 REX.W 0F 1E /1","N.S.","V","CET","modrm_regonly","w","","" +"RDTSC","RDTSC","rdtsc","0F 31","V","V","Pentium","","","","" +"RDTSCP","RDTSCP","rdtscp","0F 01 F9","V","V","RDTSCP","","","","" +"RET_FAR","RETFW/RETFL/RETFQ","lretw/lretl/lretl","CB","V","V","","","","","" +"RET_FAR imm16u","RETFW/RETFL/RETFQ imm16u","lretw/lretl/lretl imm16u","CA iw","V","V","","","r","","" +"RET","RETW/RETL/RETQ","retw/retl/retq","C3","N.S.","V","","default64","","","" +"RET","RETW/RETL/RETQ","retw/retl/retq","C3","V","N.S.","","","","","" +"RET imm16u","RETW/RETL/RETQ imm16u","retw/retl/retq imm16u","C2 iw","N.S.","V","","default64","r","","" +"RET imm16u","RETW/RETL/RETQ imm16u","retw/retl/retq imm16u","C2 iw","V","N.S.","","","r","","" +"ROL r/m8, 1","ROLB 1, r/m8","rolb 1, r/m8","D0 /0","V","V","","","rw,r","Y","8" +"ROL r/m8, 1","ROLB 1, r/m8","rolb 1, r/m8","REX D0 /0","N.E.","V","","pseudo64","w,r","Y","8" +"ROL r/m8, CL","ROLB CL, r/m8","rolb CL, r/m8","D2 /0","V","V","","","rw,r","Y","8" +"ROL r/m8, CL","ROLB CL, r/m8","rolb CL, r/m8","REX D2 /0","N.E.","V","","pseudo64","w,r","Y","8" +"ROL r/m8, imm8","ROLB imm8, r/m8","rolb imm8, r/m8","REX C0 /0 ib","N.E.","V","","pseudo64","w,r","Y","8" +"ROL r/m8, imm8u","ROLB imm8u, r/m8","rolb imm8u, r/m8","C0 /0 ib","V","V","","","rw,r","Y","8" +"ROL r/m32, 1","ROLL 1, r/m32","roll 1, r/m32","D1 /0","V","V","","operand32","rw,r","Y","32" +"ROL r/m32, CL","ROLL CL, r/m32","roll CL, r/m32","D3 /0","V","V","","operand32","rw,r","Y","32" +"ROL r/m32, imm8u","ROLL imm8u, r/m32","roll imm8u, r/m32","C1 /0 ib","V","V","","operand32","rw,r","Y","32" +"ROL r/m64, 1","ROLQ 1, r/m64","rolq 1, r/m64","REX.W D1 /0","N.S.","V","","","rw,r","Y","64" +"ROL r/m64, CL","ROLQ CL, r/m64","rolq CL, r/m64","REX.W D3 /0","N.S.","V","","","rw,r","Y","64" +"ROL r/m64, imm8u","ROLQ imm8u, r/m64","rolq imm8u, r/m64","REX.W C1 /0 ib","N.S.","V","","","rw,r","Y","64" +"ROL r/m16, 1","ROLW 1, r/m16","rolw 1, r/m16","D1 /0","V","V","","operand16","rw,r","Y","16" +"ROL r/m16, CL","ROLW CL, r/m16","rolw CL, r/m16","D3 /0","V","V","","operand16","rw,r","Y","16" +"ROL r/m16, imm8u","ROLW imm8u, r/m16","rolw imm8u, r/m16","C1 /0 ib","V","V","","operand16","rw,r","Y","16" +"ROR r/m8, 1","RORB 1, r/m8","rorb 1, r/m8","D0 /1","V","V","","","rw,r","Y","8" +"ROR r/m8, 1","RORB 1, r/m8","rorb 1, r/m8","REX D0 /1","N.E.","V","","pseudo64","w,r","Y","8" +"ROR r/m8, CL","RORB CL, r/m8","rorb CL, r/m8","D2 /1","V","V","","","rw,r","Y","8" +"ROR r/m8, CL","RORB CL, r/m8","rorb CL, r/m8","REX D2 /1","N.E.","V","","pseudo64","w,r","Y","8" +"ROR r/m8, imm8","RORB imm8, r/m8","rorb imm8, r/m8","REX C0 /1 ib","N.E.","V","","pseudo64","w,r","Y","8" +"ROR r/m8, imm8u","RORB imm8u, r/m8","rorb imm8u, r/m8","C0 /1 ib","V","V","","","rw,r","Y","8" +"ROR r/m32, 1","RORL 1, r/m32","rorl 1, r/m32","D1 /1","V","V","","operand32","rw,r","Y","32" +"ROR r/m32, CL","RORL CL, r/m32","rorl CL, r/m32","D3 /1","V","V","","operand32","rw,r","Y","32" +"ROR r/m32, imm8u","RORL imm8u, r/m32","rorl imm8u, r/m32","C1 /1 ib","V","V","","operand32","rw,r","Y","32" +"ROR r/m64, 1","RORQ 1, r/m64","rorq 1, r/m64","REX.W D1 /1","N.S.","V","","","rw,r","Y","64" +"ROR r/m64, CL","RORQ CL, r/m64","rorq CL, r/m64","REX.W D3 /1","N.S.","V","","","rw,r","Y","64" +"ROR r/m64, imm8u","RORQ imm8u, r/m64","rorq imm8u, r/m64","REX.W C1 /1 ib","N.S.","V","","","rw,r","Y","64" +"ROR r/m16, 1","RORW 1, r/m16","rorw 1, r/m16","D1 /1","V","V","","operand16","rw,r","Y","16" +"ROR r/m16, CL","RORW CL, r/m16","rorw CL, r/m16","D3 /1","V","V","","operand16","rw,r","Y","16" +"ROR r/m16, imm8u","RORW imm8u, r/m16","rorw imm8u, r/m16","C1 /1 ib","V","V","","operand16","rw,r","Y","16" +"RORX r32, r/m32, imm8u","RORXL imm8u, r/m32, r32","rorxl imm8u, r/m32, r32","VEX.128.F2.0F3A.W0 F0 /r ib","V","V","BMI2","","w,r,r","Y","32" +"RORX r64, r/m64, imm8u","RORXQ imm8u, r/m64, r64","rorxq imm8u, r/m64, r64","VEX.128.F2.0F3A.W1 F0 /r ib","N.S.","V","BMI2","","w,r,r","Y","64" +"ROUNDPD xmm1, xmm2/m128, imm8u","ROUNDPD imm8u, xmm2/m128, xmm1","roundpd imm8u, xmm2/m128, xmm1","66 0F 3A 09 /r ib","V","V","SSE4_1","","w,r,r","","" +"ROUNDPS xmm1, xmm2/m128, imm8u","ROUNDPS imm8u, xmm2/m128, xmm1","roundps imm8u, xmm2/m128, xmm1","66 0F 3A 08 /r ib","V","V","SSE4_1","","w,r,r","","" +"ROUNDSD xmm1, xmm2/m64, imm8u","ROUNDSD imm8u, xmm2/m64, xmm1","roundsd imm8u, xmm2/m64, xmm1","66 0F 3A 0B /r ib","V","V","SSE4_1","","w,r,r","","" +"ROUNDSS xmm1, xmm2/m32, imm8u","ROUNDSS imm8u, xmm2/m32, xmm1","roundss imm8u, xmm2/m32, xmm1","66 0F 3A 0A /r ib","V","V","SSE4_1","","w,r,r","","" +"RSM","RSM","rsm","0F AA","V","V","","","","","" +"RSQRTPS xmm1, xmm2/m128","RSQRTPS xmm2/m128, xmm1","rsqrtps xmm2/m128, xmm1","0F 52 /r","V","V","SSE","","w,r","","" +"RSQRTSS xmm1, xmm2/m32","RSQRTSS xmm2/m32, xmm1","rsqrtss xmm2/m32, xmm1","F3 0F 52 /r","V","V","SSE","","w,r","","" +"RSTORSSP m64","RSTORSSP m64","rstorssp m64","F3 0F 01 /5","V","V","CET","modrm_memonly","rw","","" +"SAHF","SAHF","sahf","9E","V","V","LAHFSAHF","","","","" +"SAL r/m8, 1","SALB 1, r/m8","salb 1, r/m8","D0 /4","V","V","","pseudo","rw,r","Y","8" +"SAL r/m8, 1","SALB 1, r/m8","salb 1, r/m8","REX D0 /4","N.E.","V","","pseudo","rw,r","Y","8" +"SAL r/m8, CL","SALB CL, r/m8","salb CL, r/m8","D2 /4","V","V","","pseudo","rw,r","Y","8" +"SAL r/m8, CL","SALB CL, r/m8","salb CL, r/m8","REX D2 /4","N.E.","V","","pseudo","rw,r","Y","8" +"SAL r/m8, imm8","SALB imm8, r/m8","salb imm8, r/m8","C0 /4 ib","V","V","","pseudo","rw,r","Y","8" +"SAL r/m8, imm8","SALB imm8, r/m8","salb imm8, r/m8","REX C0 /4 ib","N.E.","V","","pseudo","rw,r","Y","8" +"SALC","SALC","salc","D6","V","N.S.","","","","","" +"SAL r/m32, 1","SALL 1, r/m32","sall 1, r/m32","D1 /4","V","V","","operand32,pseudo","rw,r","Y","32" +"SAL r/m32, CL","SALL CL, r/m32","sall CL, r/m32","D3 /4","V","V","","operand32,pseudo","rw,r","Y","32" +"SAL r/m32, imm8","SALL imm8, r/m32","sall imm8, r/m32","C1 /4 ib","V","V","","operand32,pseudo","rw,r","Y","32" +"SAL r/m64, 1","SALQ 1, r/m64","salq 1, r/m64","REX.W D1 /4","N.E.","V","","pseudo","rw,r","Y","64" +"SAL r/m64, CL","SALQ CL, r/m64","salq CL, r/m64","REX.W D3 /4","N.E.","V","","pseudo","rw,r","Y","64" +"SAL r/m64, imm8","SALQ imm8, r/m64","salq imm8, r/m64","REX.W C1 /4 ib","N.E.","V","","pseudo","rw,r","Y","64" +"SAL r/m16, 1","SALW 1, r/m16","salw 1, r/m16","D1 /4","V","V","","operand16,pseudo","rw,r","Y","16" +"SAL r/m16, CL","SALW CL, r/m16","salw CL, r/m16","D3 /4","V","V","","operand16,pseudo","rw,r","Y","16" +"SAL r/m16, imm8","SALW imm8, r/m16","salw imm8, r/m16","C1 /4 ib","V","V","","operand16,pseudo","rw,r","Y","16" +"SAR r/m8, 1","SARB 1, r/m8","sarb 1, r/m8","D0 /7","V","V","","","rw,r","Y","8" +"SAR r/m8, 1","SARB 1, r/m8","sarb 1, r/m8","REX D0 /7","N.E.","V","","pseudo64","rw,r","Y","8" +"SAR r/m8, CL","SARB CL, r/m8","sarb CL, r/m8","D2 /7","V","V","","","rw,r","Y","8" +"SAR r/m8, CL","SARB CL, r/m8","sarb CL, r/m8","REX D2 /7","N.E.","V","","pseudo64","rw,r","Y","8" +"SAR r/m8, imm8","SARB imm8, r/m8","sarb imm8, r/m8","REX C0 /7 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"SAR r/m8, imm8u","SARB imm8u, r/m8","sarb imm8u, r/m8","C0 /7 ib","V","V","","","rw,r","Y","8" +"SAR r/m32, 1","SARL 1, r/m32","sarl 1, r/m32","D1 /7","V","V","","operand32","rw,r","Y","32" +"SAR r/m32, CL","SARL CL, r/m32","sarl CL, r/m32","D3 /7","V","V","","operand32","rw,r","Y","32" +"SAR r/m32, imm8u","SARL imm8u, r/m32","sarl imm8u, r/m32","C1 /7 ib","V","V","","operand32","rw,r","Y","32" +"SAR r/m64, 1","SARQ 1, r/m64","sarq 1, r/m64","REX.W D1 /7","N.S.","V","","","rw,r","Y","64" +"SAR r/m64, CL","SARQ CL, r/m64","sarq CL, r/m64","REX.W D3 /7","N.S.","V","","","rw,r","Y","64" +"SAR r/m64, imm8u","SARQ imm8u, r/m64","sarq imm8u, r/m64","REX.W C1 /7 ib","N.S.","V","","","rw,r","Y","64" +"SAR r/m16, 1","SARW 1, r/m16","sarw 1, r/m16","D1 /7","V","V","","operand16","rw,r","Y","16" +"SAR r/m16, CL","SARW CL, r/m16","sarw CL, r/m16","D3 /7","V","V","","operand16","rw,r","Y","16" +"SAR r/m16, imm8u","SARW imm8u, r/m16","sarw imm8u, r/m16","C1 /7 ib","V","V","","operand16","rw,r","Y","16" +"SARX r32, r/m32, r32V","SARXL r32V, r/m32, r32","sarxl r32V, r/m32, r32","VEX.NDS.128.F3.0F38.W0 F7 /r","V","V","BMI2","","w,r,r","Y","32" +"SARX r64, r/m64, r64V","SARXQ r64V, r/m64, r64","sarxq r64V, r/m64, r64","VEX.NDS.128.F3.0F38.W1 F7 /r","N.S.","V","BMI2","","w,r,r","Y","64" +"SAVESSP","SAVESSP","savessp","F3 0F 01 EA","V","V","CET","","","","" +"SBB AL, imm8","SBBB imm8, AL","sbbb imm8, AL","1C ib","V","V","","","rw,r","Y","8" +"SBB r/m8, imm8","SBBB imm8, r/m8","sbbb imm8, r/m8","80 /3 ib","V","V","","","rw,r","Y","8" +"SBB r/m8, imm8","SBBB imm8, r/m8","sbbb imm8, r/m8","82 /3 ib","V","N.S.","","","rw,r","Y","8" +"SBB r/m8, imm8","SBBB imm8, r/m8","sbbb imm8, r/m8","REX 80 /3 ib","N.E.","V","","pseudo64","w,r","Y","8" +"SBB r8, r/m8","SBBB r/m8, r8","sbbb r/m8, r8","1A /r","V","V","","","rw,r","Y","8" +"SBB r8, r/m8","SBBB r/m8, r8","sbbb r/m8, r8","REX 1A /r","N.E.","V","","pseudo64","w,r","Y","8" +"SBB r/m8, r8","SBBB r8, r/m8","sbbb r8, r/m8","18 /r","V","V","","","rw,r","Y","8" +"SBB r/m8, r8","SBBB r8, r/m8","sbbb r8, r/m8","REX 18 /r","N.E.","V","","pseudo64","w,r","Y","8" +"SBB EAX, imm32","SBBL imm32, EAX","sbbl imm32, EAX","1D id","V","V","","operand32","rw,r","Y","32" +"SBB r/m32, imm32","SBBL imm32, r/m32","sbbl imm32, r/m32","81 /3 id","V","V","","operand32","rw,r","Y","32" +"SBB r/m32, imm8","SBBL imm8, r/m32","sbbl imm8, r/m32","83 /3 ib","V","V","","operand32","rw,r","Y","32" +"SBB r32, r/m32","SBBL r/m32, r32","sbbl r/m32, r32","1B /r","V","V","","operand32","rw,r","Y","32" +"SBB r/m32, r32","SBBL r32, r/m32","sbbl r32, r/m32","19 /r","V","V","","operand32","rw,r","Y","32" +"SBB RAX, imm32","SBBQ imm32, RAX","sbbq imm32, RAX","REX.W 1D id","N.S.","V","","","rw,r","Y","64" +"SBB r/m64, imm32","SBBQ imm32, r/m64","sbbq imm32, r/m64","REX.W 81 /3 id","N.S.","V","","","rw,r","Y","64" +"SBB r/m64, imm8","SBBQ imm8, r/m64","sbbq imm8, r/m64","REX.W 83 /3 ib","N.S.","V","","","rw,r","Y","64" +"SBB r64, r/m64","SBBQ r/m64, r64","sbbq r/m64, r64","REX.W 1B /r","N.S.","V","","","rw,r","Y","64" +"SBB r/m64, r64","SBBQ r64, r/m64","sbbq r64, r/m64","REX.W 19 /r","N.S.","V","","","rw,r","Y","64" +"SBB AX, imm16","SBBW imm16, AX","sbbw imm16, AX","1D iw","V","V","","operand16","rw,r","Y","16" +"SBB r/m16, imm16","SBBW imm16, r/m16","sbbw imm16, r/m16","81 /3 iw","V","V","","operand16","rw,r","Y","16" +"SBB r/m16, imm8","SBBW imm8, r/m16","sbbw imm8, r/m16","83 /3 ib","V","V","","operand16","rw,r","Y","16" +"SBB r16, r/m16","SBBW r/m16, r16","sbbw r/m16, r16","1B /r","V","V","","operand16","rw,r","Y","16" +"SBB r/m16, r16","SBBW r16, r/m16","sbbw r16, r/m16","19 /r","V","V","","operand16","rw,r","Y","16" +"SCASB","SCASB","scasb","AE","V","V","","","","","" +"SCASD","SCASL","scasl","AF","V","V","","operand32","","","" +"SCASQ","SCASQ","scasq","REX.W AF","N.S.","V","","","","","" +"SCASW","SCASW","scasw","AF","V","V","","operand16","","","" +"SETAE r/m8","SETCC r/m8","setae r/m8","0F 93 /r","V","V","","","w","","" +"SETNB r/m8","SETCC r/m8","setnb r/m8","0F 93 /r","V","V","","pseudo","r","","" +"SETNC r/m8","SETCC r/m8","setnc r/m8","0F 93 /r","V","V","","pseudo","r","","" +"SETAE r/m8","SETCC r/m8","setae r/m8","REX 0F 93 /r","N.E.","V","","pseudo64","r","","" +"SETNB r/m8","SETCC r/m8","setnb r/m8","REX 0F 93 /r","N.E.","V","","pseudo","r","","" +"SETNC r/m8","SETCC r/m8","setnc r/m8","REX 0F 93 /r","N.E.","V","","pseudo","r","","" +"SETB r/m8","SETCS r/m8","setb r/m8","0F 92 /r","V","V","","","w","","" +"SETC r/m8","SETCS r/m8","setc r/m8","0F 92 /r","V","V","","pseudo","r","","" +"SETNAE r/m8","SETCS r/m8","setnae r/m8","0F 92 /r","V","V","","pseudo","r","","" +"SETB r/m8","SETCS r/m8","setb r/m8","REX 0F 92 /r","N.E.","V","","pseudo64","r","","" +"SETC r/m8","SETCS r/m8","setc r/m8","REX 0F 92 /r","N.E.","V","","pseudo","r","","" +"SETNAE r/m8","SETCS r/m8","setnae r/m8","REX 0F 92 /r","N.E.","V","","pseudo","r","","" +"SETE r/m8","SETEQ r/m8","sete r/m8","0F 94 /r","V","V","","","w","","" +"SETZ r/m8","SETEQ r/m8","setz r/m8","0F 94 /r","V","V","","pseudo","r","","" +"SETE r/m8","SETEQ r/m8","sete r/m8","REX 0F 94 /r","N.E.","V","","pseudo64","r","","" +"SETZ r/m8","SETEQ r/m8","setz r/m8","REX 0F 94 /r","N.E.","V","","pseudo","r","","" +"SETGE r/m8","SETGE r/m8","setge r/m8","0F 9D /r","V","V","","","w","","" +"SETNL r/m8","SETGE r/m8","setnl r/m8","0F 9D /r","V","V","","pseudo","r","","" +"SETGE r/m8","SETGE r/m8","setge r/m8","REX 0F 9D /r","N.E.","V","","pseudo64","r","","" +"SETNL r/m8","SETGE r/m8","setnl r/m8","REX 0F 9D /r","N.E.","V","","pseudo","r","","" +"SETG r/m8","SETGT r/m8","setg r/m8","0F 9F /r","V","V","","","w","","" +"SETNLE r/m8","SETGT r/m8","setnle r/m8","0F 9F /r","V","V","","pseudo","r","","" +"SETG r/m8","SETGT r/m8","setg r/m8","REX 0F 9F /r","N.E.","V","","pseudo64","r","","" +"SETNLE r/m8","SETGT r/m8","setnle r/m8","REX 0F 9F /r","N.E.","V","","pseudo","r","","" +"SETA r/m8","SETHI r/m8","seta r/m8","0F 97 /r","V","V","","","w","","" +"SETNBE r/m8","SETHI r/m8","setnbe r/m8","0F 97 /r","V","V","","pseudo","r","","" +"SETA r/m8","SETHI r/m8","seta r/m8","REX 0F 97 /r","N.E.","V","","pseudo64","r","","" +"SETNBE r/m8","SETHI r/m8","setnbe r/m8","REX 0F 97 /r","N.E.","V","","pseudo","r","","" +"SETLE r/m8","SETLE r/m8","setle r/m8","0F 9E /r","V","V","","","w","","" +"SETNG r/m8","SETLE r/m8","setng r/m8","0F 9E /r","V","V","","pseudo","r","","" +"SETLE r/m8","SETLE r/m8","setle r/m8","REX 0F 9E /r","N.E.","V","","pseudo64","r","","" +"SETNG r/m8","SETLE r/m8","setng r/m8","REX 0F 9E /r","N.E.","V","","pseudo","r","","" +"SETBE r/m8","SETLS r/m8","setbe r/m8","0F 96 /r","V","V","","","w","","" +"SETNA r/m8","SETLS r/m8","setna r/m8","0F 96 /r","V","V","","pseudo","r","","" +"SETBE r/m8","SETLS r/m8","setbe r/m8","REX 0F 96 /r","N.E.","V","","pseudo64","r","","" +"SETNA r/m8","SETLS r/m8","setna r/m8","REX 0F 96 /r","N.E.","V","","pseudo","r","","" +"SETL r/m8","SETLT r/m8","setl r/m8","0F 9C /r","V","V","","","w","","" +"SETNGE r/m8","SETLT r/m8","setnge r/m8","0F 9C /r","V","V","","pseudo","r","","" +"SETL r/m8","SETLT r/m8","setl r/m8","REX 0F 9C /r","N.E.","V","","pseudo64","r","","" +"SETNGE r/m8","SETLT r/m8","setnge r/m8","REX 0F 9C /r","N.E.","V","","pseudo","r","","" +"SETS r/m8","SETMI r/m8","sets r/m8","0F 98 /r","V","V","","","w","","" +"SETS r/m8","SETMI r/m8","sets r/m8","REX 0F 98 /r","N.E.","V","","pseudo64","r","","" +"SETNE r/m8","SETNE r/m8","setne r/m8","0F 95 /r","V","V","","","w","","" +"SETNZ r/m8","SETNE r/m8","setnz r/m8","0F 95 /r","V","V","","pseudo","r","","" +"SETNE r/m8","SETNE r/m8","setne r/m8","REX 0F 95 /r","N.E.","V","","pseudo64","r","","" +"SETNZ r/m8","SETNE r/m8","setnz r/m8","REX 0F 95 /r","N.E.","V","","pseudo","r","","" +"SETNO r/m8","SETOC r/m8","setno r/m8","0F 91 /r","V","V","","","w","","" +"SETNO r/m8","SETOC r/m8","setno r/m8","REX 0F 91 /r","N.E.","V","","pseudo64","r","","" +"SETO r/m8","SETOS r/m8","seto r/m8","0F 90 /r","V","V","","","w","","" +"SETO r/m8","SETOS r/m8","seto r/m8","REX 0F 90 /r","N.E.","V","","pseudo64","r","","" +"SETNP r/m8","SETPC r/m8","setnp r/m8","0F 9B /r","V","V","","","w","","" +"SETPO r/m8","SETPC r/m8","setpo r/m8","0F 9B /r","V","V","","pseudo","r","","" +"SETNP r/m8","SETPC r/m8","setnp r/m8","REX 0F 9B /r","N.E.","V","","pseudo64","r","","" +"SETPO r/m8","SETPC r/m8","setpo r/m8","REX 0F 9B /r","N.E.","V","","pseudo","r","","" +"SETNS r/m8","SETPL r/m8","setns r/m8","0F 99 /r","V","V","","","w","","" +"SETNS r/m8","SETPL r/m8","setns r/m8","REX 0F 99 /r","N.E.","V","","pseudo64","r","","" +"SETP r/m8","SETPS r/m8","setp r/m8","0F 9A /r","V","V","","","w","","" +"SETPE r/m8","SETPS r/m8","setpe r/m8","0F 9A /r","V","V","","pseudo","r","","" +"SETP r/m8","SETPS r/m8","setp r/m8","REX 0F 9A /r","N.E.","V","","pseudo64","r","","" +"SETPE r/m8","SETPS r/m8","setpe r/m8","REX 0F 9A /r","N.E.","V","","pseudo","r","","" +"SETSSBSY","SETSSBSY","setssbsy","F3 0F 01 E8","V","V","CET","","","","" +"SFENCE","SFENCE","sfence","0F AE /7","V","V","SSE","","","","" +"SGDT m16&32","SGDT m16&32","sgdt m16&32","0F 01 /0","V","N.S.","","modrm_memonly","w","","" +"SGDT m16&64","SGDT m16&64","sgdt m16&64","0F 01 /0","N.S.","V","","default64,modrm_memonly","w","","" +"SHA1MSG1 xmm1, xmm2/m128","SHA1MSG1 xmm2/m128, xmm1","sha1msg1 xmm2/m128, xmm1","0F 38 C9 /r","V","V","SHA","","rw,r","","" +"SHA1MSG2 xmm1, xmm2/m128","SHA1MSG2 xmm2/m128, xmm1","sha1msg2 xmm2/m128, xmm1","0F 38 CA /r","V","V","SHA","","rw,r","","" +"SHA1NEXTE xmm1, xmm2/m128","SHA1NEXTE xmm2/m128, xmm1","sha1nexte xmm2/m128, xmm1","0F 38 C8 /r","V","V","SHA","","rw,r","","" +"SHA1RNDS4 xmm1, xmm2/m128, imm8u:2","SHA1RNDS4 imm8u:2, xmm2/m128, xmm1","sha1rnds4 imm8u:2, xmm2/m128, xmm1","0F 3A CC /r ib","V","V","SHA","","rw,r,r","","" +"SHA256MSG1 xmm1, xmm2/m128","SHA256MSG1 xmm2/m128, xmm1","sha256msg1 xmm2/m128, xmm1","0F 38 CC /r","V","V","SHA","","rw,r","","" +"SHA256MSG2 xmm1, xmm2/m128","SHA256MSG2 xmm2/m128, xmm1","sha256msg2 xmm2/m128, xmm1","0F 38 CD /r","V","V","SHA","","rw,r","","" +"SHA256RNDS2 xmm1, xmm2/m128, ","SHA256RNDS2 , xmm2/m128, xmm1","sha256rnds2 , xmm2/m128, xmm1","0F 38 CB /r","V","V","SHA","","rw,r,r","","" +"SHL r/m8, 1","SHLB 1, r/m8","shlb 1, r/m8","D0 /4","V","V","","","rw,r","Y","8" +"SHL r/m8, 1","SHLB 1, r/m8","shlb 1, r/m8","D0 /6","V","V","","","rw,r","Y","8" +"SHL r/m8, 1","SHLB 1, r/m8","shlb 1, r/m8","REX D0 /4","N.E.","V","","pseudo64","rw,r","Y","8" +"SHL r/m8, CL","SHLB CL, r/m8","shlb CL, r/m8","D2 /4","V","V","","","rw,r","Y","8" +"SHL r/m8, CL","SHLB CL, r/m8","shlb CL, r/m8","D2 /6","V","V","","","rw,r","Y","8" +"SHL r/m8, CL","SHLB CL, r/m8","shlb CL, r/m8","REX D2 /4","N.E.","V","","pseudo64","rw,r","Y","8" +"SHL r/m8, imm8","SHLB imm8, r/m8","shlb imm8, r/m8","REX C0 /4 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"SHL r/m8, imm8u","SHLB imm8u, r/m8","shlb imm8u, r/m8","C0 /4 ib","V","V","","","rw,r","Y","8" +"SHL r/m8, imm8u","SHLB imm8u, r/m8","shlb imm8u, r/m8","C0 /6 ib","V","V","","","rw,r","Y","8" +"SHL r/m32, 1","SHLL 1, r/m32","shll 1, r/m32","D1 /4","V","V","","operand32","rw,r","Y","32" +"SHL r/m32, 1","SHLL 1, r/m32","shll 1, r/m32","D1 /6","V","V","","operand32","rw,r","Y","32" +"SHL r/m32, CL","SHLL CL, r/m32","shll CL, r/m32","D3 /4","V","V","","operand32","rw,r","Y","32" +"SHL r/m32, CL","SHLL CL, r/m32","shll CL, r/m32","D3 /6","V","V","","operand32","rw,r","Y","32" +"SHLD r/m32, r32, CL","SHLL CL, r32, r/m32","shldl CL, r32, r/m32","0F A5 /r","V","V","","operand32","rw,r,r","Y","32" +"SHL r/m32, imm8u","SHLL imm8u, r/m32","shll imm8u, r/m32","C1 /4 ib","V","V","","operand32","rw,r","Y","32" +"SHL r/m32, imm8u","SHLL imm8u, r/m32","shll imm8u, r/m32","C1 /6 ib","V","V","","operand32","rw,r","Y","32" +"SHLD r/m32, r32, imm8u","SHLL imm8u, r32, r/m32","shldl imm8u, r32, r/m32","0F A4 /r ib","V","V","","operand32","rw,r,r","Y","32" +"SHL r/m64, 1","SHLQ 1, r/m64","shlq 1, r/m64","REX.W D1 /4","N.S.","V","","","rw,r","Y","64" +"SHL r/m64, 1","SHLQ 1, r/m64","shlq 1, r/m64","REX.W D1 /6","N.S.","V","","","rw,r","Y","64" +"SHL r/m64, CL","SHLQ CL, r/m64","shlq CL, r/m64","REX.W D3 /4","N.S.","V","","","rw,r","Y","64" +"SHL r/m64, CL","SHLQ CL, r/m64","shlq CL, r/m64","REX.W D3 /6","N.S.","V","","","rw,r","Y","64" +"SHLD r/m64, r64, CL","SHLQ CL, r64, r/m64","shldq CL, r64, r/m64","REX.W 0F A5 /r","N.S.","V","","","rw,r,r","Y","64" +"SHL r/m64, imm8u","SHLQ imm8u, r/m64","shlq imm8u, r/m64","REX.W C1 /4 ib","N.S.","V","","","rw,r","Y","64" +"SHL r/m64, imm8u","SHLQ imm8u, r/m64","shlq imm8u, r/m64","REX.W C1 /6 ib","N.S.","V","","","rw,r","Y","64" +"SHLD r/m64, r64, imm8u","SHLQ imm8u, r64, r/m64","shldq imm8u, r64, r/m64","REX.W 0F A4 /r ib","N.S.","V","","","rw,r,r","Y","64" +"SHL r/m16, 1","SHLW 1, r/m16","shlw 1, r/m16","D1 /4","V","V","","operand16","rw,r","Y","16" +"SHL r/m16, 1","SHLW 1, r/m16","shlw 1, r/m16","D1 /6","V","V","","operand16","rw,r","Y","16" +"SHL r/m16, CL","SHLW CL, r/m16","shlw CL, r/m16","D3 /4","V","V","","operand16","rw,r","Y","16" +"SHL r/m16, CL","SHLW CL, r/m16","shlw CL, r/m16","D3 /6","V","V","","operand16","rw,r","Y","16" +"SHLD r/m16, r16, CL","SHLW CL, r16, r/m16","shldw CL, r16, r/m16","0F A5 /r","V","V","","operand16","rw,r,r","Y","16" +"SHL r/m16, imm8u","SHLW imm8u, r/m16","shlw imm8u, r/m16","C1 /4 ib","V","V","","operand16","rw,r","Y","16" +"SHL r/m16, imm8u","SHLW imm8u, r/m16","shlw imm8u, r/m16","C1 /6 ib","V","V","","operand16","rw,r","Y","16" +"SHLD r/m16, r16, imm8u","SHLW imm8u, r16, r/m16","shldw imm8u, r16, r/m16","0F A4 /r ib","V","V","","operand16","rw,r,r","Y","16" +"SHLX r32, r/m32, r32V","SHLXL r32V, r/m32, r32","shlxl r32V, r/m32, r32","VEX.NDS.128.66.0F38.W0 F7 /r","V","V","BMI2","","w,r,r","Y","32" +"SHLX r64, r/m64, r64V","SHLXQ r64V, r/m64, r64","shlxq r64V, r/m64, r64","VEX.NDS.128.66.0F38.W1 F7 /r","N.S.","V","BMI2","","w,r,r","Y","64" +"SHR r/m8, 1","SHRB 1, r/m8","shrb 1, r/m8","D0 /5","V","V","","","rw,r","Y","8" +"SHR r/m8, 1","SHRB 1, r/m8","shrb 1, r/m8","REX D0 /5","N.E.","V","","pseudo64","rw,r","Y","8" +"SHR r/m8, CL","SHRB CL, r/m8","shrb CL, r/m8","D2 /5","V","V","","","rw,r","Y","8" +"SHR r/m8, CL","SHRB CL, r/m8","shrb CL, r/m8","REX D2 /5","N.E.","V","","pseudo64","rw,r","Y","8" +"SHR r/m8, imm8","SHRB imm8, r/m8","shrb imm8, r/m8","REX C0 /5 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"SHR r/m8, imm8u","SHRB imm8u, r/m8","shrb imm8u, r/m8","C0 /5 ib","V","V","","","rw,r","Y","8" +"SHR r/m32, 1","SHRL 1, r/m32","shrl 1, r/m32","D1 /5","V","V","","operand32","rw,r","Y","32" +"SHR r/m32, CL","SHRL CL, r/m32","shrl CL, r/m32","D3 /5","V","V","","operand32","rw,r","Y","32" +"SHRD r/m32, r32, CL","SHRL CL, r32, r/m32","shrdl CL, r32, r/m32","0F AD /r","V","V","","operand32","rw,r,r","Y","32" +"SHR r/m32, imm8u","SHRL imm8u, r/m32","shrl imm8u, r/m32","C1 /5 ib","V","V","","operand32","rw,r","Y","32" +"SHRD r/m32, r32, imm8u","SHRL imm8u, r32, r/m32","shrdl imm8u, r32, r/m32","0F AC /r ib","V","V","","operand32","rw,r,r","Y","32" +"SHR r/m64, 1","SHRQ 1, r/m64","shrq 1, r/m64","REX.W D1 /5","N.S.","V","","","rw,r","Y","64" +"SHR r/m64, CL","SHRQ CL, r/m64","shrq CL, r/m64","REX.W D3 /5","N.S.","V","","","rw,r","Y","64" +"SHRD r/m64, r64, CL","SHRQ CL, r64, r/m64","shrdq CL, r64, r/m64","REX.W 0F AD /r","N.S.","V","","","rw,r,r","Y","64" +"SHR r/m64, imm8u","SHRQ imm8u, r/m64","shrq imm8u, r/m64","REX.W C1 /5 ib","N.S.","V","","","rw,r","Y","64" +"SHRD r/m64, r64, imm8u","SHRQ imm8u, r64, r/m64","shrdq imm8u, r64, r/m64","REX.W 0F AC /r ib","N.S.","V","","","rw,r,r","Y","64" +"SHR r/m16, 1","SHRW 1, r/m16","shrw 1, r/m16","D1 /5","V","V","","operand16","rw,r","Y","16" +"SHR r/m16, CL","SHRW CL, r/m16","shrw CL, r/m16","D3 /5","V","V","","operand16","rw,r","Y","16" +"SHRD r/m16, r16, CL","SHRW CL, r16, r/m16","shrdw CL, r16, r/m16","0F AD /r","V","V","","operand16","rw,r,r","Y","16" +"SHR r/m16, imm8u","SHRW imm8u, r/m16","shrw imm8u, r/m16","C1 /5 ib","V","V","","operand16","rw,r","Y","16" +"SHRD r/m16, r16, imm8u","SHRW imm8u, r16, r/m16","shrdw imm8u, r16, r/m16","0F AC /r ib","V","V","","operand16","rw,r,r","Y","16" +"SHRX r32, r/m32, r32V","SHRXL r32V, r/m32, r32","shrxl r32V, r/m32, r32","VEX.NDS.128.F2.0F38.W0 F7 /r","V","V","BMI2","","w,r,r","Y","32" +"SHRX r64, r/m64, r64V","SHRXQ r64V, r/m64, r64","shrxq r64V, r/m64, r64","VEX.NDS.128.F2.0F38.W1 F7 /r","N.S.","V","BMI2","","w,r,r","Y","64" +"SHUFPD xmm1, xmm2/m128, imm8u","SHUFPD imm8u, xmm2/m128, xmm1","shufpd imm8u, xmm2/m128, xmm1","66 0F C6 /r ib","V","V","SSE2","","rw,r,r","","" +"SHUFPS xmm1, xmm2/m128, imm8u","SHUFPS imm8u, xmm2/m128, xmm1","shufps imm8u, xmm2/m128, xmm1","0F C6 /r ib","V","V","SSE","","rw,r,r","","" +"SIDT m16&32","SIDT m16&32","sidt m16&32","0F 01 /1","V","N.S.","","modrm_memonly","w","","" +"SIDT m16&64","SIDT m16&64","sidt m16&64","0F 01 /1","N.S.","V","","default64,modrm_memonly","w","","" +"SKINIT EAX","SKINIT EAX","skinit EAX","0F 01 DE","V","V","SVM","amd,modrm_regonly","r","","" +"SLDT r/m16","SLDTW r/m16","sldtw r/m16","0F 00 /0","V","V","","operand16","w","Y","16" +"SLDT r32/m16","SLDT{L/W} r32/m16","sldt{l/w} r32/m16","0F 00 /0","V","V","","operand32","w","Y","" +"SLDT r64/m16","SLDT{Q/W} r64/m16","sldt{q/w} r64/m16","REX.W 0F 00 /0","N.S.","V","","","w","Y","" +"SLWPCB rmr32","SLWPCBL rmr32","slwpcbl rmr32","XOP.128.09.W0 12 /1","V","V","XOP","amd,modrm_regonly,operand16,operand32","w","Y","32" +"SLWPCB rmr64","SLWPCBQ rmr64","slwpcbq rmr64","XOP.128.09.W0 12 /1","N.S.","V","XOP","amd,modrm_regonly,operand64","w","Y","64" +"SMSW r/m16","SMSWW r/m16","smsww r/m16","0F 01 /4","V","V","","operand16","w","Y","16" +"SMSW r32/m16","SMSW{L/W} r32/m16","smsw{l/w} r32/m16","0F 01 /4","V","V","","operand32","w","Y","" +"SMSW r64/m16","SMSW{Q/W} r64/m16","smsw{q/w} r64/m16","REX.W 0F 01 /4","N.S.","V","","","w","Y","" +"SQRTPD xmm1, xmm2/m128","SQRTPD xmm2/m128, xmm1","sqrtpd xmm2/m128, xmm1","66 0F 51 /r","V","V","SSE2","","w,r","","" +"SQRTPS xmm1, xmm2/m128","SQRTPS xmm2/m128, xmm1","sqrtps xmm2/m128, xmm1","0F 51 /r","V","V","SSE","","w,r","","" +"SQRTSD xmm1, xmm2/m64","SQRTSD xmm2/m64, xmm1","sqrtsd xmm2/m64, xmm1","F2 0F 51 /r","V","V","SSE2","","w,r","","" +"SQRTSS xmm1, xmm2/m32","SQRTSS xmm2/m32, xmm1","sqrtss xmm2/m32, xmm1","F3 0F 51 /r","V","V","SSE","","w,r","","" +"STAC","STAC","stac","0F 01 CB","V","V","","","","","" +"STC","STC","stc","F9","V","V","","","","","" +"STD","STD","std","FD","V","V","","","","","" +"STGI","STGI","stgi","0F 01 DC","V","V","SVM","amd","","","" +"STI","STI","sti","FB","V","V","","","","","" +"STMXCSR m32","STMXCSR m32","stmxcsr m32","0F AE /3","V","V","SSE","modrm_memonly","w","","" +"STOSB","STOSB","stosb","AA","V","V","","","","","" +"STOSD","STOSL","stosl","AB","V","V","","operand32","","","" +"STOSQ","STOSQ","stosq","REX.W AB","N.S.","V","","","","","" +"STOSW","STOSW","stosw","AB","V","V","","operand16","","","" +"STR r/m16","STRW r/m16","strw r/m16","0F 00 /1","V","V","","operand16","w","Y","16" +"STR r32/m16","STR{L/W} r32/m16","str{l/w} r32/m16","0F 00 /1","V","V","","operand32","w","Y","" +"STR r64/m16","STR{Q/W} r64/m16","str{q/w} r64/m16","REX.W 0F 00 /1","N.S.","V","","","w","Y","" +"SUB AL, imm8","SUBB imm8, AL","subb imm8, AL","2C ib","V","V","","","rw,r","Y","8" +"SUB r/m8, imm8","SUBB imm8, r/m8","subb imm8, r/m8","80 /5 ib","V","V","","","rw,r","Y","8" +"SUB r/m8, imm8","SUBB imm8, r/m8","subb imm8, r/m8","82 /5 ib","V","N.S.","","","rw,r","Y","8" +"SUB r/m8, imm8","SUBB imm8, r/m8","subb imm8, r/m8","REX 80 /5 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"SUB r8, r/m8","SUBB r/m8, r8","subb r/m8, r8","2A /r","V","V","","","rw,r","Y","8" +"SUB r8, r/m8","SUBB r/m8, r8","subb r/m8, r8","REX 2A /r","N.E.","V","","pseudo64","rw,r","Y","8" +"SUB r/m8, r8","SUBB r8, r/m8","subb r8, r/m8","28 /r","V","V","","","rw,r","Y","8" +"SUB r/m8, r8","SUBB r8, r/m8","subb r8, r/m8","REX 28 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"SUB EAX, imm32","SUBL imm32, EAX","subl imm32, EAX","2D id","V","V","","operand32","rw,r","Y","32" +"SUB r/m32, imm32","SUBL imm32, r/m32","subl imm32, r/m32","81 /5 id","V","V","","operand32","rw,r","Y","32" +"SUB r/m32, imm8","SUBL imm8, r/m32","subl imm8, r/m32","83 /5 ib","V","V","","operand32","rw,r","Y","32" +"SUB r32, r/m32","SUBL r/m32, r32","subl r/m32, r32","2B /r","V","V","","operand32","rw,r","Y","32" +"SUB r/m32, r32","SUBL r32, r/m32","subl r32, r/m32","29 /r","V","V","","operand32","rw,r","Y","32" +"SUBPD xmm1, xmm2/m128","SUBPD xmm2/m128, xmm1","subpd xmm2/m128, xmm1","66 0F 5C /r","V","V","SSE2","","rw,r","","" +"SUBPS xmm1, xmm2/m128","SUBPS xmm2/m128, xmm1","subps xmm2/m128, xmm1","0F 5C /r","V","V","SSE","","rw,r","","" +"SUB RAX, imm32","SUBQ imm32, RAX","subq imm32, RAX","REX.W 2D id","N.S.","V","","","rw,r","Y","64" +"SUB r/m64, imm32","SUBQ imm32, r/m64","subq imm32, r/m64","REX.W 81 /5 id","N.S.","V","","","rw,r","Y","64" +"SUB r/m64, imm8","SUBQ imm8, r/m64","subq imm8, r/m64","REX.W 83 /5 ib","N.S.","V","","","rw,r","Y","64" +"SUB r64, r/m64","SUBQ r/m64, r64","subq r/m64, r64","REX.W 2B /r","N.S.","V","","","rw,r","Y","64" +"SUB r/m64, r64","SUBQ r64, r/m64","subq r64, r/m64","REX.W 29 /r","N.S.","V","","","rw,r","Y","64" +"SUBSD xmm1, xmm2/m64","SUBSD xmm2/m64, xmm1","subsd xmm2/m64, xmm1","F2 0F 5C /r","V","V","SSE2","","rw,r","","" +"SUBSS xmm1, xmm2/m32","SUBSS xmm2/m32, xmm1","subss xmm2/m32, xmm1","F3 0F 5C /r","V","V","SSE","","rw,r","","" +"SUB AX, imm16","SUBW imm16, AX","subw imm16, AX","2D iw","V","V","","operand16","rw,r","Y","16" +"SUB r/m16, imm16","SUBW imm16, r/m16","subw imm16, r/m16","81 /5 iw","V","V","","operand16","rw,r","Y","16" +"SUB r/m16, imm8","SUBW imm8, r/m16","subw imm8, r/m16","83 /5 ib","V","V","","operand16","rw,r","Y","16" +"SUB r16, r/m16","SUBW r/m16, r16","subw r/m16, r16","2B /r","V","V","","operand16","rw,r","Y","16" +"SUB r/m16, r16","SUBW r16, r/m16","subw r16, r/m16","29 /r","V","V","","operand16","rw,r","Y","16" +"SWAPGS","SWAPGS","swapgs","0F 01 F8","N.S.","V","","","","","" +"SYSCALL","SYSCALL","syscall","0F 05","N.S.","V","","default64","","","" +"SYSCALL","SYSCALL","syscall","0F 05","V","N.S.","AMD","amd","","","" +"SYSENTER","SYSENTER","sysenter","0F 34","V","V","PPRO","","","","" +"SYSEXIT","SYSEXIT","sysexit","0F 35","V","V","PPRO","","","","" +"SYSEXIT","SYSEXIT","sysexit","REX.W 0F 35","N.E.","V","","pseudo","","","" +"SYSRET","SYSRET","sysretw/sysretl/sysretl","0F 07","V","N.S.","AMD","amd","","","" +"SYSRET","SYSRET","sysretw/sysretl/sysretl","0F 07","N.S.","V","","operand32,operand64","","","" +"SYSRET","SYSRET","sysretw/sysretl/sysretl","REX.W 0F 07","I","V","","pseudo","","","" +"T1MSKC r32V, r/m32","T1MSKCL r/m32, r32V","t1mskcl r/m32, r32V","XOP.NDD.128.09.WIG 01 /7","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"T1MSKC r64V, r/m64","T1MSKCQ r/m64, r64V","t1mskcq r/m64, r64V","XOP.NDD.128.09.WIG 01 /7","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"TEST AL, imm8","TESTB imm8, AL","testb imm8, AL","A8 ib","V","V","","","r,r","Y","8" +"TEST r/m8, imm8","TESTB imm8, r/m8","testb imm8, r/m8","F6 /0 ib","V","V","","","r,r","Y","8" +"TEST r/m8, imm8","TESTB imm8, r/m8","testb imm8, r/m8","F6 /1 ib","V","V","","","r,r","Y","8" +"TEST r/m8, imm8","TESTB imm8, r/m8","testb imm8, r/m8","REX F6 /0 ib","N.E.","V","","pseudo64","r,r","Y","8" +"TEST r/m8, r8","TESTB r8, r/m8","testb r8, r/m8","84 /r","V","V","","","r,r","Y","8" +"TEST r/m8, r8","TESTB r8, r/m8","testb r8, r/m8","REX 84 /r","N.E.","V","","pseudo64","r,r","Y","8" +"TEST EAX, imm32","TESTL imm32, EAX","testl imm32, EAX","A9 id","V","V","","operand32","r,r","Y","32" +"TEST r/m32, imm32","TESTL imm32, r/m32","testl imm32, r/m32","F7 /0 id","V","V","","operand32","r,r","Y","32" +"TEST r/m32, imm32","TESTL imm32, r/m32","testl imm32, r/m32","F7 /1 id","V","V","","operand32","r,r","Y","32" +"TEST r/m32, r32","TESTL r32, r/m32","testl r32, r/m32","85 /r","V","V","","operand32","r,r","Y","32" +"TEST RAX, imm32","TESTQ imm32, RAX","testq imm32, RAX","REX.W A9 id","N.S.","V","","","r,r","Y","64" +"TEST r/m64, imm32","TESTQ imm32, r/m64","testq imm32, r/m64","REX.W F7 /0 id","N.S.","V","","","r,r","Y","64" +"TEST r/m64, imm32","TESTQ imm32, r/m64","testq imm32, r/m64","REX.W F7 /1 id","N.S.","V","","","r,r","Y","64" +"TEST r/m64, r64","TESTQ r64, r/m64","testq r64, r/m64","REX.W 85 /r","N.S.","V","","","r,r","Y","64" +"TEST AX, imm16","TESTW imm16, AX","testw imm16, AX","A9 iw","V","V","","operand16","r,r","Y","16" +"TEST r/m16, imm16","TESTW imm16, r/m16","testw imm16, r/m16","F7 /0 iw","V","V","","operand16","r,r","Y","16" +"TEST r/m16, imm16","TESTW imm16, r/m16","testw imm16, r/m16","F7 /1 iw","V","V","","operand16","r,r","Y","16" +"TEST r/m16, r16","TESTW r16, r/m16","testw r16, r/m16","85 /r","V","V","","operand16","r,r","Y","16" +"TZCNT r32, r/m32","TZCNTL r/m32, r32","tzcntl r/m32, r32","F3 0F BC /r","V","V","BMI1","operand32","w,r","Y","32" +"TZCNT r64, r/m64","TZCNTQ r/m64, r64","tzcntq r/m64, r64","F3 REX.W 0F BC /r","N.S.","V","BMI1","","w,r","Y","64" +"TZCNT r16, r/m16","TZCNTW r/m16, r16","tzcntw r/m16, r16","F3 0F BC /r","V","V","BMI1","operand16","w,r","Y","16" +"TZMSK r32V, r/m32","TZMSKL r/m32, r32V","tzmskl r/m32, r32V","XOP.NDD.128.09.WIG 01 /4","V","V","TBM","amd,operand16,operand32","w,r","Y","32" +"TZMSK r64V, r/m64","TZMSKQ r/m64, r64V","tzmskq r/m64, r64V","XOP.NDD.128.09.WIG 01 /4","N.S.","V","TBM","amd,operand64","w,r","Y","64" +"UCOMISD xmm1, xmm2/m64","UCOMISD xmm2/m64, xmm1","ucomisd xmm2/m64, xmm1","66 0F 2E /r","V","V","SSE2","","r,r","","" +"UCOMISS xmm1, xmm2/m32","UCOMISS xmm2/m32, xmm1","ucomiss xmm2/m32, xmm1","0F 2E /r","V","V","SSE","","r,r","","" +"UD0 r32, r/m32","UD0 r/m32, r32","ud0 r/m32, r32","0F FF /r","V","V","PPRO","","r,r","","" +"UD1 r32, r/m32","UD1 r/m32, r32","ud1 r/m32, r32","0F B9 /r","V","V","PPRO","","r,r","","" +"UD2","UD2","ud2","0F 0B","V","V","PPRO","","","","" +"UNPCKHPD xmm1, xmm2/m128","UNPCKHPD xmm2/m128, xmm1","unpckhpd xmm2/m128, xmm1","66 0F 15 /r","V","V","SSE2","","rw,r","","" +"UNPCKHPS xmm1, xmm2/m128","UNPCKHPS xmm2/m128, xmm1","unpckhps xmm2/m128, xmm1","0F 15 /r","V","V","SSE","","rw,r","","" +"UNPCKLPD xmm1, xmm2/m128","UNPCKLPD xmm2/m128, xmm1","unpcklpd xmm2/m128, xmm1","66 0F 14 /r","V","V","SSE2","","rw,r","","" +"UNPCKLPS xmm1, xmm2/m128","UNPCKLPS xmm2/m128, xmm1","unpcklps xmm2/m128, xmm1","0F 14 /r","V","V","SSE","","rw,r","","" +"V4FMADDPS zmm1, {k}{z}, zmmV+3, m128","V4FMADDPS m128, zmmV+3, {k}{z}, zmm1","v4fmaddps m128, zmmV+3, {k}{z}, zmm1","EVEX.DDS.512.F2.0F38.W0 9A /r","V","V","AVX512_4FMAPS","modrm_memonly,scale16","rw,r,r,r","","" +"V4FMADDSS xmm1, {k}{z}, xmmV+3, m128","V4FMADDSS m128, xmmV+3, {k}{z}, xmm1","v4fmaddss m128, xmmV+3, {k}{z}, xmm1","EVEX.DDS.LIG.F2.0F38.W0 9B /r","V","V","AVX512_4FMAPS","modrm_memonly,scale16","rw,r,r,r","","" +"V4FNMADDPS zmm1, {k}{z}, zmmV+3, m128","V4FNMADDPS m128, zmmV+3, {k}{z}, zmm1","v4fnmaddps m128, zmmV+3, {k}{z}, zmm1","EVEX.DDS.512.F2.0F38.W0 AA /r","V","V","AVX512_4FMAPS","modrm_memonly,scale16","rw,r,r,r","","" +"V4FNMADDSS xmm1, {k}{z}, xmmV+3, m128","V4FNMADDSS m128, xmmV+3, {k}{z}, xmm1","v4fnmaddss m128, xmmV+3, {k}{z}, xmm1","EVEX.DDS.LIG.F2.0F38.W0 AB /r","V","V","AVX512_4FMAPS","modrm_memonly,scale16","rw,r,r,r","","" +"VADDPD xmm1, xmmV, xmm2/m128","VADDPD xmm2/m128, xmmV, xmm1","vaddpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 58 /r","V","V","AVX","","w,r,r","","" +"VADDPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VADDPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vaddpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 58 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VADDPD ymm1, ymmV, ymm2/m256","VADDPD ymm2/m256, ymmV, ymm1","vaddpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 58 /r","V","V","AVX","","w,r,r","","" +"VADDPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VADDPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vaddpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 58 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VADDPD zmm1{er}, {k}{z}, zmmV, zmm2","VADDPD zmm2, zmmV, {k}{z}, zmm1{er}","vaddpd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.66.0F.W1 58 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VADDPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VADDPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vaddpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 58 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VADDPS xmm1, xmmV, xmm2/m128","VADDPS xmm2/m128, xmmV, xmm1","vaddps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 58 /r","V","V","AVX","","w,r,r","","" +"VADDPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VADDPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vaddps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 58 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VADDPS ymm1, ymmV, ymm2/m256","VADDPS ymm2/m256, ymmV, ymm1","vaddps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 58 /r","V","V","AVX","","w,r,r","","" +"VADDPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VADDPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vaddps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 58 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VADDPS zmm1{er}, {k}{z}, zmmV, zmm2","VADDPS zmm2, zmmV, {k}{z}, zmm1{er}","vaddps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.0F.W0 58 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VADDPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VADDPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vaddps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 58 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VADDSD xmm1{er}, {k}{z}, xmmV, xmm2","VADDSD xmm2, xmmV, {k}{z}, xmm1{er}","vaddsd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F2.0F.W1 58 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VADDSD xmm1, xmmV, xmm2/m64","VADDSD xmm2/m64, xmmV, xmm1","vaddsd xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 58 /r","V","V","AVX","","w,r,r","","" +"VADDSD xmm1, {k}{z}, xmmV, xmm2/m64","VADDSD xmm2/m64, xmmV, {k}{z}, xmm1","vaddsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 58 /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VADDSS xmm1{er}, {k}{z}, xmmV, xmm2","VADDSS xmm2, xmmV, {k}{z}, xmm1{er}","vaddss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F3.0F.W0 58 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VADDSS xmm1, xmmV, xmm2/m32","VADDSS xmm2/m32, xmmV, xmm1","vaddss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 58 /r","V","V","AVX","","w,r,r","","" +"VADDSS xmm1, {k}{z}, xmmV, xmm2/m32","VADDSS xmm2/m32, xmmV, {k}{z}, xmm1","vaddss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 58 /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VADDSUBPD xmm1, xmmV, xmm2/m128","VADDSUBPD xmm2/m128, xmmV, xmm1","vaddsubpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG D0 /r","V","V","AVX","","w,r,r","","" +"VADDSUBPD ymm1, ymmV, ymm2/m256","VADDSUBPD ymm2/m256, ymmV, ymm1","vaddsubpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG D0 /r","V","V","AVX","","w,r,r","","" +"VADDSUBPS xmm1, xmmV, xmm2/m128","VADDSUBPS xmm2/m128, xmmV, xmm1","vaddsubps xmm2/m128, xmmV, xmm1","VEX.NDS.128.F2.0F.WIG D0 /r","V","V","AVX","","w,r,r","","" +"VADDSUBPS ymm1, ymmV, ymm2/m256","VADDSUBPS ymm2/m256, ymmV, ymm1","vaddsubps ymm2/m256, ymmV, ymm1","VEX.NDS.256.F2.0F.WIG D0 /r","V","V","AVX","","w,r,r","","" +"VAESDEC xmm1, xmmV, xmm2/m128","VAESDEC xmm2/m128, xmmV, xmm1","vaesdec xmm2/m128, xmmV, xmm1","EVEX.NDS.128.66.0F38.WIG DE /r","V","V","AES+AVX512VL","scale16","w,r,r","","" +"VAESDEC xmm1, xmmV, xmm2/m128","VAESDEC xmm2/m128, xmmV, xmm1","vaesdec xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG DE /r","V","V","AES+AVX","","w,r,r","","" +"VAESDEC ymm1, ymmV, ymm2/m256","VAESDEC ymm2/m256, ymmV, ymm1","vaesdec ymm2/m256, ymmV, ymm1","EVEX.NDS.256.66.0F38.WIG DE /r","V","V","AES+AVX512VL","scale32","w,r,r","","" +"VAESDEC ymm1, ymmV, ymm2/m256","VAESDEC ymm2/m256, ymmV, ymm1","vaesdec ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG DE /r","V","V","VAES+AVX","","w,r,r","","" +"VAESDEC zmm1, zmmV, zmm2/m512","VAESDEC zmm2/m512, zmmV, zmm1","vaesdec zmm2/m512, zmmV, zmm1","EVEX.NDS.512.66.0F38.WIG DE /r","V","V","AES+AVX512F","scale64","w,r,r","","" +"VAESDECLAST xmm1, xmmV, xmm2/m128","VAESDECLAST xmm2/m128, xmmV, xmm1","vaesdeclast xmm2/m128, xmmV, xmm1","EVEX.NDS.128.66.0F38.WIG DF /r","V","V","AES+AVX512VL","scale16","w,r,r","","" +"VAESDECLAST xmm1, xmmV, xmm2/m128","VAESDECLAST xmm2/m128, xmmV, xmm1","vaesdeclast xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG DF /r","V","V","AES+AVX","","w,r,r","","" +"VAESDECLAST ymm1, ymmV, ymm2/m256","VAESDECLAST ymm2/m256, ymmV, ymm1","vaesdeclast ymm2/m256, ymmV, ymm1","EVEX.NDS.256.66.0F38.WIG DF /r","V","V","AES+AVX512VL","scale32","w,r,r","","" +"VAESDECLAST ymm1, ymmV, ymm2/m256","VAESDECLAST ymm2/m256, ymmV, ymm1","vaesdeclast ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG DF /r","V","V","VAES+AVX","","w,r,r","","" +"VAESDECLAST zmm1, zmmV, zmm2/m512","VAESDECLAST zmm2/m512, zmmV, zmm1","vaesdeclast zmm2/m512, zmmV, zmm1","EVEX.NDS.512.66.0F38.WIG DF /r","V","V","AES+AVX512F","scale64","w,r,r","","" +"VAESENC xmm1, xmmV, xmm2/m128","VAESENC xmm2/m128, xmmV, xmm1","vaesenc xmm2/m128, xmmV, xmm1","EVEX.NDS.128.66.0F38.WIG DC /r","V","V","AES+AVX512VL","scale16","w,r,r","","" +"VAESENC xmm1, xmmV, xmm2/m128","VAESENC xmm2/m128, xmmV, xmm1","vaesenc xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG DC /r","V","V","AES+AVX","","w,r,r","","" +"VAESENC ymm1, ymmV, ymm2/m256","VAESENC ymm2/m256, ymmV, ymm1","vaesenc ymm2/m256, ymmV, ymm1","EVEX.NDS.256.66.0F38.WIG DC /r","V","V","AES+AVX512VL","scale32","w,r,r","","" +"VAESENC ymm1, ymmV, ymm2/m256","VAESENC ymm2/m256, ymmV, ymm1","vaesenc ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG DC /r","V","V","VAES+AVX","","w,r,r","","" +"VAESENC zmm1, zmmV, zmm2/m512","VAESENC zmm2/m512, zmmV, zmm1","vaesenc zmm2/m512, zmmV, zmm1","EVEX.NDS.512.66.0F38.WIG DC /r","V","V","AES+AVX512F","scale64","w,r,r","","" +"VAESENCLAST xmm1, xmmV, xmm2/m128","VAESENCLAST xmm2/m128, xmmV, xmm1","vaesenclast xmm2/m128, xmmV, xmm1","EVEX.NDS.128.66.0F38.WIG DD /r","V","V","AES+AVX512VL","scale16","w,r,r","","" +"VAESENCLAST xmm1, xmmV, xmm2/m128","VAESENCLAST xmm2/m128, xmmV, xmm1","vaesenclast xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG DD /r","V","V","AES+AVX","","w,r,r","","" +"VAESENCLAST ymm1, ymmV, ymm2/m256","VAESENCLAST ymm2/m256, ymmV, ymm1","vaesenclast ymm2/m256, ymmV, ymm1","EVEX.NDS.256.66.0F38.WIG DD /r","V","V","AES+AVX512VL","scale32","w,r,r","","" +"VAESENCLAST ymm1, ymmV, ymm2/m256","VAESENCLAST ymm2/m256, ymmV, ymm1","vaesenclast ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG DD /r","V","V","VAES+AVX","","w,r,r","","" +"VAESENCLAST zmm1, zmmV, zmm2/m512","VAESENCLAST zmm2/m512, zmmV, zmm1","vaesenclast zmm2/m512, zmmV, zmm1","EVEX.NDS.512.66.0F38.WIG DD /r","V","V","AES+AVX512F","scale64","w,r,r","","" +"VAESIMC xmm1, xmm2/m128","VAESIMC xmm2/m128, xmm1","vaesimc xmm2/m128, xmm1","VEX.128.66.0F38.WIG DB /r","V","V","AES+AVX","","w,r","","" +"VAESKEYGENASSIST xmm1, xmm2/m128, imm8u","VAESKEYGENASSIST imm8u, xmm2/m128, xmm1","vaeskeygenassist imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.WIG DF /r ib","V","V","AES+AVX","","w,r,r","","" +"VALIGND xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst, imm8u","VALIGND imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","valignd imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W0 03 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r,r","","" +"VALIGND ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u","VALIGND imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","valignd imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 03 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VALIGND zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u","VALIGND imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","valignd imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 03 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r,r","","" +"VALIGNQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u","VALIGNQ imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","valignq imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W1 03 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VALIGNQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VALIGNQ imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","valignq imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 03 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VALIGNQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VALIGNQ imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","valignq imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 03 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VANDNPD xmm1, xmmV, xmm2/m128","VANDNPD xmm2/m128, xmmV, xmm1","vandnpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 55 /r","V","V","AVX","","w,r,r","","" +"VANDNPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VANDNPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vandnpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 55 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VANDNPD ymm1, ymmV, ymm2/m256","VANDNPD ymm2/m256, ymmV, ymm1","vandnpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 55 /r","V","V","AVX","","w,r,r","","" +"VANDNPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VANDNPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vandnpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 55 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VANDNPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VANDNPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vandnpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 55 /r","V","V","AVX512DQ","bscale8,scale64","w,r,r,r","","" +"VANDNPS xmm1, xmmV, xmm2/m128","VANDNPS xmm2/m128, xmmV, xmm1","vandnps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 55 /r","V","V","AVX","","w,r,r","","" +"VANDNPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VANDNPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vandnps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 55 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VANDNPS ymm1, ymmV, ymm2/m256","VANDNPS ymm2/m256, ymmV, ymm1","vandnps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 55 /r","V","V","AVX","","w,r,r","","" +"VANDNPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VANDNPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vandnps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 55 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VANDNPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VANDNPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vandnps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 55 /r","V","V","AVX512DQ","bscale4,scale64","w,r,r,r","","" +"VANDPD xmm1, xmmV, xmm2/m128","VANDPD xmm2/m128, xmmV, xmm1","vandpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 54 /r","V","V","AVX","","w,r,r","","" +"VANDPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VANDPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vandpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 54 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VANDPD ymm1, ymmV, ymm2/m256","VANDPD ymm2/m256, ymmV, ymm1","vandpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 54 /r","V","V","AVX","","w,r,r","","" +"VANDPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VANDPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vandpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 54 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VANDPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VANDPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vandpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 54 /r","V","V","AVX512DQ","bscale8,scale64","w,r,r,r","","" +"VANDPS xmm1, xmmV, xmm2/m128","VANDPS xmm2/m128, xmmV, xmm1","vandps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 54 /r","V","V","AVX","","w,r,r","","" +"VANDPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VANDPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vandps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 54 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VANDPS ymm1, ymmV, ymm2/m256","VANDPS ymm2/m256, ymmV, ymm1","vandps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 54 /r","V","V","AVX","","w,r,r","","" +"VANDPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VANDPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vandps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 54 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VANDPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VANDPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vandps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 54 /r","V","V","AVX512DQ","bscale4,scale64","w,r,r,r","","" +"VBLENDMPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VBLENDMPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vblendmpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 65 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VBLENDMPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VBLENDMPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vblendmpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 65 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VBLENDMPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VBLENDMPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vblendmpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 65 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VBLENDMPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VBLENDMPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vblendmps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 65 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VBLENDMPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VBLENDMPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vblendmps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 65 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VBLENDMPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VBLENDMPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vblendmps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 65 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VBLENDPD xmm1, xmmV, xmm2/m128, imm8u","VBLENDPD imm8u, xmm2/m128, xmmV, xmm1","vblendpd imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 0D /r ib","V","V","AVX","","w,r,r,r","","" +"VBLENDPD ymm1, ymmV, ymm2/m256, imm8u","VBLENDPD imm8u, ymm2/m256, ymmV, ymm1","vblendpd imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.WIG 0D /r ib","V","V","AVX","","w,r,r,r","","" +"VBLENDPS xmm1, xmmV, xmm2/m128, imm8u","VBLENDPS imm8u, xmm2/m128, xmmV, xmm1","vblendps imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 0C /r ib","V","V","AVX","","w,r,r,r","","" +"VBLENDPS ymm1, ymmV, ymm2/m256, imm8u","VBLENDPS imm8u, ymm2/m256, ymmV, ymm1","vblendps imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.WIG 0C /r ib","V","V","AVX","","w,r,r,r","","" +"VBLENDVPD xmm1, xmmV, xmm2/m128, xmmIH","VBLENDVPD xmmIH, xmm2/m128, xmmV, xmm1","vblendvpd xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 4B /r /is4","V","V","AVX","","w,r,r,r","","" +"VBLENDVPD ymm1, ymmV, ymm2/m256, ymmIH","VBLENDVPD ymmIH, ymm2/m256, ymmV, ymm1","vblendvpd ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 4B /r /is4","V","V","AVX","","w,r,r,r","","" +"VBLENDVPS xmm1, xmmV, xmm2/m128, xmmIH","VBLENDVPS xmmIH, xmm2/m128, xmmV, xmm1","vblendvps xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 4A /r /is4","V","V","AVX","","w,r,r,r","","" +"VBLENDVPS ymm1, ymmV, ymm2/m256, ymmIH","VBLENDVPS ymmIH, ymm2/m256, ymmV, ymm1","vblendvps ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 4A /r /is4","V","V","AVX","","w,r,r,r","","" +"VBROADCASTF128 ymm1, m128","VBROADCASTF128 m128, ymm1","vbroadcastf128 m128, ymm1","VEX.256.66.0F38.W0 1A /r","V","V","AVX","modrm_memonly","w,r","","" +"VBROADCASTF32X2 ymm1, {k}{z}, xmm2/m64","VBROADCASTF32X2 xmm2/m64, {k}{z}, ymm1","vbroadcastf32x2 xmm2/m64, {k}{z}, ymm1","EVEX.256.66.0F38.W0 19 /r","V","V","AVX512DQ+AVX512VL","scale8","w,r,r","","" +"VBROADCASTF32X2 zmm1, {k}{z}, xmm2/m64","VBROADCASTF32X2 xmm2/m64, {k}{z}, zmm1","vbroadcastf32x2 xmm2/m64, {k}{z}, zmm1","EVEX.512.66.0F38.W0 19 /r","V","V","AVX512DQ","scale8","w,r,r","","" +"VBROADCASTF32X4 ymm1, {k}{z}, m128","VBROADCASTF32X4 m128, {k}{z}, ymm1","vbroadcastf32x4 m128, {k}{z}, ymm1","EVEX.256.66.0F38.W0 1A /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale16","w,r,r","","" +"VBROADCASTF32X4 zmm1, {k}{z}, m128","VBROADCASTF32X4 m128, {k}{z}, zmm1","vbroadcastf32x4 m128, {k}{z}, zmm1","EVEX.512.66.0F38.W0 1A /r","V","V","AVX512F","modrm_memonly,scale16","w,r,r","","" +"VBROADCASTF32X8 zmm1, {k}{z}, m256","VBROADCASTF32X8 m256, {k}{z}, zmm1","vbroadcastf32x8 m256, {k}{z}, zmm1","EVEX.512.66.0F38.W0 1B /r","V","V","AVX512DQ","modrm_memonly,scale32","w,r,r","","" +"VBROADCASTF64X2 ymm1, {k}{z}, m128","VBROADCASTF64X2 m128, {k}{z}, ymm1","vbroadcastf64x2 m128, {k}{z}, ymm1","EVEX.256.66.0F38.W1 1A /r","V","V","AVX512DQ+AVX512VL","modrm_memonly,scale16","w,r,r","","" +"VBROADCASTF64X2 zmm1, {k}{z}, m128","VBROADCASTF64X2 m128, {k}{z}, zmm1","vbroadcastf64x2 m128, {k}{z}, zmm1","EVEX.512.66.0F38.W1 1A /r","V","V","AVX512DQ","modrm_memonly,scale16","w,r,r","","" +"VBROADCASTF64X4 zmm1, {k}{z}, m256","VBROADCASTF64X4 m256, {k}{z}, zmm1","vbroadcastf64x4 m256, {k}{z}, zmm1","EVEX.512.66.0F38.W1 1B /r","V","V","AVX512F","modrm_memonly,scale32","w,r,r","","" +"VBROADCASTI128 ymm1, m128","VBROADCASTI128 m128, ymm1","vbroadcasti128 m128, ymm1","VEX.256.66.0F38.W0 5A /r","V","V","AVX2","modrm_memonly","w,r","","" +"VBROADCASTI32X2 xmm1, {k}{z}, xmm2/m64","VBROADCASTI32X2 xmm2/m64, {k}{z}, xmm1","vbroadcasti32x2 xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.W0 59 /r","V","V","AVX512DQ+AVX512VL","scale8","w,r,r","","" +"VBROADCASTI32X2 ymm1, {k}{z}, xmm2/m64","VBROADCASTI32X2 xmm2/m64, {k}{z}, ymm1","vbroadcasti32x2 xmm2/m64, {k}{z}, ymm1","EVEX.256.66.0F38.W0 59 /r","V","V","AVX512DQ+AVX512VL","scale8","w,r,r","","" +"VBROADCASTI32X2 zmm1, {k}{z}, xmm2/m64","VBROADCASTI32X2 xmm2/m64, {k}{z}, zmm1","vbroadcasti32x2 xmm2/m64, {k}{z}, zmm1","EVEX.512.66.0F38.W0 59 /r","V","V","AVX512DQ","scale8","w,r,r","","" +"VBROADCASTI32X4 ymm1, {k}{z}, m128","VBROADCASTI32X4 m128, {k}{z}, ymm1","vbroadcasti32x4 m128, {k}{z}, ymm1","EVEX.256.66.0F38.W0 5A /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale16","w,r,r","","" +"VBROADCASTI32X4 zmm1, {k}{z}, m128","VBROADCASTI32X4 m128, {k}{z}, zmm1","vbroadcasti32x4 m128, {k}{z}, zmm1","EVEX.512.66.0F38.W0 5A /r","V","V","AVX512F","modrm_memonly,scale16","w,r,r","","" +"VBROADCASTI32X8 zmm1, {k}{z}, m256","VBROADCASTI32X8 m256, {k}{z}, zmm1","vbroadcasti32x8 m256, {k}{z}, zmm1","EVEX.512.66.0F38.W0 5B /r","V","V","AVX512DQ","modrm_memonly,scale32","w,r,r","","" +"VBROADCASTI64X2 ymm1, {k}{z}, m128","VBROADCASTI64X2 m128, {k}{z}, ymm1","vbroadcasti64x2 m128, {k}{z}, ymm1","EVEX.256.66.0F38.W1 5A /r","V","V","AVX512DQ+AVX512VL","modrm_memonly,scale16","w,r,r","","" +"VBROADCASTI64X2 zmm1, {k}{z}, m128","VBROADCASTI64X2 m128, {k}{z}, zmm1","vbroadcasti64x2 m128, {k}{z}, zmm1","EVEX.512.66.0F38.W1 5A /r","V","V","AVX512DQ","modrm_memonly,scale16","w,r,r","","" +"VBROADCASTI64X4 zmm1, {k}{z}, m256","VBROADCASTI64X4 m256, {k}{z}, zmm1","vbroadcasti64x4 m256, {k}{z}, zmm1","EVEX.512.66.0F38.W1 5B /r","V","V","AVX512F","modrm_memonly,scale32","w,r,r","","" +"VBROADCASTSD ymm1, m64","VBROADCASTSD m64, ymm1","vbroadcastsd m64, ymm1","VEX.256.66.0F38.W0 19 /r","V","V","AVX","modrm_memonly","w,r","","" +"VBROADCASTSD ymm1, xmm2","VBROADCASTSD xmm2, ymm1","vbroadcastsd xmm2, ymm1","VEX.256.66.0F38.W0 19 /r","V","V","AVX2","modrm_regonly","w,r","","" +"VBROADCASTSD ymm1, {k}{z}, xmm2/m64","VBROADCASTSD xmm2/m64, {k}{z}, ymm1","vbroadcastsd xmm2/m64, {k}{z}, ymm1","EVEX.256.66.0F38.W1 19 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VBROADCASTSD zmm1, {k}{z}, xmm2/m64","VBROADCASTSD xmm2/m64, {k}{z}, zmm1","vbroadcastsd xmm2/m64, {k}{z}, zmm1","EVEX.512.66.0F38.W1 19 /r","V","V","AVX512F","scale8","w,r,r","","" +"VBROADCASTSS xmm1, m32","VBROADCASTSS m32, xmm1","vbroadcastss m32, xmm1","VEX.128.66.0F38.W0 18 /r","V","V","AVX","modrm_memonly","w,r","","" +"VBROADCASTSS ymm1, m32","VBROADCASTSS m32, ymm1","vbroadcastss m32, ymm1","VEX.256.66.0F38.W0 18 /r","V","V","AVX","modrm_memonly","w,r","","" +"VBROADCASTSS xmm1, xmm2","VBROADCASTSS xmm2, xmm1","vbroadcastss xmm2, xmm1","VEX.128.66.0F38.W0 18 /r","V","V","AVX2","modrm_regonly","w,r","","" +"VBROADCASTSS ymm1, xmm2","VBROADCASTSS xmm2, ymm1","vbroadcastss xmm2, ymm1","VEX.256.66.0F38.W0 18 /r","V","V","AVX2","modrm_regonly","w,r","","" +"VBROADCASTSS xmm1, {k}{z}, xmm2/m32","VBROADCASTSS xmm2/m32, {k}{z}, xmm1","vbroadcastss xmm2/m32, {k}{z}, xmm1","EVEX.128.66.0F38.W0 18 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VBROADCASTSS ymm1, {k}{z}, xmm2/m32","VBROADCASTSS xmm2/m32, {k}{z}, ymm1","vbroadcastss xmm2/m32, {k}{z}, ymm1","EVEX.256.66.0F38.W0 18 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VBROADCASTSS zmm1, {k}{z}, xmm2/m32","VBROADCASTSS xmm2/m32, {k}{z}, zmm1","vbroadcastss xmm2/m32, {k}{z}, zmm1","EVEX.512.66.0F38.W0 18 /r","V","V","AVX512F","scale4","w,r,r","","" +"VCMPPD xmm1, xmmV, xmm2/m128, imm8u","VCMPPD imm8u, xmm2/m128, xmmV, xmm1","vcmppd imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG C2 /r ib","V","V","AVX","","w,r,r,r","","" +"VCMPPD k1, {k}, xmmV, xmm2/m128/m64bcst, imm8u","VCMPPD imm8u, xmm2/m128/m64bcst, xmmV, {k}, k1","vcmppd imm8u, xmm2/m128/m64bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F.W1 C2 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VCMPPD ymm1, ymmV, ymm2/m256, imm8u","VCMPPD imm8u, ymm2/m256, ymmV, ymm1","vcmppd imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG C2 /r ib","V","V","AVX","","w,r,r,r","","" +"VCMPPD k1, {k}, ymmV, ymm2/m256/m64bcst, imm8u","VCMPPD imm8u, ymm2/m256/m64bcst, ymmV, {k}, k1","vcmppd imm8u, ymm2/m256/m64bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F.W1 C2 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VCMPPD k1{sae}, {k}, zmmV, zmm2, imm8u","VCMPPD imm8u, zmm2, zmmV, {k}, k1{sae}","vcmppd imm8u, zmm2, zmmV, {k}, k1{sae}","EVEX.NDS.512.66.0F.W1 C2 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r,r","","" +"VCMPPD k1, {k}, zmmV, zmm2/m512/m64bcst, imm8u","VCMPPD imm8u, zmm2/m512/m64bcst, zmmV, {k}, k1","vcmppd imm8u, zmm2/m512/m64bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F.W1 C2 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VCMPPS xmm1, xmmV, xmm2/m128, imm8u","VCMPPS imm8u, xmm2/m128, xmmV, xmm1","vcmpps imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG C2 /r ib","V","V","AVX","","w,r,r,r","","" +"VCMPPS k1, {k}, xmmV, xmm2/m128/m32bcst, imm8u","VCMPPS imm8u, xmm2/m128/m32bcst, xmmV, {k}, k1","vcmpps imm8u, xmm2/m128/m32bcst, xmmV, {k}, k1","EVEX.NDS.128.0F.W0 C2 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r,r","","" +"VCMPPS ymm1, ymmV, ymm2/m256, imm8u","VCMPPS imm8u, ymm2/m256, ymmV, ymm1","vcmpps imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG C2 /r ib","V","V","AVX","","w,r,r,r","","" +"VCMPPS k1, {k}, ymmV, ymm2/m256/m32bcst, imm8u","VCMPPS imm8u, ymm2/m256/m32bcst, ymmV, {k}, k1","vcmpps imm8u, ymm2/m256/m32bcst, ymmV, {k}, k1","EVEX.NDS.256.0F.W0 C2 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VCMPPS k1{sae}, {k}, zmmV, zmm2, imm8u","VCMPPS imm8u, zmm2, zmmV, {k}, k1{sae}","vcmpps imm8u, zmm2, zmmV, {k}, k1{sae}","EVEX.NDS.512.0F.W0 C2 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r,r","","" +"VCMPPS k1, {k}, zmmV, zmm2/m512/m32bcst, imm8u","VCMPPS imm8u, zmm2/m512/m32bcst, zmmV, {k}, k1","vcmpps imm8u, zmm2/m512/m32bcst, zmmV, {k}, k1","EVEX.NDS.512.0F.W0 C2 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r,r","","" +"VCMPSD k1{sae}, {k}, xmmV, xmm2, imm8u","VCMPSD imm8u, xmm2, xmmV, {k}, k1{sae}","vcmpsd imm8u, xmm2, xmmV, {k}, k1{sae}","EVEX.NDS.128.F2.0F.W1 C2 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r,r","","" +"VCMPSD xmm1, xmmV, xmm2/m64, imm8u","VCMPSD imm8u, xmm2/m64, xmmV, xmm1","vcmpsd imm8u, xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG C2 /r ib","V","V","AVX","","w,r,r,r","","" +"VCMPSD k1, {k}, xmmV, xmm2/m64, imm8u","VCMPSD imm8u, xmm2/m64, xmmV, {k}, k1","vcmpsd imm8u, xmm2/m64, xmmV, {k}, k1","EVEX.NDS.LIG.F2.0F.W1 C2 /r ib","V","V","AVX512F","scale8","w,r,r,r,r","","" +"VCMPSS k1{sae}, {k}, xmmV, xmm2, imm8u","VCMPSS imm8u, xmm2, xmmV, {k}, k1{sae}","vcmpss imm8u, xmm2, xmmV, {k}, k1{sae}","EVEX.NDS.128.F3.0F.W0 C2 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r,r","","" +"VCMPSS xmm1, xmmV, xmm2/m32, imm8u","VCMPSS imm8u, xmm2/m32, xmmV, xmm1","vcmpss imm8u, xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG C2 /r ib","V","V","AVX","","w,r,r,r","","" +"VCMPSS k1, {k}, xmmV, xmm2/m32, imm8u","VCMPSS imm8u, xmm2/m32, xmmV, {k}, k1","vcmpss imm8u, xmm2/m32, xmmV, {k}, k1","EVEX.NDS.LIG.F3.0F.W0 C2 /r ib","V","V","AVX512F","scale4","w,r,r,r,r","","" +"VCOMISD xmm1{sae}, xmm2","VCOMISD xmm2, xmm1{sae}","vcomisd xmm2, xmm1{sae}","EVEX.128.66.0F.W1 2F /r","V","V","AVX512F","modrm_regonly","r,r","","" +"VCOMISD xmm1, xmm2/m64","VCOMISD xmm2/m64, xmm1","vcomisd xmm2/m64, xmm1","EVEX.LIG.66.0F.W1 2F /r","V","V","AVX512F","scale8","r,r","","" +"VCOMISD xmm1, xmm2/m64","VCOMISD xmm2/m64, xmm1","vcomisd xmm2/m64, xmm1","VEX.LIG.66.0F.WIG 2F /r","V","V","AVX","","r,r","","" +"VCOMISS xmm1{sae}, xmm2","VCOMISS xmm2, xmm1{sae}","vcomiss xmm2, xmm1{sae}","EVEX.128.0F.W0 2F /r","V","V","AVX512F","modrm_regonly","r,r","","" +"VCOMISS xmm1, xmm2/m32","VCOMISS xmm2/m32, xmm1","vcomiss xmm2/m32, xmm1","EVEX.LIG.0F.W0 2F /r","V","V","AVX512F","scale4","r,r","","" +"VCOMISS xmm1, xmm2/m32","VCOMISS xmm2/m32, xmm1","vcomiss xmm2/m32, xmm1","VEX.LIG.0F.WIG 2F /r","V","V","AVX","","r,r","","" +"VCOMPRESSPD xmm2/m128, {k}{z}, xmm1","VCOMPRESSPD xmm1, {k}{z}, xmm2/m128","vcompresspd xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F38.W1 8A /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VCOMPRESSPD ymm2/m256, {k}{z}, ymm1","VCOMPRESSPD ymm1, {k}{z}, ymm2/m256","vcompresspd ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F38.W1 8A /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VCOMPRESSPD zmm2/m512, {k}{z}, zmm1","VCOMPRESSPD zmm1, {k}{z}, zmm2/m512","vcompresspd zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F38.W1 8A /r","V","V","AVX512F","scale8","w,r,r","","" +"VCOMPRESSPS xmm2/m128, {k}{z}, xmm1","VCOMPRESSPS xmm1, {k}{z}, xmm2/m128","vcompressps xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F38.W0 8A /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VCOMPRESSPS ymm2/m256, {k}{z}, ymm1","VCOMPRESSPS ymm1, {k}{z}, ymm2/m256","vcompressps ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F38.W0 8A /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VCOMPRESSPS zmm2/m512, {k}{z}, zmm1","VCOMPRESSPS zmm1, {k}{z}, zmm2/m512","vcompressps zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F38.W0 8A /r","V","V","AVX512F","scale4","w,r,r","","" +"VCVTDQ2PD ymm1, xmm2/m128","VCVTDQ2PD xmm2/m128, ymm1","vcvtdq2pd xmm2/m128, ymm1","VEX.256.F3.0F.WIG E6 /r","V","V","AVX","","w,r","","" +"VCVTDQ2PD xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTDQ2PD xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtdq2pd xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.F3.0F.W0 E6 /r","V","V","AVX512F+AVX512VL","bscale4,scale8","w,r,r","","" +"VCVTDQ2PD ymm1, {k}{z}, xmm2/m256/m32bcst","VCVTDQ2PD xmm2/m256/m32bcst, {k}{z}, ymm1","vcvtdq2pd xmm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.F3.0F.W0 E6 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTDQ2PD xmm1, xmm2/m64","VCVTDQ2PD xmm2/m64, xmm1","vcvtdq2pd xmm2/m64, xmm1","VEX.128.F3.0F.WIG E6 /r","V","V","AVX","","w,r","","" +"VCVTDQ2PD zmm1, {k}{z}, ymm2/m512/m32bcst","VCVTDQ2PD ymm2/m512/m32bcst, {k}{z}, zmm1","vcvtdq2pd ymm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.F3.0F.W0 E6 /r","V","V","AVX512F","bscale4,scale32","w,r,r","","" +"VCVTDQ2PS xmm1, xmm2/m128","VCVTDQ2PS xmm2/m128, xmm1","vcvtdq2ps xmm2/m128, xmm1","VEX.128.0F.WIG 5B /r","V","V","AVX","","w,r","","" +"VCVTDQ2PS xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTDQ2PS xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtdq2ps xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.0F.W0 5B /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTDQ2PS ymm1, ymm2/m256","VCVTDQ2PS ymm2/m256, ymm1","vcvtdq2ps ymm2/m256, ymm1","VEX.256.0F.WIG 5B /r","V","V","AVX","","w,r","","" +"VCVTDQ2PS ymm1, {k}{z}, ymm2/m256/m32bcst","VCVTDQ2PS ymm2/m256/m32bcst, {k}{z}, ymm1","vcvtdq2ps ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.0F.W0 5B /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VCVTDQ2PS zmm1{er}, {k}{z}, zmm2","VCVTDQ2PS zmm2, {k}{z}, zmm1{er}","vcvtdq2ps zmm2, {k}{z}, zmm1{er}","EVEX.512.0F.W0 5B /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VCVTDQ2PS zmm1, {k}{z}, zmm2/m512/m32bcst","VCVTDQ2PS zmm2/m512/m32bcst, {k}{z}, zmm1","vcvtdq2ps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.0F.W0 5B /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VCVTPD2DQ ymm1{er}, {k}{z}, zmm2","VCVTPD2DQ zmm2, {k}{z}, ymm1{er}","vcvtpd2dq zmm2, {k}{z}, ymm1{er}","EVEX.512.F2.0F.W1 E6 /r","V","V","AVX512F","modrm_regonly","w,r,r","Y","" +"VCVTPD2DQ ymm1, {k}{z}, zmm2/m512/m64bcst","VCVTPD2DQ zmm2/m512/m64bcst, {k}{z}, ymm1","vcvtpd2dq zmm2/m512/m64bcst, {k}{z}, ymm1","EVEX.512.F2.0F.W1 E6 /r","V","V","AVX512F","bscale8,scale64","w,r,r","Y","512" +"VCVTPD2DQ xmm1, xmm2/m128","VCVTPD2DQX xmm2/m128, xmm1","vcvtpd2dqx xmm2/m128, xmm1","VEX.128.F2.0F.WIG E6 /r","V","V","AVX","","w,r","Y","128" +"VCVTPD2DQ xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTPD2DQX xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtpd2dqx xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.F2.0F.W1 E6 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","Y","128" +"VCVTPD2DQ xmm1, ymm2/m256","VCVTPD2DQY ymm2/m256, xmm1","vcvtpd2dqy ymm2/m256, xmm1","VEX.256.F2.0F.WIG E6 /r","V","V","AVX","","w,r","Y","256" +"VCVTPD2DQ xmm1, {k}{z}, ymm2/m256/m64bcst","VCVTPD2DQY ymm2/m256/m64bcst, {k}{z}, xmm1","vcvtpd2dqy ymm2/m256/m64bcst, {k}{z}, xmm1","EVEX.256.F2.0F.W1 E6 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","Y","256" +"VCVTPD2PS ymm1{er}, {k}{z}, zmm2","VCVTPD2PS zmm2, {k}{z}, ymm1{er}","vcvtpd2ps zmm2, {k}{z}, ymm1{er}","EVEX.512.66.0F.W1 5A /r","V","V","AVX512F","modrm_regonly","w,r,r","Y","" +"VCVTPD2PS ymm1, {k}{z}, zmm2/m512/m64bcst","VCVTPD2PS zmm2/m512/m64bcst, {k}{z}, ymm1","vcvtpd2ps zmm2/m512/m64bcst, {k}{z}, ymm1","EVEX.512.66.0F.W1 5A /r","V","V","AVX512F","bscale8,scale64","w,r,r","Y","512" +"VCVTPD2PS xmm1, xmm2/m128","VCVTPD2PSX xmm2/m128, xmm1","vcvtpd2psx xmm2/m128, xmm1","VEX.128.66.0F.WIG 5A /r","V","V","AVX","","w,r","Y","128" +"VCVTPD2PS xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTPD2PSX xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtpd2psx xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F.W1 5A /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","Y","128" +"VCVTPD2PS xmm1, ymm2/m256","VCVTPD2PSY ymm2/m256, xmm1","vcvtpd2psy ymm2/m256, xmm1","VEX.256.66.0F.WIG 5A /r","V","V","AVX","","w,r","Y","256" +"VCVTPD2PS xmm1, {k}{z}, ymm2/m256/m64bcst","VCVTPD2PSY ymm2/m256/m64bcst, {k}{z}, xmm1","vcvtpd2psy ymm2/m256/m64bcst, {k}{z}, xmm1","EVEX.256.66.0F.W1 5A /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","Y","256" +"VCVTPD2QQ xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTPD2QQ xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtpd2qq xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F.W1 7B /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r","","" +"VCVTPD2QQ ymm1, {k}{z}, ymm2/m256/m64bcst","VCVTPD2QQ ymm2/m256/m64bcst, {k}{z}, ymm1","vcvtpd2qq ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F.W1 7B /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r","","" +"VCVTPD2QQ zmm1{er}, {k}{z}, zmm2","VCVTPD2QQ zmm2, {k}{z}, zmm1{er}","vcvtpd2qq zmm2, {k}{z}, zmm1{er}","EVEX.512.66.0F.W1 7B /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTPD2QQ zmm1, {k}{z}, zmm2/m512/m64bcst","VCVTPD2QQ zmm2/m512/m64bcst, {k}{z}, zmm1","vcvtpd2qq zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F.W1 7B /r","V","V","AVX512DQ","bscale8,scale64","w,r,r","","" +"VCVTPD2UDQ ymm1{er}, {k}{z}, zmm2","VCVTPD2UDQ zmm2, {k}{z}, ymm1{er}","vcvtpd2udq zmm2, {k}{z}, ymm1{er}","EVEX.512.0F.W1 79 /r","V","V","AVX512F","modrm_regonly","w,r,r","Y","" +"VCVTPD2UDQ ymm1, {k}{z}, zmm2/m512/m64bcst","VCVTPD2UDQ zmm2/m512/m64bcst, {k}{z}, ymm1","vcvtpd2udq zmm2/m512/m64bcst, {k}{z}, ymm1","EVEX.512.0F.W1 79 /r","V","V","AVX512F","bscale8,scale64","w,r,r","Y","512" +"VCVTPD2UDQ xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTPD2UDQX xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtpd2udqx xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.0F.W1 79 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","Y","128" +"VCVTPD2UDQ xmm1, {k}{z}, ymm2/m256/m64bcst","VCVTPD2UDQY ymm2/m256/m64bcst, {k}{z}, xmm1","vcvtpd2udqy ymm2/m256/m64bcst, {k}{z}, xmm1","EVEX.256.0F.W1 79 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","Y","256" +"VCVTPD2UQQ xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTPD2UQQ xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtpd2uqq xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F.W1 79 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r","","" +"VCVTPD2UQQ ymm1, {k}{z}, ymm2/m256/m64bcst","VCVTPD2UQQ ymm2/m256/m64bcst, {k}{z}, ymm1","vcvtpd2uqq ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F.W1 79 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r","","" +"VCVTPD2UQQ zmm1{er}, {k}{z}, zmm2","VCVTPD2UQQ zmm2, {k}{z}, zmm1{er}","vcvtpd2uqq zmm2, {k}{z}, zmm1{er}","EVEX.512.66.0F.W1 79 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTPD2UQQ zmm1, {k}{z}, zmm2/m512/m64bcst","VCVTPD2UQQ zmm2/m512/m64bcst, {k}{z}, zmm1","vcvtpd2uqq zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F.W1 79 /r","V","V","AVX512DQ","bscale8,scale64","w,r,r","","" +"VCVTPH2PS ymm1, xmm2/m128","VCVTPH2PS xmm2/m128, ymm1","vcvtph2ps xmm2/m128, ymm1","VEX.256.66.0F38.W0 13 /r","V","V","F16C","","w,r","","" +"VCVTPH2PS ymm1, {k}{z}, xmm2/m128","VCVTPH2PS xmm2/m128, {k}{z}, ymm1","vcvtph2ps xmm2/m128, {k}{z}, ymm1","EVEX.256.66.0F38.W0 13 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VCVTPH2PS xmm1, xmm2/m64","VCVTPH2PS xmm2/m64, xmm1","vcvtph2ps xmm2/m64, xmm1","VEX.128.66.0F38.W0 13 /r","V","V","F16C","","w,r","","" +"VCVTPH2PS xmm1, {k}{z}, xmm2/m64","VCVTPH2PS xmm2/m64, {k}{z}, xmm1","vcvtph2ps xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.W0 13 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VCVTPH2PS zmm1{sae}, {k}{z}, ymm2","VCVTPH2PS ymm2, {k}{z}, zmm1{sae}","vcvtph2ps ymm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W0 13 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VCVTPH2PS zmm1, {k}{z}, ymm2/m256","VCVTPH2PS ymm2/m256, {k}{z}, zmm1","vcvtph2ps ymm2/m256, {k}{z}, zmm1","EVEX.512.66.0F38.W0 13 /r","V","V","AVX512F","scale32","w,r,r","","" +"VCVTPS2DQ xmm1, xmm2/m128","VCVTPS2DQ xmm2/m128, xmm1","vcvtps2dq xmm2/m128, xmm1","VEX.128.66.0F.WIG 5B /r","V","V","AVX","","w,r","","" +"VCVTPS2DQ xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTPS2DQ xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtps2dq xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F.W0 5B /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTPS2DQ ymm1, ymm2/m256","VCVTPS2DQ ymm2/m256, ymm1","vcvtps2dq ymm2/m256, ymm1","VEX.256.66.0F.WIG 5B /r","V","V","AVX","","w,r","","" +"VCVTPS2DQ ymm1, {k}{z}, ymm2/m256/m32bcst","VCVTPS2DQ ymm2/m256/m32bcst, {k}{z}, ymm1","vcvtps2dq ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F.W0 5B /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VCVTPS2DQ zmm1{er}, {k}{z}, zmm2","VCVTPS2DQ zmm2, {k}{z}, zmm1{er}","vcvtps2dq zmm2, {k}{z}, zmm1{er}","EVEX.512.66.0F.W0 5B /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VCVTPS2DQ zmm1, {k}{z}, zmm2/m512/m32bcst","VCVTPS2DQ zmm2/m512/m32bcst, {k}{z}, zmm1","vcvtps2dq zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F.W0 5B /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VCVTPS2PD ymm1, xmm2/m128","VCVTPS2PD xmm2/m128, ymm1","vcvtps2pd xmm2/m128, ymm1","VEX.256.0F.WIG 5A /r","V","V","AVX","","w,r","","" +"VCVTPS2PD xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTPS2PD xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtps2pd xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.0F.W0 5A /r","V","V","AVX512F+AVX512VL","bscale4,scale8","w,r,r","","" +"VCVTPS2PD ymm1, {k}{z}, xmm2/m256/m32bcst","VCVTPS2PD xmm2/m256/m32bcst, {k}{z}, ymm1","vcvtps2pd xmm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.0F.W0 5A /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTPS2PD xmm1, xmm2/m64","VCVTPS2PD xmm2/m64, xmm1","vcvtps2pd xmm2/m64, xmm1","VEX.128.0F.WIG 5A /r","V","V","AVX","","w,r","","" +"VCVTPS2PD zmm1{sae}, {k}{z}, ymm2","VCVTPS2PD ymm2, {k}{z}, zmm1{sae}","vcvtps2pd ymm2, {k}{z}, zmm1{sae}","EVEX.512.0F.W0 5A /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VCVTPS2PD zmm1, {k}{z}, ymm2/m512/m32bcst","VCVTPS2PD ymm2/m512/m32bcst, {k}{z}, zmm1","vcvtps2pd ymm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.0F.W0 5A /r","V","V","AVX512F","bscale4,scale32","w,r,r","","" +"VCVTPS2PH xmm2/m64, xmm1, imm8u","VCVTPS2PH imm8u, xmm1, xmm2/m64","vcvtps2ph imm8u, xmm1, xmm2/m64","VEX.128.66.0F3A.W0 1D /r ib","V","V","F16C","","w,r,r","","" +"VCVTPS2PH xmm2/m64, {k}{z}, xmm1, imm8u","VCVTPS2PH imm8u, xmm1, {k}{z}, xmm2/m64","vcvtps2ph imm8u, xmm1, {k}{z}, xmm2/m64","EVEX.128.66.0F3A.W0 1D /r ib","V","V","AVX512F+AVX512VL","scale8","w,r,r,r","","" +"VCVTPS2PH xmm2/m128, ymm1, imm8u","VCVTPS2PH imm8u, ymm1, xmm2/m128","vcvtps2ph imm8u, ymm1, xmm2/m128","VEX.256.66.0F3A.W0 1D /r ib","V","V","F16C","","w,r,r","","" +"VCVTPS2PH xmm2/m128, {k}{z}, ymm1, imm8u","VCVTPS2PH imm8u, ymm1, {k}{z}, xmm2/m128","vcvtps2ph imm8u, ymm1, {k}{z}, xmm2/m128","EVEX.256.66.0F3A.W0 1D /r ib","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VCVTPS2PH ymm2/m256, {k}{z}, zmm1, imm8u","VCVTPS2PH imm8u, zmm1, {k}{z}, ymm2/m256","vcvtps2ph imm8u, zmm1, {k}{z}, ymm2/m256","EVEX.512.66.0F3A.W0 1D /r ib","V","V","AVX512F","scale32","w,r,r,r","","" +"VCVTPS2PH ymm2{sae}, {k}{z}, zmm1, imm8u","VCVTPS2PH imm8u, zmm1, {k}{z}, ymm2{sae}","vcvtps2ph imm8u, zmm1, {k}{z}, ymm2{sae}","EVEX.512.66.0F3A.W0 1D /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VCVTPS2QQ xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTPS2QQ xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtps2qq xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F.W0 7B /r","V","V","AVX512DQ+AVX512VL","bscale4,scale8","w,r,r","","" +"VCVTPS2QQ ymm1, {k}{z}, xmm2/m256/m32bcst","VCVTPS2QQ xmm2/m256/m32bcst, {k}{z}, ymm1","vcvtps2qq xmm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F.W0 7B /r","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTPS2QQ zmm1{er}, {k}{z}, ymm2","VCVTPS2QQ ymm2, {k}{z}, zmm1{er}","vcvtps2qq ymm2, {k}{z}, zmm1{er}","EVEX.512.66.0F.W0 7B /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTPS2QQ zmm1, {k}{z}, ymm2/m512/m32bcst","VCVTPS2QQ ymm2/m512/m32bcst, {k}{z}, zmm1","vcvtps2qq ymm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F.W0 7B /r","V","V","AVX512DQ","bscale4,scale32","w,r,r","","" +"VCVTPS2UDQ xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTPS2UDQ xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtps2udq xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.0F.W0 79 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTPS2UDQ ymm1, {k}{z}, ymm2/m256/m32bcst","VCVTPS2UDQ ymm2/m256/m32bcst, {k}{z}, ymm1","vcvtps2udq ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.0F.W0 79 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VCVTPS2UDQ zmm1{er}, {k}{z}, zmm2","VCVTPS2UDQ zmm2, {k}{z}, zmm1{er}","vcvtps2udq zmm2, {k}{z}, zmm1{er}","EVEX.512.0F.W0 79 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VCVTPS2UDQ zmm1, {k}{z}, zmm2/m512/m32bcst","VCVTPS2UDQ zmm2/m512/m32bcst, {k}{z}, zmm1","vcvtps2udq zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.0F.W0 79 /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VCVTPS2UQQ xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTPS2UQQ xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtps2uqq xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F.W0 79 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale8","w,r,r","","" +"VCVTPS2UQQ ymm1, {k}{z}, xmm2/m256/m32bcst","VCVTPS2UQQ xmm2/m256/m32bcst, {k}{z}, ymm1","vcvtps2uqq xmm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F.W0 79 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTPS2UQQ zmm1{er}, {k}{z}, ymm2","VCVTPS2UQQ ymm2, {k}{z}, zmm1{er}","vcvtps2uqq ymm2, {k}{z}, zmm1{er}","EVEX.512.66.0F.W0 79 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTPS2UQQ zmm1, {k}{z}, ymm2/m512/m32bcst","VCVTPS2UQQ ymm2/m512/m32bcst, {k}{z}, zmm1","vcvtps2uqq ymm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F.W0 79 /r","V","V","AVX512DQ","bscale4,scale32","w,r,r","","" +"VCVTQQ2PD xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTQQ2PD xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtqq2pd xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.F3.0F.W1 E6 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r","","" +"VCVTQQ2PD ymm1, {k}{z}, ymm2/m256/m64bcst","VCVTQQ2PD ymm2/m256/m64bcst, {k}{z}, ymm1","vcvtqq2pd ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.F3.0F.W1 E6 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r","","" +"VCVTQQ2PD zmm1{er}, {k}{z}, zmm2","VCVTQQ2PD zmm2, {k}{z}, zmm1{er}","vcvtqq2pd zmm2, {k}{z}, zmm1{er}","EVEX.512.F3.0F.W1 E6 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTQQ2PD zmm1, {k}{z}, zmm2/m512/m64bcst","VCVTQQ2PD zmm2/m512/m64bcst, {k}{z}, zmm1","vcvtqq2pd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.F3.0F.W1 E6 /r","V","V","AVX512DQ","bscale8,scale64","w,r,r","","" +"VCVTQQ2PS ymm1{er}, {k}{z}, zmm2","VCVTQQ2PS zmm2, {k}{z}, ymm1{er}","vcvtqq2ps zmm2, {k}{z}, ymm1{er}","EVEX.512.0F.W1 5B /r","V","V","AVX512DQ","modrm_regonly","w,r,r","Y","" +"VCVTQQ2PS ymm1, {k}{z}, zmm2/m512/m64bcst","VCVTQQ2PS zmm2/m512/m64bcst, {k}{z}, ymm1","vcvtqq2ps zmm2/m512/m64bcst, {k}{z}, ymm1","EVEX.512.0F.W1 5B /r","V","V","AVX512DQ","bscale8,scale64","w,r,r","Y","512" +"VCVTQQ2PS xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTQQ2PSX xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtqq2psx xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.0F.W1 5B /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r","Y","128" +"VCVTQQ2PS xmm1, {k}{z}, ymm2/m256/m64bcst","VCVTQQ2PSY ymm2/m256/m64bcst, {k}{z}, xmm1","vcvtqq2psy ymm2/m256/m64bcst, {k}{z}, xmm1","EVEX.256.0F.W1 5B /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r","Y","256" +"VCVTSD2SI r32{er}, xmm2","VCVTSD2SI xmm2, r32{er}","vcvtsd2si xmm2, r32{er}","EVEX.128.F2.0F.W0 2D /r","V","V","AVX512F","modrm_regonly","w,r","Y","32" +"VCVTSD2SI r32, xmm2/m64","VCVTSD2SI xmm2/m64, r32","vcvtsd2si xmm2/m64, r32","EVEX.LIG.F2.0F.W0 2D /r","V","V","AVX512F","scale8","w,r","Y","32" +"VCVTSD2SI r32, xmm2/m64","VCVTSD2SI xmm2/m64, r32","vcvtsd2si xmm2/m64, r32","VEX.LIG.F2.0F.W0 2D /r","V","V","AVX","","w,r","Y","32" +"VCVTSD2SI r64{er}, xmm2","VCVTSD2SIQ xmm2, r64{er}","vcvtsd2siq xmm2, r64{er}","EVEX.128.F2.0F.W1 2D /r","N.S.","V","AVX512F","modrm_regonly","w,r","Y","64" +"VCVTSD2SI r64, xmm2/m64","VCVTSD2SIQ xmm2/m64, r64","vcvtsd2siq xmm2/m64, r64","EVEX.LIG.F2.0F.W1 2D /r","N.S.","V","AVX512F","scale8","w,r","Y","64" +"VCVTSD2SI r64, xmm2/m64","VCVTSD2SIQ xmm2/m64, r64","vcvtsd2siq xmm2/m64, r64","VEX.LIG.F2.0F.W1 2D /r","N.S.","V","AVX","","w,r","Y","64" +"VCVTSD2SS xmm1{er}, {k}{z}, xmmV, xmm2","VCVTSD2SS xmm2, xmmV, {k}{z}, xmm1{er}","vcvtsd2ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F2.0F.W1 5A /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VCVTSD2SS xmm1, xmmV, xmm2/m64","VCVTSD2SS xmm2/m64, xmmV, xmm1","vcvtsd2ss xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 5A /r","V","V","AVX","","w,r,r","","" +"VCVTSD2SS xmm1, {k}{z}, xmmV, xmm2/m64","VCVTSD2SS xmm2/m64, xmmV, {k}{z}, xmm1","vcvtsd2ss xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 5A /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VCVTSD2USI r32{er}, xmm2","VCVTSD2USIL xmm2, r32{er}","vcvtsd2usi xmm2, r32{er}","EVEX.128.F2.0F.W0 79 /r","V","V","AVX512F","modrm_regonly","w,r","Y","32" +"VCVTSD2USI r32, xmm2/m64","VCVTSD2USIL xmm2/m64, r32","vcvtsd2usi xmm2/m64, r32","EVEX.LIG.F2.0F.W0 79 /r","V","V","AVX512F","scale8","w,r","Y","32" +"VCVTSD2USI r64{er}, xmm2","VCVTSD2USIQ xmm2, r64{er}","vcvtsd2usi xmm2, r64{er}","EVEX.128.F2.0F.W1 79 /r","N.S.","V","AVX512F","modrm_regonly","w,r","Y","64" +"VCVTSD2USI r64, xmm2/m64","VCVTSD2USIQ xmm2/m64, r64","vcvtsd2usi xmm2/m64, r64","EVEX.LIG.F2.0F.W1 79 /r","N.S.","V","AVX512F","scale8","w,r","Y","64" +"VCVTSI2SD xmm1, xmmV, r/m32","VCVTSI2SDL r/m32, xmmV, xmm1","vcvtsi2sdl r/m32, xmmV, xmm1","EVEX.NDS.LIG.F2.0F.W0 2A /r","V","V","AVX512F","scale4","w,r,r","Y","32" +"VCVTSI2SD xmm1, xmmV, r/m32","VCVTSI2SDL r/m32, xmmV, xmm1","vcvtsi2sdl r/m32, xmmV, xmm1","VEX.NDS.LIG.F2.0F.W0 2A /r","V","V","AVX","","w,r,r","Y","32" +"VCVTSI2SD xmm1, xmmV, r/m64","VCVTSI2SDQ r/m64, xmmV, xmm1","vcvtsi2sdq r/m64, xmmV, xmm1","EVEX.NDS.LIG.F2.0F.W1 2A /r","N.S.","V","AVX512F","scale8","w,r,r","Y","64" +"VCVTSI2SD xmm1, xmmV, r/m64","VCVTSI2SDQ r/m64, xmmV, xmm1","vcvtsi2sdq r/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.W1 2A /r","N.S.","V","AVX","","w,r,r","Y","64" +"VCVTSI2SD xmm1{er}, xmmV, rmr64","VCVTSI2SDQ rmr64, xmmV, xmm1{er}","vcvtsi2sdq rmr64, xmmV, xmm1{er}","EVEX.NDS.128.F2.0F.W1 2A /r","N.S.","V","AVX512F","modrm_regonly","w,r,r","Y","64" +"VCVTSI2SS xmm1, xmmV, r/m32","VCVTSI2SSL r/m32, xmmV, xmm1","vcvtsi2ssl r/m32, xmmV, xmm1","EVEX.NDS.LIG.F3.0F.W0 2A /r","V","V","AVX512F","scale4","w,r,r","Y","32" +"VCVTSI2SS xmm1, xmmV, r/m32","VCVTSI2SSL r/m32, xmmV, xmm1","vcvtsi2ssl r/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.W0 2A /r","V","V","AVX","","w,r,r","Y","32" +"VCVTSI2SS xmm1{er}, xmmV, rmr32","VCVTSI2SSL rmr32, xmmV, xmm1{er}","vcvtsi2ssl rmr32, xmmV, xmm1{er}","EVEX.NDS.128.F3.0F.W0 2A /r","V","V","AVX512F","modrm_regonly","w,r,r","Y","32" +"VCVTSI2SS xmm1, xmmV, r/m64","VCVTSI2SSQ r/m64, xmmV, xmm1","vcvtsi2ssq r/m64, xmmV, xmm1","EVEX.NDS.LIG.F3.0F.W1 2A /r","N.S.","V","AVX512F","scale8","w,r,r","Y","64" +"VCVTSI2SS xmm1, xmmV, r/m64","VCVTSI2SSQ r/m64, xmmV, xmm1","vcvtsi2ssq r/m64, xmmV, xmm1","VEX.NDS.LIG.F3.0F.W1 2A /r","N.S.","V","AVX","","w,r,r","Y","64" +"VCVTSI2SS xmm1{er}, xmmV, rmr64","VCVTSI2SSQ rmr64, xmmV, xmm1{er}","vcvtsi2ssq rmr64, xmmV, xmm1{er}","EVEX.NDS.128.F3.0F.W1 2A /r","N.S.","V","AVX512F","modrm_regonly","w,r,r","Y","64" +"VCVTSS2SD xmm1{sae}, {k}{z}, xmmV, xmm2","VCVTSS2SD xmm2, xmmV, {k}{z}, xmm1{sae}","vcvtss2sd xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.F3.0F.W0 5A /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VCVTSS2SD xmm1, xmmV, xmm2/m32","VCVTSS2SD xmm2/m32, xmmV, xmm1","vcvtss2sd xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 5A /r","V","V","AVX","","w,r,r","","" +"VCVTSS2SD xmm1, {k}{z}, xmmV, xmm2/m32","VCVTSS2SD xmm2/m32, xmmV, {k}{z}, xmm1","vcvtss2sd xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 5A /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VCVTSS2SI r32{er}, xmm2","VCVTSS2SI xmm2, r32{er}","vcvtss2si xmm2, r32{er}","EVEX.128.F3.0F.W0 2D /r","V","V","AVX512F","modrm_regonly","w,r","Y","32" +"VCVTSS2SI r32, xmm2/m32","VCVTSS2SI xmm2/m32, r32","vcvtss2si xmm2/m32, r32","EVEX.LIG.F3.0F.W0 2D /r","V","V","AVX512F","scale4","w,r","Y","32" +"VCVTSS2SI r32, xmm2/m32","VCVTSS2SI xmm2/m32, r32","vcvtss2si xmm2/m32, r32","VEX.LIG.F3.0F.W0 2D /r","V","V","AVX","","w,r","Y","32" +"VCVTSS2SI r64{er}, xmm2","VCVTSS2SIQ xmm2, r64{er}","vcvtss2siq xmm2, r64{er}","EVEX.128.F3.0F.W1 2D /r","N.S.","V","AVX512F","modrm_regonly","w,r","Y","64" +"VCVTSS2SI r64, xmm2/m32","VCVTSS2SIQ xmm2/m32, r64","vcvtss2siq xmm2/m32, r64","EVEX.LIG.F3.0F.W1 2D /r","N.S.","V","AVX512F","scale4","w,r","Y","64" +"VCVTSS2SI r64, xmm2/m32","VCVTSS2SIQ xmm2/m32, r64","vcvtss2siq xmm2/m32, r64","VEX.LIG.F3.0F.W1 2D /r","N.S.","V","AVX","","w,r","Y","64" +"VCVTSS2USI r32{er}, xmm2","VCVTSS2USIL xmm2, r32{er}","vcvtss2usil xmm2, r32{er}","EVEX.128.F3.0F.W0 79 /r","V","V","AVX512F","modrm_regonly","w,r","Y","32" +"VCVTSS2USI r32, xmm2/m32","VCVTSS2USIL xmm2/m32, r32","vcvtss2usil xmm2/m32, r32","EVEX.LIG.F3.0F.W0 79 /r","V","V","AVX512F","scale4","w,r","Y","32" +"VCVTSS2USI r64{er}, xmm2","VCVTSS2USIQ xmm2, r64{er}","vcvtss2usiq xmm2, r64{er}","EVEX.128.F3.0F.W1 79 /r","N.S.","V","AVX512F","modrm_regonly","w,r","Y","64" +"VCVTSS2USI r64, xmm2/m32","VCVTSS2USIQ xmm2/m32, r64","vcvtss2usiq xmm2/m32, r64","EVEX.LIG.F3.0F.W1 79 /r","N.S.","V","AVX512F","scale4","w,r","Y","64" +"VCVTTPD2DQ ymm1{sae}, {k}{z}, zmm2","VCVTTPD2DQ zmm2, {k}{z}, ymm1{sae}","vcvttpd2dq zmm2, {k}{z}, ymm1{sae}","EVEX.512.66.0F.W1 E6 /r","V","V","AVX512F","modrm_regonly","w,r,r","Y","" +"VCVTTPD2DQ ymm1, {k}{z}, zmm2/m512/m64bcst","VCVTTPD2DQ zmm2/m512/m64bcst, {k}{z}, ymm1","vcvttpd2dq zmm2/m512/m64bcst, {k}{z}, ymm1","EVEX.512.66.0F.W1 E6 /r","V","V","AVX512F","bscale8,scale64","w,r,r","Y","512" +"VCVTTPD2DQ xmm1, xmm2/m128","VCVTTPD2DQX xmm2/m128, xmm1","vcvttpd2dqx xmm2/m128, xmm1","VEX.128.66.0F.WIG E6 /r","V","V","AVX","","w,r","Y","128" +"VCVTTPD2DQ xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTTPD2DQX xmm2/m128/m64bcst, {k}{z}, xmm1","vcvttpd2dqx xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F.W1 E6 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","Y","128" +"VCVTTPD2DQ xmm1, ymm2/m256","VCVTTPD2DQY ymm2/m256, xmm1","vcvttpd2dqy ymm2/m256, xmm1","VEX.256.66.0F.WIG E6 /r","V","V","AVX","","w,r","Y","256" +"VCVTTPD2DQ xmm1, {k}{z}, ymm2/m256/m64bcst","VCVTTPD2DQY ymm2/m256/m64bcst, {k}{z}, xmm1","vcvttpd2dqy ymm2/m256/m64bcst, {k}{z}, xmm1","EVEX.256.66.0F.W1 E6 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","Y","256" +"VCVTTPD2QQ xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTTPD2QQ xmm2/m128/m64bcst, {k}{z}, xmm1","vcvttpd2qq xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F.W1 7A /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r","","" +"VCVTTPD2QQ ymm1, {k}{z}, ymm2/m256/m64bcst","VCVTTPD2QQ ymm2/m256/m64bcst, {k}{z}, ymm1","vcvttpd2qq ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F.W1 7A /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r","","" +"VCVTTPD2QQ zmm1{sae}, {k}{z}, zmm2","VCVTTPD2QQ zmm2, {k}{z}, zmm1{sae}","vcvttpd2qq zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F.W1 7A /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTTPD2QQ zmm1, {k}{z}, zmm2/m512/m64bcst","VCVTTPD2QQ zmm2/m512/m64bcst, {k}{z}, zmm1","vcvttpd2qq zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F.W1 7A /r","V","V","AVX512DQ","bscale8,scale64","w,r,r","","" +"VCVTTPD2UDQ ymm1{sae}, {k}{z}, zmm2","VCVTTPD2UDQ zmm2, {k}{z}, ymm1{sae}","vcvttpd2udq zmm2, {k}{z}, ymm1{sae}","EVEX.512.0F.W1 78 /r","V","V","AVX512F","modrm_regonly","w,r,r","Y","" +"VCVTTPD2UDQ ymm1, {k}{z}, zmm2/m512/m64bcst","VCVTTPD2UDQ zmm2/m512/m64bcst, {k}{z}, ymm1","vcvttpd2udq zmm2/m512/m64bcst, {k}{z}, ymm1","EVEX.512.0F.W1 78 /r","V","V","AVX512F","bscale8,scale64","w,r,r","Y","512" +"VCVTTPD2UDQ xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTTPD2UDQX xmm2/m128/m64bcst, {k}{z}, xmm1","vcvttpd2udqx xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.0F.W1 78 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","Y","128" +"VCVTTPD2UDQ xmm1, {k}{z}, ymm2/m256/m64bcst","VCVTTPD2UDQY ymm2/m256/m64bcst, {k}{z}, xmm1","vcvttpd2udqy ymm2/m256/m64bcst, {k}{z}, xmm1","EVEX.256.0F.W1 78 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","Y","256" +"VCVTTPD2UQQ xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTTPD2UQQ xmm2/m128/m64bcst, {k}{z}, xmm1","vcvttpd2uqq xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F.W1 78 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r","","" +"VCVTTPD2UQQ ymm1, {k}{z}, ymm2/m256/m64bcst","VCVTTPD2UQQ ymm2/m256/m64bcst, {k}{z}, ymm1","vcvttpd2uqq ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F.W1 78 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r","","" +"VCVTTPD2UQQ zmm1{sae}, {k}{z}, zmm2","VCVTTPD2UQQ zmm2, {k}{z}, zmm1{sae}","vcvttpd2uqq zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F.W1 78 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTTPD2UQQ zmm1, {k}{z}, zmm2/m512/m64bcst","VCVTTPD2UQQ zmm2/m512/m64bcst, {k}{z}, zmm1","vcvttpd2uqq zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F.W1 78 /r","V","V","AVX512DQ","bscale8,scale64","w,r,r","","" +"VCVTTPS2DQ xmm1, xmm2/m128","VCVTTPS2DQ xmm2/m128, xmm1","vcvttps2dq xmm2/m128, xmm1","VEX.128.F3.0F.WIG 5B /r","V","V","AVX","","w,r","","" +"VCVTTPS2DQ xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTTPS2DQ xmm2/m128/m32bcst, {k}{z}, xmm1","vcvttps2dq xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.F3.0F.W0 5B /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTTPS2DQ ymm1, ymm2/m256","VCVTTPS2DQ ymm2/m256, ymm1","vcvttps2dq ymm2/m256, ymm1","VEX.256.F3.0F.WIG 5B /r","V","V","AVX","","w,r","","" +"VCVTTPS2DQ ymm1, {k}{z}, ymm2/m256/m32bcst","VCVTTPS2DQ ymm2/m256/m32bcst, {k}{z}, ymm1","vcvttps2dq ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.F3.0F.W0 5B /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VCVTTPS2DQ zmm1{sae}, {k}{z}, zmm2","VCVTTPS2DQ zmm2, {k}{z}, zmm1{sae}","vcvttps2dq zmm2, {k}{z}, zmm1{sae}","EVEX.512.F3.0F.W0 5B /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VCVTTPS2DQ zmm1, {k}{z}, zmm2/m512/m32bcst","VCVTTPS2DQ zmm2/m512/m32bcst, {k}{z}, zmm1","vcvttps2dq zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.F3.0F.W0 5B /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VCVTTPS2QQ xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTTPS2QQ xmm2/m128/m32bcst, {k}{z}, xmm1","vcvttps2qq xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F.W0 7A /r","V","V","AVX512DQ+AVX512VL","bscale4,scale8","w,r,r","","" +"VCVTTPS2QQ ymm1, {k}{z}, xmm2/m256/m32bcst","VCVTTPS2QQ xmm2/m256/m32bcst, {k}{z}, ymm1","vcvttps2qq xmm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F.W0 7A /r","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTTPS2QQ zmm1{sae}, {k}{z}, ymm2","VCVTTPS2QQ ymm2, {k}{z}, zmm1{sae}","vcvttps2qq ymm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F.W0 7A /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTTPS2QQ zmm1, {k}{z}, ymm2/m512/m32bcst","VCVTTPS2QQ ymm2/m512/m32bcst, {k}{z}, zmm1","vcvttps2qq ymm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F.W0 7A /r","V","V","AVX512DQ","bscale4,scale32","w,r,r","","" +"VCVTTPS2UDQ xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTTPS2UDQ xmm2/m128/m32bcst, {k}{z}, xmm1","vcvttps2udq xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.0F.W0 78 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTTPS2UDQ ymm1, {k}{z}, ymm2/m256/m32bcst","VCVTTPS2UDQ ymm2/m256/m32bcst, {k}{z}, ymm1","vcvttps2udq ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.0F.W0 78 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VCVTTPS2UDQ zmm1{sae}, {k}{z}, zmm2","VCVTTPS2UDQ zmm2, {k}{z}, zmm1{sae}","vcvttps2udq zmm2, {k}{z}, zmm1{sae}","EVEX.512.0F.W0 78 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VCVTTPS2UDQ zmm1, {k}{z}, zmm2/m512/m32bcst","VCVTTPS2UDQ zmm2/m512/m32bcst, {k}{z}, zmm1","vcvttps2udq zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.0F.W0 78 /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VCVTTPS2UQQ xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTTPS2UQQ xmm2/m128/m32bcst, {k}{z}, xmm1","vcvttps2uqq xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F.W0 78 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale8","w,r,r","","" +"VCVTTPS2UQQ ymm1, {k}{z}, xmm2/m256/m32bcst","VCVTTPS2UQQ xmm2/m256/m32bcst, {k}{z}, ymm1","vcvttps2uqq xmm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F.W0 78 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTTPS2UQQ zmm1{sae}, {k}{z}, ymm2","VCVTTPS2UQQ ymm2, {k}{z}, zmm1{sae}","vcvttps2uqq ymm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F.W0 78 /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTTPS2UQQ zmm1, {k}{z}, ymm2/m512/m32bcst","VCVTTPS2UQQ ymm2/m512/m32bcst, {k}{z}, zmm1","vcvttps2uqq ymm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F.W0 78 /r","V","V","AVX512DQ","bscale4,scale32","w,r,r","","" +"VCVTTSD2SI r32{sae}, xmm2","VCVTTSD2SI xmm2, r32{sae}","vcvttsd2si xmm2, r32{sae}","EVEX.128.F2.0F.W0 2C /r","V","V","AVX512F","modrm_regonly","w,r","Y","32" +"VCVTTSD2SI r32, xmm2/m64","VCVTTSD2SI xmm2/m64, r32","vcvttsd2si xmm2/m64, r32","EVEX.LIG.F2.0F.W0 2C /r","V","V","AVX512F","scale8","w,r","Y","32" +"VCVTTSD2SI r32, xmm2/m64","VCVTTSD2SI xmm2/m64, r32","vcvttsd2si xmm2/m64, r32","VEX.LIG.F2.0F.W0 2C /r","V","V","AVX","","w,r","Y","32" +"VCVTTSD2SI r64{sae}, xmm2","VCVTTSD2SIQ xmm2, r64{sae}","vcvttsd2siq xmm2, r64{sae}","EVEX.128.F2.0F.W1 2C /r","N.S.","V","AVX512F","modrm_regonly","w,r","Y","64" +"VCVTTSD2SI r64, xmm2/m64","VCVTTSD2SIQ xmm2/m64, r64","vcvttsd2siq xmm2/m64, r64","EVEX.LIG.F2.0F.W1 2C /r","N.S.","V","AVX512F","scale8","w,r","Y","64" +"VCVTTSD2SI r64, xmm2/m64","VCVTTSD2SIQ xmm2/m64, r64","vcvttsd2siq xmm2/m64, r64","VEX.LIG.F2.0F.W1 2C /r","N.S.","V","AVX","","w,r","Y","64" +"VCVTTSD2USI r32{sae}, xmm2","VCVTTSD2USIL xmm2, r32{sae}","vcvttsd2usil xmm2, r32{sae}","EVEX.128.F2.0F.W0 78 /r","V","V","AVX512F","modrm_regonly","w,r","Y","32" +"VCVTTSD2USI r32, xmm2/m64","VCVTTSD2USIL xmm2/m64, r32","vcvttsd2usil xmm2/m64, r32","EVEX.LIG.F2.0F.W0 78 /r","V","V","AVX512F","scale8","w,r","Y","32" +"VCVTTSD2USI r64{sae}, xmm2","VCVTTSD2USIQ xmm2, r64{sae}","vcvttsd2usiq xmm2, r64{sae}","EVEX.128.F2.0F.W1 78 /r","N.S.","V","AVX512F","modrm_regonly","w,r","Y","64" +"VCVTTSD2USI r64, xmm2/m64","VCVTTSD2USIQ xmm2/m64, r64","vcvttsd2usiq xmm2/m64, r64","EVEX.LIG.F2.0F.W1 78 /r","N.S.","V","AVX512F","scale8","w,r","Y","64" +"VCVTTSS2SI r32{sae}, xmm2","VCVTTSS2SI xmm2, r32{sae}","vcvttss2si xmm2, r32{sae}","EVEX.128.F3.0F.W0 2C /r","V","V","AVX512F","modrm_regonly","w,r","Y","32" +"VCVTTSS2SI r32, xmm2/m32","VCVTTSS2SI xmm2/m32, r32","vcvttss2si xmm2/m32, r32","EVEX.LIG.F3.0F.W0 2C /r","V","V","AVX512F","scale4","w,r","Y","32" +"VCVTTSS2SI r32, xmm2/m32","VCVTTSS2SI xmm2/m32, r32","vcvttss2si xmm2/m32, r32","VEX.LIG.F3.0F.W0 2C /r","V","V","AVX","","w,r","Y","32" +"VCVTTSS2SI r64{sae}, xmm2","VCVTTSS2SIQ xmm2, r64{sae}","vcvttss2siq xmm2, r64{sae}","EVEX.128.F3.0F.W1 2C /r","N.S.","V","AVX512F","modrm_regonly","w,r","Y","64" +"VCVTTSS2SI r64, xmm2/m32","VCVTTSS2SIQ xmm2/m32, r64","vcvttss2siq xmm2/m32, r64","EVEX.LIG.F3.0F.W1 2C /r","N.S.","V","AVX512F","scale4","w,r","Y","64" +"VCVTTSS2SI r64, xmm2/m32","VCVTTSS2SIQ xmm2/m32, r64","vcvttss2siq xmm2/m32, r64","VEX.LIG.F3.0F.W1 2C /r","N.S.","V","AVX","","w,r","Y","64" +"VCVTTSS2USI r32{sae}, xmm2","VCVTTSS2USIL xmm2, r32{sae}","vcvttss2usil xmm2, r32{sae}","EVEX.128.F3.0F.W0 78 /r","V","V","AVX512F","modrm_regonly","w,r","Y","32" +"VCVTTSS2USI r32, xmm2/m32","VCVTTSS2USIL xmm2/m32, r32","vcvttss2usil xmm2/m32, r32","EVEX.LIG.F3.0F.W0 78 /r","V","V","AVX512F","scale4","w,r","Y","32" +"VCVTTSS2USI r64{sae}, xmm2","VCVTTSS2USIQ xmm2, r64{sae}","vcvttss2usiq xmm2, r64{sae}","EVEX.128.F3.0F.W1 78 /r","N.S.","V","AVX512F","modrm_regonly","w,r","Y","64" +"VCVTTSS2USI r64, xmm2/m32","VCVTTSS2USIQ xmm2/m32, r64","vcvttss2usiq xmm2/m32, r64","EVEX.LIG.F3.0F.W1 78 /r","N.S.","V","AVX512F","scale4","w,r","Y","64" +"VCVTUDQ2PD xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTUDQ2PD xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtudq2pd xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.F3.0F.W0 7A /r","V","V","AVX512F+AVX512VL","bscale4,scale8","w,r,r","","" +"VCVTUDQ2PD ymm1, {k}{z}, xmm2/m256/m32bcst","VCVTUDQ2PD xmm2/m256/m32bcst, {k}{z}, ymm1","vcvtudq2pd xmm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.F3.0F.W0 7A /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTUDQ2PD zmm1, {k}{z}, ymm2/m512/m32bcst","VCVTUDQ2PD ymm2/m512/m32bcst, {k}{z}, zmm1","vcvtudq2pd ymm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.F3.0F.W0 7A /r","V","V","AVX512F","bscale4,scale32","w,r,r","","" +"VCVTUDQ2PS xmm1, {k}{z}, xmm2/m128/m32bcst","VCVTUDQ2PS xmm2/m128/m32bcst, {k}{z}, xmm1","vcvtudq2ps xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.F2.0F.W0 7A /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VCVTUDQ2PS ymm1, {k}{z}, ymm2/m256/m32bcst","VCVTUDQ2PS ymm2/m256/m32bcst, {k}{z}, ymm1","vcvtudq2ps ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.F2.0F.W0 7A /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VCVTUDQ2PS zmm1{er}, {k}{z}, zmm2","VCVTUDQ2PS zmm2, {k}{z}, zmm1{er}","vcvtudq2ps zmm2, {k}{z}, zmm1{er}","EVEX.512.F2.0F.W0 7A /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VCVTUDQ2PS zmm1, {k}{z}, zmm2/m512/m32bcst","VCVTUDQ2PS zmm2/m512/m32bcst, {k}{z}, zmm1","vcvtudq2ps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.F2.0F.W0 7A /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VCVTUQQ2PD xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTUQQ2PD xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtuqq2pd xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.F3.0F.W1 7A /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r","","" +"VCVTUQQ2PD ymm1, {k}{z}, ymm2/m256/m64bcst","VCVTUQQ2PD ymm2/m256/m64bcst, {k}{z}, ymm1","vcvtuqq2pd ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.F3.0F.W1 7A /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r","","" +"VCVTUQQ2PD zmm1{er}, {k}{z}, zmm2","VCVTUQQ2PD zmm2, {k}{z}, zmm1{er}","vcvtuqq2pd zmm2, {k}{z}, zmm1{er}","EVEX.512.F3.0F.W1 7A /r","V","V","AVX512DQ","modrm_regonly","w,r,r","","" +"VCVTUQQ2PD zmm1, {k}{z}, zmm2/m512/m64bcst","VCVTUQQ2PD zmm2/m512/m64bcst, {k}{z}, zmm1","vcvtuqq2pd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.F3.0F.W1 7A /r","V","V","AVX512DQ","bscale8,scale64","w,r,r","","" +"VCVTUQQ2PS ymm1{er}, {k}{z}, zmm2","VCVTUQQ2PS zmm2, {k}{z}, ymm1{er}","vcvtuqq2ps zmm2, {k}{z}, ymm1{er}","EVEX.512.F2.0F.W1 7A /r","V","V","AVX512DQ","modrm_regonly","w,r,r","Y","" +"VCVTUQQ2PS ymm1, {k}{z}, zmm2/m512/m64bcst","VCVTUQQ2PS zmm2/m512/m64bcst, {k}{z}, ymm1","vcvtuqq2ps zmm2/m512/m64bcst, {k}{z}, ymm1","EVEX.512.F2.0F.W1 7A /r","V","V","AVX512DQ","bscale8,scale64","w,r,r","Y","512" +"VCVTUQQ2PS xmm1, {k}{z}, xmm2/m128/m64bcst","VCVTUQQ2PSX xmm2/m128/m64bcst, {k}{z}, xmm1","vcvtuqq2psx xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.F2.0F.W1 7A /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r","Y","128" +"VCVTUQQ2PS xmm1, {k}{z}, ymm2/m256/m64bcst","VCVTUQQ2PSY ymm2/m256/m64bcst, {k}{z}, xmm1","vcvtuqq2psy ymm2/m256/m64bcst, {k}{z}, xmm1","EVEX.256.F2.0F.W1 7A /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r","Y","256" +"VCVTUSI2SD xmm1, xmmV, r/m32","VCVTUSI2SDL r/m32, xmmV, xmm1","vcvtusi2sd r/m32, xmmV, xmm1","EVEX.NDS.LIG.F2.0F.W0 7B /r","V","V","AVX512F","scale4","w,r,r","Y","32" +"VCVTUSI2SD xmm1, xmmV, r/m64","VCVTUSI2SDQ r/m64, xmmV, xmm1","vcvtusi2sd r/m64, xmmV, xmm1","EVEX.NDS.LIG.F2.0F.W1 7B /r","N.S.","V","AVX512F","scale8","w,r,r","Y","64" +"VCVTUSI2SD xmm1{er}, xmmV, rmr64","VCVTUSI2SDQ rmr64, xmmV, xmm1{er}","vcvtusi2sd rmr64, xmmV, xmm1{er}","EVEX.NDS.128.F2.0F.W1 7B /r","N.S.","V","AVX512F","modrm_regonly","w,r,r","Y","64" +"VCVTUSI2SS xmm1, xmmV, r/m32","VCVTUSI2SSL r/m32, xmmV, xmm1","vcvtusi2ssl r/m32, xmmV, xmm1","EVEX.NDS.LIG.F3.0F.W0 7B /r","V","V","AVX512F","scale4","w,r,r","Y","32" +"VCVTUSI2SS xmm1{er}, xmmV, rmr32","VCVTUSI2SSL rmr32, xmmV, xmm1{er}","vcvtusi2ssl rmr32, xmmV, xmm1{er}","EVEX.NDS.128.F3.0F.W0 7B /r","V","V","AVX512F","modrm_regonly","w,r,r","Y","32" +"VCVTUSI2SS xmm1, xmmV, r/m64","VCVTUSI2SSQ r/m64, xmmV, xmm1","vcvtusi2ssq r/m64, xmmV, xmm1","EVEX.NDS.LIG.F3.0F.W1 7B /r","N.S.","V","AVX512F","scale8","w,r,r","Y","64" +"VCVTUSI2SS xmm1{er}, xmmV, rmr64","VCVTUSI2SSQ rmr64, xmmV, xmm1{er}","vcvtusi2ssq rmr64, xmmV, xmm1{er}","EVEX.NDS.128.F3.0F.W1 7B /r","N.S.","V","AVX512F","modrm_regonly","w,r,r","Y","64" +"VDBPSADBW xmm1, {k}{z}, xmmV, xmm2/m128, imm8u","VDBPSADBW imm8u, xmm2/m128, xmmV, {k}{z}, xmm1","vdbpsadbw imm8u, xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W0 42 /r ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r,r","","" +"VDBPSADBW ymm1, {k}{z}, ymmV, ymm2/m256, imm8u","VDBPSADBW imm8u, ymm2/m256, ymmV, {k}{z}, ymm1","vdbpsadbw imm8u, ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 42 /r ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r,r","","" +"VDBPSADBW zmm1, {k}{z}, zmmV, zmm2/m512, imm8u","VDBPSADBW imm8u, zmm2/m512, zmmV, {k}{z}, zmm1","vdbpsadbw imm8u, zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 42 /r ib","V","V","AVX512BW","scale64","w,r,r,r,r","","" +"VDIVPD xmm1, xmmV, xmm2/m128","VDIVPD xmm2/m128, xmmV, xmm1","vdivpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 5E /r","V","V","AVX","","w,r,r","","" +"VDIVPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VDIVPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vdivpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 5E /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VDIVPD ymm1, ymmV, ymm2/m256","VDIVPD ymm2/m256, ymmV, ymm1","vdivpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 5E /r","V","V","AVX","","w,r,r","","" +"VDIVPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VDIVPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vdivpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 5E /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VDIVPD zmm1{er}, {k}{z}, zmmV, zmm2","VDIVPD zmm2, zmmV, {k}{z}, zmm1{er}","vdivpd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.66.0F.W1 5E /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VDIVPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VDIVPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vdivpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 5E /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VDIVPS xmm1, xmmV, xmm2/m128","VDIVPS xmm2/m128, xmmV, xmm1","vdivps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 5E /r","V","V","AVX","","w,r,r","","" +"VDIVPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VDIVPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vdivps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 5E /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VDIVPS ymm1, ymmV, ymm2/m256","VDIVPS ymm2/m256, ymmV, ymm1","vdivps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 5E /r","V","V","AVX","","w,r,r","","" +"VDIVPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VDIVPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vdivps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 5E /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VDIVPS zmm1{er}, {k}{z}, zmmV, zmm2","VDIVPS zmm2, zmmV, {k}{z}, zmm1{er}","vdivps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.0F.W0 5E /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VDIVPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VDIVPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vdivps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 5E /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VDIVSD xmm1{er}, {k}{z}, xmmV, xmm2","VDIVSD xmm2, xmmV, {k}{z}, xmm1{er}","vdivsd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F2.0F.W1 5E /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VDIVSD xmm1, xmmV, xmm2/m64","VDIVSD xmm2/m64, xmmV, xmm1","vdivsd xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 5E /r","V","V","AVX","","w,r,r","","" +"VDIVSD xmm1, {k}{z}, xmmV, xmm2/m64","VDIVSD xmm2/m64, xmmV, {k}{z}, xmm1","vdivsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 5E /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VDIVSS xmm1{er}, {k}{z}, xmmV, xmm2","VDIVSS xmm2, xmmV, {k}{z}, xmm1{er}","vdivss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F3.0F.W0 5E /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VDIVSS xmm1, xmmV, xmm2/m32","VDIVSS xmm2/m32, xmmV, xmm1","vdivss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 5E /r","V","V","AVX","","w,r,r","","" +"VDIVSS xmm1, {k}{z}, xmmV, xmm2/m32","VDIVSS xmm2/m32, xmmV, {k}{z}, xmm1","vdivss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 5E /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VDPPD xmm1, xmmV, xmm2/m128, imm8u","VDPPD imm8u, xmm2/m128, xmmV, xmm1","vdppd imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 41 /r ib","V","V","AVX","","w,r,r,r","","" +"VDPPS xmm1, xmmV, xmm2/m128, imm8u","VDPPS imm8u, xmm2/m128, xmmV, xmm1","vdpps imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 40 /r ib","V","V","AVX","","w,r,r,r","","" +"VDPPS ymm1, ymmV, ymm2/m256, imm8u","VDPPS imm8u, ymm2/m256, ymmV, ymm1","vdpps imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.WIG 40 /r ib","V","V","AVX","","w,r,r,r","","" +"VERR r/m16","VERR r/m16","verr r/m16","0F 00 /4","V","V","","","r","","" +"VERW r/m16","VERW r/m16","verw r/m16","0F 00 /5","V","V","","","r","","" +"VEXP2PD zmm1{sae}, {k}{z}, zmm2","VEXP2PD zmm2, {k}{z}, zmm1{sae}","vexp2pd zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W1 C8 /r","V","V","AVX512ER","modrm_regonly","w,r,r","","" +"VEXP2PD zmm1, {k}{z}, zmm2/m512/m64bcst","VEXP2PD zmm2/m512/m64bcst, {k}{z}, zmm1","vexp2pd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 C8 /r","V","V","AVX512ER","bscale8,scale64","w,r,r","","" +"VEXP2PS zmm1{sae}, {k}{z}, zmm2","VEXP2PS zmm2, {k}{z}, zmm1{sae}","vexp2ps zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W0 C8 /r","V","V","AVX512ER","modrm_regonly","w,r,r","","" +"VEXP2PS zmm1, {k}{z}, zmm2/m512/m32bcst","VEXP2PS zmm2/m512/m32bcst, {k}{z}, zmm1","vexp2ps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 C8 /r","V","V","AVX512ER","bscale4,scale64","w,r,r","","" +"VEXPANDPD xmm1, {k}{z}, xmm2/m128","VEXPANDPD xmm2/m128, {k}{z}, xmm1","vexpandpd xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.W1 88 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VEXPANDPD ymm1, {k}{z}, ymm2/m256","VEXPANDPD ymm2/m256, {k}{z}, ymm1","vexpandpd ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.W1 88 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VEXPANDPD zmm1, {k}{z}, zmm2/m512","VEXPANDPD zmm2/m512, {k}{z}, zmm1","vexpandpd zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.W1 88 /r","V","V","AVX512F","scale8","w,r,r","","" +"VEXPANDPS xmm1, {k}{z}, xmm2/m128","VEXPANDPS xmm2/m128, {k}{z}, xmm1","vexpandps xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.W0 88 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VEXPANDPS ymm1, {k}{z}, ymm2/m256","VEXPANDPS ymm2/m256, {k}{z}, ymm1","vexpandps ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.W0 88 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VEXPANDPS zmm1, {k}{z}, zmm2/m512","VEXPANDPS zmm2/m512, {k}{z}, zmm1","vexpandps zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.W0 88 /r","V","V","AVX512F","scale4","w,r,r","","" +"VEXTRACTF128 xmm2/m128, ymm1, imm8u:1","VEXTRACTF128 imm8u:1, ymm1, xmm2/m128","vextractf128 imm8u:1, ymm1, xmm2/m128","VEX.256.66.0F3A.W0 19 /r ib","V","V","AVX","","w,r,r","","" +"VEXTRACTF32X4 xmm2/m128, {k}{z}, ymm1, imm8u:1","VEXTRACTF32X4 imm8u:1, ymm1, {k}{z}, xmm2/m128","vextractf32x4 imm8u:1, ymm1, {k}{z}, xmm2/m128","EVEX.256.66.0F3A.W0 19 /r ib","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VEXTRACTF32X4 xmm2/m128, {k}{z}, zmm1, imm8u:2","VEXTRACTF32X4 imm8u:2, zmm1, {k}{z}, xmm2/m128","vextractf32x4 imm8u:2, zmm1, {k}{z}, xmm2/m128","EVEX.512.66.0F3A.W0 19 /r ib","V","V","AVX512F","scale16","w,r,r,r","","" +"VEXTRACTF32X8 ymm2/m256, {k}{z}, zmm1, imm8u:1","VEXTRACTF32X8 imm8u:1, zmm1, {k}{z}, ymm2/m256","vextractf32x8 imm8u:1, zmm1, {k}{z}, ymm2/m256","EVEX.512.66.0F3A.W0 1B /r ib","V","V","AVX512DQ","scale32","w,r,r,r","","" +"VEXTRACTF64X2 xmm2/m128, {k}{z}, ymm1, imm8u:1","VEXTRACTF64X2 imm8u:1, ymm1, {k}{z}, xmm2/m128","vextractf64x2 imm8u:1, ymm1, {k}{z}, xmm2/m128","EVEX.256.66.0F3A.W1 19 /r ib","V","V","AVX512DQ+AVX512VL","scale16","w,r,r,r","","" +"VEXTRACTF64X2 xmm2/m128, {k}{z}, zmm1, imm8u:2","VEXTRACTF64X2 imm8u:2, zmm1, {k}{z}, xmm2/m128","vextractf64x2 imm8u:2, zmm1, {k}{z}, xmm2/m128","EVEX.512.66.0F3A.W1 19 /r ib","V","V","AVX512DQ","scale16","w,r,r,r","","" +"VEXTRACTF64X4 ymm2/m256, {k}{z}, zmm1, imm8u","VEXTRACTF64X4 imm8u, zmm1, {k}{z}, ymm2/m256","vextractf64x4 imm8u, zmm1, {k}{z}, ymm2/m256","EVEX.512.66.0F3A.W1 1B /r ib","V","V","AVX512F","scale32","w,r,r,r","","" +"VEXTRACTI128 xmm2/m128, ymm1, imm8u:1","VEXTRACTI128 imm8u:1, ymm1, xmm2/m128","vextracti128 imm8u:1, ymm1, xmm2/m128","VEX.256.66.0F3A.W0 39 /r ib","V","V","AVX2","","w,r,r","","" +"VEXTRACTI32X4 xmm2/m128, {k}{z}, ymm1, imm8u:1","VEXTRACTI32X4 imm8u:1, ymm1, {k}{z}, xmm2/m128","vextracti32x4 imm8u:1, ymm1, {k}{z}, xmm2/m128","EVEX.256.66.0F3A.W0 39 /r ib","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VEXTRACTI32X4 xmm2/m128, {k}{z}, zmm1, imm8u:2","VEXTRACTI32X4 imm8u:2, zmm1, {k}{z}, xmm2/m128","vextracti32x4 imm8u:2, zmm1, {k}{z}, xmm2/m128","EVEX.512.66.0F3A.W0 39 /r ib","V","V","AVX512F","scale16","w,r,r,r","","" +"VEXTRACTI32X8 ymm2/m256, {k}{z}, zmm1, imm8u:1","VEXTRACTI32X8 imm8u:1, zmm1, {k}{z}, ymm2/m256","vextracti32x8 imm8u:1, zmm1, {k}{z}, ymm2/m256","EVEX.512.66.0F3A.W0 3B /r ib","V","V","AVX512DQ","scale32","w,r,r,r","","" +"VEXTRACTI64X2 xmm2/m128, {k}{z}, ymm1, imm8u:1","VEXTRACTI64X2 imm8u:1, ymm1, {k}{z}, xmm2/m128","vextracti64x2 imm8u:1, ymm1, {k}{z}, xmm2/m128","EVEX.256.66.0F3A.W1 39 /r ib","V","V","AVX512DQ+AVX512VL","scale16","w,r,r,r","","" +"VEXTRACTI64X2 xmm2/m128, {k}{z}, zmm1, imm8u:2","VEXTRACTI64X2 imm8u:2, zmm1, {k}{z}, xmm2/m128","vextracti64x2 imm8u:2, zmm1, {k}{z}, xmm2/m128","EVEX.512.66.0F3A.W1 39 /r ib","V","V","AVX512DQ","scale16","w,r,r,r","","" +"VEXTRACTI64X4 ymm2/m256, {k}{z}, zmm1, imm8u:1","VEXTRACTI64X4 imm8u:1, zmm1, {k}{z}, ymm2/m256","vextracti64x4 imm8u:1, zmm1, {k}{z}, ymm2/m256","EVEX.512.66.0F3A.W1 3B /r ib","V","V","AVX512F","scale32","w,r,r,r","","" +"VEXTRACTPS r/m32, xmm1, imm8u:2","VEXTRACTPS imm8u:2, xmm1, r/m32","vextractps imm8u:2, xmm1, r/m32","EVEX.128.66.0F3A.WIG 17 /r ib","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VEXTRACTPS r/m32, xmm1, imm8u:2","VEXTRACTPS imm8u:2, xmm1, r/m32","vextractps imm8u:2, xmm1, r/m32","VEX.128.66.0F3A.WIG 17 /r ib","V","V","AVX","","w,r,r","","" +"VFIXUPIMMPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u","VFIXUPIMMPD imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfixupimmpd imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F3A.W1 54 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r,r","","" +"VFIXUPIMMPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VFIXUPIMMPD imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfixupimmpd imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F3A.W1 54 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r,r","","" +"VFIXUPIMMPD zmm1{sae}, {k}{z}, zmmV, zmm2, imm8u","VFIXUPIMMPD imm8u, zmm2, zmmV, {k}{z}, zmm1{sae}","vfixupimmpd imm8u, zmm2, zmmV, {k}{z}, zmm1{sae}","EVEX.DDS.512.66.0F3A.W1 54 /r ib","V","V","AVX512F","modrm_regonly","rw,r,r,r,r","","" +"VFIXUPIMMPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VFIXUPIMMPD imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfixupimmpd imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F3A.W1 54 /r ib","V","V","AVX512F","bscale8,scale64","rw,r,r,r,r","","" +"VFIXUPIMMPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst, imm8u","VFIXUPIMMPS imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfixupimmps imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F3A.W0 54 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r,r","","" +"VFIXUPIMMPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u","VFIXUPIMMPS imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfixupimmps imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F3A.W0 54 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r,r","","" +"VFIXUPIMMPS zmm1{sae}, {k}{z}, zmmV, zmm2, imm8u","VFIXUPIMMPS imm8u, zmm2, zmmV, {k}{z}, zmm1{sae}","vfixupimmps imm8u, zmm2, zmmV, {k}{z}, zmm1{sae}","EVEX.DDS.512.66.0F3A.W0 54 /r ib","V","V","AVX512F","modrm_regonly","rw,r,r,r,r","","" +"VFIXUPIMMPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u","VFIXUPIMMPS imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfixupimmps imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F3A.W0 54 /r ib","V","V","AVX512F","bscale4,scale64","rw,r,r,r,r","","" +"VFIXUPIMMSD xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u","VFIXUPIMMSD imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","vfixupimmsd imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.DDS.128.66.0F3A.W1 55 /r ib","V","V","AVX512F","modrm_regonly","rw,r,r,r,r","","" +"VFIXUPIMMSD xmm1, {k}{z}, xmmV, xmm2/m64, imm8u","VFIXUPIMMSD imm8u, xmm2/m64, xmmV, {k}{z}, xmm1","vfixupimmsd imm8u, xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F3A.W1 55 /r ib","V","V","AVX512F","scale8","rw,r,r,r,r","","" +"VFIXUPIMMSS xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u","VFIXUPIMMSS imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","vfixupimmss imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.DDS.128.66.0F3A.W0 55 /r ib","V","V","AVX512F","modrm_regonly","rw,r,r,r,r","","" +"VFIXUPIMMSS xmm1, {k}{z}, xmmV, xmm2/m32, imm8u","VFIXUPIMMSS imm8u, xmm2/m32, xmmV, {k}{z}, xmm1","vfixupimmss imm8u, xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F3A.W0 55 /r ib","V","V","AVX512F","scale4","rw,r,r,r,r","","" +"VFMADD132PD xmm1, xmmV, xmm2/m128","VFMADD132PD xmm2/m128, xmmV, xmm1","vfmadd132pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 98 /r","V","V","FMA","","rw,r,r","","" +"VFMADD132PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMADD132PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmadd132pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 98 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMADD132PD ymm1, ymmV, ymm2/m256","VFMADD132PD ymm2/m256, ymmV, ymm1","vfmadd132pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 98 /r","V","V","FMA","","rw,r,r","","" +"VFMADD132PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMADD132PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmadd132pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 98 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMADD132PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMADD132PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmadd132pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 98 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD132PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMADD132PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmadd132pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 98 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMADD132PS xmm1, xmmV, xmm2/m128","VFMADD132PS xmm2/m128, xmmV, xmm1","vfmadd132ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 98 /r","V","V","FMA","","rw,r,r","","" +"VFMADD132PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMADD132PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmadd132ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 98 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMADD132PS ymm1, ymmV, ymm2/m256","VFMADD132PS ymm2/m256, ymmV, ymm1","vfmadd132ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 98 /r","V","V","FMA","","rw,r,r","","" +"VFMADD132PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMADD132PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmadd132ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 98 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMADD132PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMADD132PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmadd132ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 98 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD132PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMADD132PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmadd132ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 98 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMADD132SD xmm1{er}, {k}{z}, xmmV, xmm2","VFMADD132SD xmm2, xmmV, {k}{z}, xmm1{er}","vfmadd132sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 99 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD132SD xmm1, xmmV, xmm2/m64","VFMADD132SD xmm2/m64, xmmV, xmm1","vfmadd132sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 99 /r","V","V","FMA","","rw,r,r","","" +"VFMADD132SD xmm1, {k}{z}, xmmV, xmm2/m64","VFMADD132SD xmm2/m64, xmmV, {k}{z}, xmm1","vfmadd132sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 99 /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFMADD132SS xmm1{er}, {k}{z}, xmmV, xmm2","VFMADD132SS xmm2, xmmV, {k}{z}, xmm1{er}","vfmadd132ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 99 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD132SS xmm1, xmmV, xmm2/m32","VFMADD132SS xmm2/m32, xmmV, xmm1","vfmadd132ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 99 /r","V","V","FMA","","rw,r,r","","" +"VFMADD132SS xmm1, {k}{z}, xmmV, xmm2/m32","VFMADD132SS xmm2/m32, xmmV, {k}{z}, xmm1","vfmadd132ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 99 /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFMADD213PD xmm1, xmmV, xmm2/m128","VFMADD213PD xmm2/m128, xmmV, xmm1","vfmadd213pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 A8 /r","V","V","FMA","","rw,r,r","","" +"VFMADD213PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMADD213PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmadd213pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 A8 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMADD213PD ymm1, ymmV, ymm2/m256","VFMADD213PD ymm2/m256, ymmV, ymm1","vfmadd213pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 A8 /r","V","V","FMA","","rw,r,r","","" +"VFMADD213PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMADD213PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmadd213pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 A8 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMADD213PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMADD213PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmadd213pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 A8 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD213PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMADD213PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmadd213pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 A8 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMADD213PS xmm1, xmmV, xmm2/m128","VFMADD213PS xmm2/m128, xmmV, xmm1","vfmadd213ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 A8 /r","V","V","FMA","","rw,r,r","","" +"VFMADD213PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMADD213PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmadd213ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 A8 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMADD213PS ymm1, ymmV, ymm2/m256","VFMADD213PS ymm2/m256, ymmV, ymm1","vfmadd213ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 A8 /r","V","V","FMA","","rw,r,r","","" +"VFMADD213PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMADD213PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmadd213ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 A8 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMADD213PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMADD213PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmadd213ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 A8 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD213PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMADD213PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmadd213ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 A8 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMADD213SD xmm1{er}, {k}{z}, xmmV, xmm2","VFMADD213SD xmm2, xmmV, {k}{z}, xmm1{er}","vfmadd213sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 A9 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD213SD xmm1, xmmV, xmm2/m64","VFMADD213SD xmm2/m64, xmmV, xmm1","vfmadd213sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 A9 /r","V","V","FMA","","rw,r,r","","" +"VFMADD213SD xmm1, {k}{z}, xmmV, xmm2/m64","VFMADD213SD xmm2/m64, xmmV, {k}{z}, xmm1","vfmadd213sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 A9 /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFMADD213SS xmm1{er}, {k}{z}, xmmV, xmm2","VFMADD213SS xmm2, xmmV, {k}{z}, xmm1{er}","vfmadd213ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 A9 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD213SS xmm1, xmmV, xmm2/m32","VFMADD213SS xmm2/m32, xmmV, xmm1","vfmadd213ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 A9 /r","V","V","FMA","","rw,r,r","","" +"VFMADD213SS xmm1, {k}{z}, xmmV, xmm2/m32","VFMADD213SS xmm2/m32, xmmV, {k}{z}, xmm1","vfmadd213ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 A9 /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFMADD231PD xmm1, xmmV, xmm2/m128","VFMADD231PD xmm2/m128, xmmV, xmm1","vfmadd231pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 B8 /r","V","V","FMA","","rw,r,r","","" +"VFMADD231PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMADD231PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmadd231pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 B8 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMADD231PD ymm1, ymmV, ymm2/m256","VFMADD231PD ymm2/m256, ymmV, ymm1","vfmadd231pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 B8 /r","V","V","FMA","","rw,r,r","","" +"VFMADD231PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMADD231PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmadd231pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 B8 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMADD231PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMADD231PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmadd231pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 B8 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD231PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMADD231PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmadd231pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 B8 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMADD231PS xmm1, xmmV, xmm2/m128","VFMADD231PS xmm2/m128, xmmV, xmm1","vfmadd231ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 B8 /r","V","V","FMA","","rw,r,r","","" +"VFMADD231PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMADD231PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmadd231ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 B8 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMADD231PS ymm1, ymmV, ymm2/m256","VFMADD231PS ymm2/m256, ymmV, ymm1","vfmadd231ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 B8 /r","V","V","FMA","","rw,r,r","","" +"VFMADD231PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMADD231PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmadd231ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 B8 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMADD231PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMADD231PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmadd231ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 B8 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD231PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMADD231PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmadd231ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 B8 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMADD231SD xmm1{er}, {k}{z}, xmmV, xmm2","VFMADD231SD xmm2, xmmV, {k}{z}, xmm1{er}","vfmadd231sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 B9 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD231SD xmm1, xmmV, xmm2/m64","VFMADD231SD xmm2/m64, xmmV, xmm1","vfmadd231sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 B9 /r","V","V","FMA","","rw,r,r","","" +"VFMADD231SD xmm1, {k}{z}, xmmV, xmm2/m64","VFMADD231SD xmm2/m64, xmmV, {k}{z}, xmm1","vfmadd231sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 B9 /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFMADD231SS xmm1{er}, {k}{z}, xmmV, xmm2","VFMADD231SS xmm2, xmmV, {k}{z}, xmm1{er}","vfmadd231ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 B9 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADD231SS xmm1, xmmV, xmm2/m32","VFMADD231SS xmm2/m32, xmmV, xmm1","vfmadd231ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 B9 /r","V","V","FMA","","rw,r,r","","" +"VFMADD231SS xmm1, {k}{z}, xmmV, xmm2/m32","VFMADD231SS xmm2/m32, xmmV, {k}{z}, xmm1","vfmadd231ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 B9 /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFMADDPD xmm1, xmmV, xmmIH, xmm2/m128","VFMADDPD xmm2/m128, xmmIH, xmmV, xmm1","vfmaddpd xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 69 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDPD xmm1, xmmV, xmm2/m128, xmmIH","VFMADDPD xmmIH, xmm2/m128, xmmV, xmm1","vfmaddpd xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 69 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDPD ymm1, ymmV, ymmIH, ymm2/m256","VFMADDPD ymm2/m256, ymmIH, ymmV, ymm1","vfmaddpd ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 69 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDPD ymm1, ymmV, ymm2/m256, ymmIH","VFMADDPD ymmIH, ymm2/m256, ymmV, ymm1","vfmaddpd ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 69 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDPS xmm1, xmmV, xmmIH, xmm2/m128","VFMADDPS xmm2/m128, xmmIH, xmmV, xmm1","vfmaddps xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 68 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDPS xmm1, xmmV, xmm2/m128, xmmIH","VFMADDPS xmmIH, xmm2/m128, xmmV, xmm1","vfmaddps xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 68 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDPS ymm1, ymmV, ymmIH, ymm2/m256","VFMADDPS ymm2/m256, ymmIH, ymmV, ymm1","vfmaddps ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 68 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDPS ymm1, ymmV, ymm2/m256, ymmIH","VFMADDPS ymmIH, ymm2/m256, ymmV, ymm1","vfmaddps ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 68 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSD xmm1, xmmV, xmmIH, xmm2/m64","VFMADDSD xmm2/m64, xmmIH, xmmV, xmm1","vfmaddsd xmm2/m64, xmmIH, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W1 6B /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSD xmm1, xmmV, xmm2/m64, xmmIH","VFMADDSD xmmIH, xmm2/m64, xmmV, xmm1","vfmaddsd xmmIH, xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W0 6B /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSS xmm1, xmmV, xmmIH, xmm2/m32","VFMADDSS xmm2/m32, xmmIH, xmmV, xmm1","vfmaddss xmm2/m32, xmmIH, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W1 6A /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSS xmm1, xmmV, xmm2/m32, xmmIH","VFMADDSS xmmIH, xmm2/m32, xmmV, xmm1","vfmaddss xmmIH, xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W0 6A /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSUB132PD xmm1, xmmV, xmm2/m128","VFMADDSUB132PD xmm2/m128, xmmV, xmm1","vfmaddsub132pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 96 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB132PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMADDSUB132PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmaddsub132pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 96 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMADDSUB132PD ymm1, ymmV, ymm2/m256","VFMADDSUB132PD ymm2/m256, ymmV, ymm1","vfmaddsub132pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 96 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB132PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMADDSUB132PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmaddsub132pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 96 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMADDSUB132PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMADDSUB132PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmaddsub132pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 96 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADDSUB132PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMADDSUB132PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmaddsub132pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 96 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMADDSUB132PS xmm1, xmmV, xmm2/m128","VFMADDSUB132PS xmm2/m128, xmmV, xmm1","vfmaddsub132ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 96 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB132PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMADDSUB132PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmaddsub132ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 96 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMADDSUB132PS ymm1, ymmV, ymm2/m256","VFMADDSUB132PS ymm2/m256, ymmV, ymm1","vfmaddsub132ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 96 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB132PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMADDSUB132PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmaddsub132ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 96 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMADDSUB132PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMADDSUB132PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmaddsub132ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 96 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADDSUB132PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMADDSUB132PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmaddsub132ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 96 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMADDSUB213PD xmm1, xmmV, xmm2/m128","VFMADDSUB213PD xmm2/m128, xmmV, xmm1","vfmaddsub213pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 A6 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB213PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMADDSUB213PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmaddsub213pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 A6 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMADDSUB213PD ymm1, ymmV, ymm2/m256","VFMADDSUB213PD ymm2/m256, ymmV, ymm1","vfmaddsub213pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 A6 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB213PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMADDSUB213PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmaddsub213pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 A6 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMADDSUB213PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMADDSUB213PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmaddsub213pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 A6 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADDSUB213PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMADDSUB213PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmaddsub213pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 A6 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMADDSUB213PS xmm1, xmmV, xmm2/m128","VFMADDSUB213PS xmm2/m128, xmmV, xmm1","vfmaddsub213ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 A6 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB213PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMADDSUB213PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmaddsub213ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 A6 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMADDSUB213PS ymm1, ymmV, ymm2/m256","VFMADDSUB213PS ymm2/m256, ymmV, ymm1","vfmaddsub213ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 A6 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB213PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMADDSUB213PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmaddsub213ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 A6 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMADDSUB213PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMADDSUB213PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmaddsub213ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 A6 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADDSUB213PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMADDSUB213PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmaddsub213ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 A6 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMADDSUB231PD xmm1, xmmV, xmm2/m128","VFMADDSUB231PD xmm2/m128, xmmV, xmm1","vfmaddsub231pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 B6 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB231PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMADDSUB231PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmaddsub231pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 B6 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMADDSUB231PD ymm1, ymmV, ymm2/m256","VFMADDSUB231PD ymm2/m256, ymmV, ymm1","vfmaddsub231pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 B6 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB231PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMADDSUB231PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmaddsub231pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 B6 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMADDSUB231PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMADDSUB231PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmaddsub231pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 B6 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADDSUB231PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMADDSUB231PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmaddsub231pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 B6 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMADDSUB231PS xmm1, xmmV, xmm2/m128","VFMADDSUB231PS xmm2/m128, xmmV, xmm1","vfmaddsub231ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 B6 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB231PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMADDSUB231PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmaddsub231ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 B6 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMADDSUB231PS ymm1, ymmV, ymm2/m256","VFMADDSUB231PS ymm2/m256, ymmV, ymm1","vfmaddsub231ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 B6 /r","V","V","FMA","","rw,r,r","","" +"VFMADDSUB231PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMADDSUB231PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmaddsub231ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 B6 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMADDSUB231PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMADDSUB231PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmaddsub231ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 B6 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMADDSUB231PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMADDSUB231PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmaddsub231ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 B6 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMADDSUBPD xmm1, xmmV, xmmIH, xmm2/m128","VFMADDSUBPD xmm2/m128, xmmIH, xmmV, xmm1","vfmaddsubpd xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 5D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSUBPD xmm1, xmmV, xmm2/m128, xmmIH","VFMADDSUBPD xmmIH, xmm2/m128, xmmV, xmm1","vfmaddsubpd xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 5D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSUBPD ymm1, ymmV, ymmIH, ymm2/m256","VFMADDSUBPD ymm2/m256, ymmIH, ymmV, ymm1","vfmaddsubpd ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 5D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSUBPD ymm1, ymmV, ymm2/m256, ymmIH","VFMADDSUBPD ymmIH, ymm2/m256, ymmV, ymm1","vfmaddsubpd ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 5D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSUBPS xmm1, xmmV, xmmIH, xmm2/m128","VFMADDSUBPS xmm2/m128, xmmIH, xmmV, xmm1","vfmaddsubps xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 5C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSUBPS xmm1, xmmV, xmm2/m128, xmmIH","VFMADDSUBPS xmmIH, xmm2/m128, xmmV, xmm1","vfmaddsubps xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 5C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSUBPS ymm1, ymmV, ymmIH, ymm2/m256","VFMADDSUBPS ymm2/m256, ymmIH, ymmV, ymm1","vfmaddsubps ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 5C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMADDSUBPS ymm1, ymmV, ymm2/m256, ymmIH","VFMADDSUBPS ymmIH, ymm2/m256, ymmV, ymm1","vfmaddsubps ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 5C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUB132PD xmm1, xmmV, xmm2/m128","VFMSUB132PD xmm2/m128, xmmV, xmm1","vfmsub132pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 9A /r","V","V","FMA","","rw,r,r","","" +"VFMSUB132PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMSUB132PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmsub132pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 9A /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMSUB132PD ymm1, ymmV, ymm2/m256","VFMSUB132PD ymm2/m256, ymmV, ymm1","vfmsub132pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 9A /r","V","V","FMA","","rw,r,r","","" +"VFMSUB132PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMSUB132PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmsub132pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 9A /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMSUB132PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUB132PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmsub132pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 9A /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB132PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMSUB132PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmsub132pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 9A /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMSUB132PS xmm1, xmmV, xmm2/m128","VFMSUB132PS xmm2/m128, xmmV, xmm1","vfmsub132ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 9A /r","V","V","FMA","","rw,r,r","","" +"VFMSUB132PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMSUB132PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmsub132ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 9A /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMSUB132PS ymm1, ymmV, ymm2/m256","VFMSUB132PS ymm2/m256, ymmV, ymm1","vfmsub132ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 9A /r","V","V","FMA","","rw,r,r","","" +"VFMSUB132PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMSUB132PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmsub132ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 9A /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMSUB132PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUB132PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmsub132ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 9A /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB132PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMSUB132PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmsub132ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 9A /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMSUB132SD xmm1{er}, {k}{z}, xmmV, xmm2","VFMSUB132SD xmm2, xmmV, {k}{z}, xmm1{er}","vfmsub132sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 9B /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB132SD xmm1, xmmV, xmm2/m64","VFMSUB132SD xmm2/m64, xmmV, xmm1","vfmsub132sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 9B /r","V","V","FMA","","rw,r,r","","" +"VFMSUB132SD xmm1, {k}{z}, xmmV, xmm2/m64","VFMSUB132SD xmm2/m64, xmmV, {k}{z}, xmm1","vfmsub132sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 9B /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFMSUB132SS xmm1{er}, {k}{z}, xmmV, xmm2","VFMSUB132SS xmm2, xmmV, {k}{z}, xmm1{er}","vfmsub132ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 9B /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB132SS xmm1, xmmV, xmm2/m32","VFMSUB132SS xmm2/m32, xmmV, xmm1","vfmsub132ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 9B /r","V","V","FMA","","rw,r,r","","" +"VFMSUB132SS xmm1, {k}{z}, xmmV, xmm2/m32","VFMSUB132SS xmm2/m32, xmmV, {k}{z}, xmm1","vfmsub132ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 9B /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFMSUB213PD xmm1, xmmV, xmm2/m128","VFMSUB213PD xmm2/m128, xmmV, xmm1","vfmsub213pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 AA /r","V","V","FMA","","rw,r,r","","" +"VFMSUB213PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMSUB213PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmsub213pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 AA /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMSUB213PD ymm1, ymmV, ymm2/m256","VFMSUB213PD ymm2/m256, ymmV, ymm1","vfmsub213pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 AA /r","V","V","FMA","","rw,r,r","","" +"VFMSUB213PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMSUB213PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmsub213pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 AA /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMSUB213PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUB213PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmsub213pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 AA /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB213PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMSUB213PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmsub213pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 AA /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMSUB213PS xmm1, xmmV, xmm2/m128","VFMSUB213PS xmm2/m128, xmmV, xmm1","vfmsub213ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 AA /r","V","V","FMA","","rw,r,r","","" +"VFMSUB213PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMSUB213PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmsub213ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 AA /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMSUB213PS ymm1, ymmV, ymm2/m256","VFMSUB213PS ymm2/m256, ymmV, ymm1","vfmsub213ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 AA /r","V","V","FMA","","rw,r,r","","" +"VFMSUB213PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMSUB213PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmsub213ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 AA /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMSUB213PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUB213PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmsub213ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 AA /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB213PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMSUB213PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmsub213ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 AA /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMSUB213SD xmm1{er}, {k}{z}, xmmV, xmm2","VFMSUB213SD xmm2, xmmV, {k}{z}, xmm1{er}","vfmsub213sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 AB /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB213SD xmm1, xmmV, xmm2/m64","VFMSUB213SD xmm2/m64, xmmV, xmm1","vfmsub213sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 AB /r","V","V","FMA","","rw,r,r","","" +"VFMSUB213SD xmm1, {k}{z}, xmmV, xmm2/m64","VFMSUB213SD xmm2/m64, xmmV, {k}{z}, xmm1","vfmsub213sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 AB /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFMSUB213SS xmm1{er}, {k}{z}, xmmV, xmm2","VFMSUB213SS xmm2, xmmV, {k}{z}, xmm1{er}","vfmsub213ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 AB /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB213SS xmm1, xmmV, xmm2/m32","VFMSUB213SS xmm2/m32, xmmV, xmm1","vfmsub213ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 AB /r","V","V","FMA","","rw,r,r","","" +"VFMSUB213SS xmm1, {k}{z}, xmmV, xmm2/m32","VFMSUB213SS xmm2/m32, xmmV, {k}{z}, xmm1","vfmsub213ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 AB /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFMSUB231PD xmm1, xmmV, xmm2/m128","VFMSUB231PD xmm2/m128, xmmV, xmm1","vfmsub231pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 BA /r","V","V","FMA","","rw,r,r","","" +"VFMSUB231PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMSUB231PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmsub231pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 BA /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMSUB231PD ymm1, ymmV, ymm2/m256","VFMSUB231PD ymm2/m256, ymmV, ymm1","vfmsub231pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 BA /r","V","V","FMA","","rw,r,r","","" +"VFMSUB231PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMSUB231PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmsub231pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 BA /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMSUB231PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUB231PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmsub231pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 BA /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB231PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMSUB231PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmsub231pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 BA /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMSUB231PS xmm1, xmmV, xmm2/m128","VFMSUB231PS xmm2/m128, xmmV, xmm1","vfmsub231ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 BA /r","V","V","FMA","","rw,r,r","","" +"VFMSUB231PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMSUB231PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmsub231ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 BA /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMSUB231PS ymm1, ymmV, ymm2/m256","VFMSUB231PS ymm2/m256, ymmV, ymm1","vfmsub231ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 BA /r","V","V","FMA","","rw,r,r","","" +"VFMSUB231PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMSUB231PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmsub231ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 BA /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMSUB231PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUB231PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmsub231ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 BA /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB231PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMSUB231PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmsub231ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 BA /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMSUB231SD xmm1{er}, {k}{z}, xmmV, xmm2","VFMSUB231SD xmm2, xmmV, {k}{z}, xmm1{er}","vfmsub231sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 BB /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB231SD xmm1, xmmV, xmm2/m64","VFMSUB231SD xmm2/m64, xmmV, xmm1","vfmsub231sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 BB /r","V","V","FMA","","rw,r,r","","" +"VFMSUB231SD xmm1, {k}{z}, xmmV, xmm2/m64","VFMSUB231SD xmm2/m64, xmmV, {k}{z}, xmm1","vfmsub231sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 BB /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFMSUB231SS xmm1{er}, {k}{z}, xmmV, xmm2","VFMSUB231SS xmm2, xmmV, {k}{z}, xmm1{er}","vfmsub231ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 BB /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUB231SS xmm1, xmmV, xmm2/m32","VFMSUB231SS xmm2/m32, xmmV, xmm1","vfmsub231ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 BB /r","V","V","FMA","","rw,r,r","","" +"VFMSUB231SS xmm1, {k}{z}, xmmV, xmm2/m32","VFMSUB231SS xmm2/m32, xmmV, {k}{z}, xmm1","vfmsub231ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 BB /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFMSUBADD132PD xmm1, xmmV, xmm2/m128","VFMSUBADD132PD xmm2/m128, xmmV, xmm1","vfmsubadd132pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 97 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD132PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMSUBADD132PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmsubadd132pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 97 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMSUBADD132PD ymm1, ymmV, ymm2/m256","VFMSUBADD132PD ymm2/m256, ymmV, ymm1","vfmsubadd132pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 97 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD132PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMSUBADD132PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmsubadd132pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 97 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMSUBADD132PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUBADD132PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmsubadd132pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 97 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUBADD132PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMSUBADD132PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmsubadd132pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 97 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMSUBADD132PS xmm1, xmmV, xmm2/m128","VFMSUBADD132PS xmm2/m128, xmmV, xmm1","vfmsubadd132ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 97 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD132PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMSUBADD132PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmsubadd132ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 97 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMSUBADD132PS ymm1, ymmV, ymm2/m256","VFMSUBADD132PS ymm2/m256, ymmV, ymm1","vfmsubadd132ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 97 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD132PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMSUBADD132PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmsubadd132ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 97 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMSUBADD132PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUBADD132PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmsubadd132ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 97 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUBADD132PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMSUBADD132PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmsubadd132ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 97 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMSUBADD213PD xmm1, xmmV, xmm2/m128","VFMSUBADD213PD xmm2/m128, xmmV, xmm1","vfmsubadd213pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 A7 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD213PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMSUBADD213PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmsubadd213pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 A7 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMSUBADD213PD ymm1, ymmV, ymm2/m256","VFMSUBADD213PD ymm2/m256, ymmV, ymm1","vfmsubadd213pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 A7 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD213PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMSUBADD213PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmsubadd213pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 A7 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMSUBADD213PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUBADD213PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmsubadd213pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 A7 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUBADD213PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMSUBADD213PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmsubadd213pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 A7 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMSUBADD213PS xmm1, xmmV, xmm2/m128","VFMSUBADD213PS xmm2/m128, xmmV, xmm1","vfmsubadd213ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 A7 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD213PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMSUBADD213PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmsubadd213ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 A7 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMSUBADD213PS ymm1, ymmV, ymm2/m256","VFMSUBADD213PS ymm2/m256, ymmV, ymm1","vfmsubadd213ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 A7 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD213PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMSUBADD213PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmsubadd213ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 A7 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMSUBADD213PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUBADD213PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmsubadd213ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 A7 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUBADD213PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMSUBADD213PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmsubadd213ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 A7 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMSUBADD231PD xmm1, xmmV, xmm2/m128","VFMSUBADD231PD xmm2/m128, xmmV, xmm1","vfmsubadd231pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 B7 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD231PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFMSUBADD231PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfmsubadd231pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 B7 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFMSUBADD231PD ymm1, ymmV, ymm2/m256","VFMSUBADD231PD ymm2/m256, ymmV, ymm1","vfmsubadd231pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 B7 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD231PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFMSUBADD231PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfmsubadd231pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 B7 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFMSUBADD231PD zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUBADD231PD zmm2, zmmV, {k}{z}, zmm1{er}","vfmsubadd231pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 B7 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUBADD231PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFMSUBADD231PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfmsubadd231pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 B7 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFMSUBADD231PS xmm1, xmmV, xmm2/m128","VFMSUBADD231PS xmm2/m128, xmmV, xmm1","vfmsubadd231ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 B7 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD231PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFMSUBADD231PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfmsubadd231ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 B7 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFMSUBADD231PS ymm1, ymmV, ymm2/m256","VFMSUBADD231PS ymm2/m256, ymmV, ymm1","vfmsubadd231ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 B7 /r","V","V","FMA","","rw,r,r","","" +"VFMSUBADD231PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFMSUBADD231PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfmsubadd231ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 B7 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFMSUBADD231PS zmm1{er}, {k}{z}, zmmV, zmm2","VFMSUBADD231PS zmm2, zmmV, {k}{z}, zmm1{er}","vfmsubadd231ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 B7 /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFMSUBADD231PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFMSUBADD231PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfmsubadd231ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 B7 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFMSUBADDPD xmm1, xmmV, xmmIH, xmm2/m128","VFMSUBADDPD xmm2/m128, xmmIH, xmmV, xmm1","vfmsubaddpd xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 5F /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBADDPD xmm1, xmmV, xmm2/m128, xmmIH","VFMSUBADDPD xmmIH, xmm2/m128, xmmV, xmm1","vfmsubaddpd xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 5F /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBADDPD ymm1, ymmV, ymmIH, ymm2/m256","VFMSUBADDPD ymm2/m256, ymmIH, ymmV, ymm1","vfmsubaddpd ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 5F /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBADDPD ymm1, ymmV, ymm2/m256, ymmIH","VFMSUBADDPD ymmIH, ymm2/m256, ymmV, ymm1","vfmsubaddpd ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 5F /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBADDPS xmm1, xmmV, xmmIH, xmm2/m128","VFMSUBADDPS xmm2/m128, xmmIH, xmmV, xmm1","vfmsubaddps xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 5E /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBADDPS xmm1, xmmV, xmm2/m128, xmmIH","VFMSUBADDPS xmmIH, xmm2/m128, xmmV, xmm1","vfmsubaddps xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 5E /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBADDPS ymm1, ymmV, ymmIH, ymm2/m256","VFMSUBADDPS ymm2/m256, ymmIH, ymmV, ymm1","vfmsubaddps ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 5E /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBADDPS ymm1, ymmV, ymm2/m256, ymmIH","VFMSUBADDPS ymmIH, ymm2/m256, ymmV, ymm1","vfmsubaddps ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 5E /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBPD xmm1, xmmV, xmmIH, xmm2/m128","VFMSUBPD xmm2/m128, xmmIH, xmmV, xmm1","vfmsubpd xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 6D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBPD xmm1, xmmV, xmm2/m128, xmmIH","VFMSUBPD xmmIH, xmm2/m128, xmmV, xmm1","vfmsubpd xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 6D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBPD ymm1, ymmV, ymmIH, ymm2/m256","VFMSUBPD ymm2/m256, ymmIH, ymmV, ymm1","vfmsubpd ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 6D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBPD ymm1, ymmV, ymm2/m256, ymmIH","VFMSUBPD ymmIH, ymm2/m256, ymmV, ymm1","vfmsubpd ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 6D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBPS xmm1, xmmV, xmmIH, xmm2/m128","VFMSUBPS xmm2/m128, xmmIH, xmmV, xmm1","vfmsubps xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 6C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBPS xmm1, xmmV, xmm2/m128, xmmIH","VFMSUBPS xmmIH, xmm2/m128, xmmV, xmm1","vfmsubps xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 6C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBPS ymm1, ymmV, ymmIH, ymm2/m256","VFMSUBPS ymm2/m256, ymmIH, ymmV, ymm1","vfmsubps ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 6C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBPS ymm1, ymmV, ymm2/m256, ymmIH","VFMSUBPS ymmIH, ymm2/m256, ymmV, ymm1","vfmsubps ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 6C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBSD xmm1, xmmV, xmmIH, xmm2/m64","VFMSUBSD xmm2/m64, xmmIH, xmmV, xmm1","vfmsubsd xmm2/m64, xmmIH, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W1 6F /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBSD xmm1, xmmV, xmm2/m64, xmmIH","VFMSUBSD xmmIH, xmm2/m64, xmmV, xmm1","vfmsubsd xmmIH, xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W0 6F /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBSS xmm1, xmmV, xmmIH, xmm2/m32","VFMSUBSS xmm2/m32, xmmIH, xmmV, xmm1","vfmsubss xmm2/m32, xmmIH, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W1 6E /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFMSUBSS xmm1, xmmV, xmm2/m32, xmmIH","VFMSUBSS xmmIH, xmm2/m32, xmmV, xmm1","vfmsubss xmmIH, xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W0 6E /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADD132PD xmm1, xmmV, xmm2/m128","VFNMADD132PD xmm2/m128, xmmV, xmm1","vfnmadd132pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 9C /r","V","V","FMA","","rw,r,r","","" +"VFNMADD132PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFNMADD132PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfnmadd132pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 9C /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFNMADD132PD ymm1, ymmV, ymm2/m256","VFNMADD132PD ymm2/m256, ymmV, ymm1","vfnmadd132pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 9C /r","V","V","FMA","","rw,r,r","","" +"VFNMADD132PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFNMADD132PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfnmadd132pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 9C /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFNMADD132PD zmm1{er}, {k}{z}, zmmV, zmm2","VFNMADD132PD zmm2, zmmV, {k}{z}, zmm1{er}","vfnmadd132pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 9C /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD132PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFNMADD132PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfnmadd132pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 9C /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFNMADD132PS xmm1, xmmV, xmm2/m128","VFNMADD132PS xmm2/m128, xmmV, xmm1","vfnmadd132ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 9C /r","V","V","FMA","","rw,r,r","","" +"VFNMADD132PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFNMADD132PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfnmadd132ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 9C /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFNMADD132PS ymm1, ymmV, ymm2/m256","VFNMADD132PS ymm2/m256, ymmV, ymm1","vfnmadd132ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 9C /r","V","V","FMA","","rw,r,r","","" +"VFNMADD132PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFNMADD132PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfnmadd132ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 9C /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFNMADD132PS zmm1{er}, {k}{z}, zmmV, zmm2","VFNMADD132PS zmm2, zmmV, {k}{z}, zmm1{er}","vfnmadd132ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 9C /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD132PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFNMADD132PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfnmadd132ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 9C /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFNMADD132SD xmm1{er}, {k}{z}, xmmV, xmm2","VFNMADD132SD xmm2, xmmV, {k}{z}, xmm1{er}","vfnmadd132sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 9D /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD132SD xmm1, xmmV, xmm2/m64","VFNMADD132SD xmm2/m64, xmmV, xmm1","vfnmadd132sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 9D /r","V","V","FMA","","rw,r,r","","" +"VFNMADD132SD xmm1, {k}{z}, xmmV, xmm2/m64","VFNMADD132SD xmm2/m64, xmmV, {k}{z}, xmm1","vfnmadd132sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 9D /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFNMADD132SS xmm1{er}, {k}{z}, xmmV, xmm2","VFNMADD132SS xmm2, xmmV, {k}{z}, xmm1{er}","vfnmadd132ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 9D /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD132SS xmm1, xmmV, xmm2/m32","VFNMADD132SS xmm2/m32, xmmV, xmm1","vfnmadd132ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 9D /r","V","V","FMA","","rw,r,r","","" +"VFNMADD132SS xmm1, {k}{z}, xmmV, xmm2/m32","VFNMADD132SS xmm2/m32, xmmV, {k}{z}, xmm1","vfnmadd132ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 9D /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFNMADD213PD xmm1, xmmV, xmm2/m128","VFNMADD213PD xmm2/m128, xmmV, xmm1","vfnmadd213pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 AC /r","V","V","FMA","","rw,r,r","","" +"VFNMADD213PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFNMADD213PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfnmadd213pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 AC /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFNMADD213PD ymm1, ymmV, ymm2/m256","VFNMADD213PD ymm2/m256, ymmV, ymm1","vfnmadd213pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 AC /r","V","V","FMA","","rw,r,r","","" +"VFNMADD213PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFNMADD213PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfnmadd213pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 AC /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFNMADD213PD zmm1{er}, {k}{z}, zmmV, zmm2","VFNMADD213PD zmm2, zmmV, {k}{z}, zmm1{er}","vfnmadd213pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 AC /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD213PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFNMADD213PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfnmadd213pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 AC /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFNMADD213PS xmm1, xmmV, xmm2/m128","VFNMADD213PS xmm2/m128, xmmV, xmm1","vfnmadd213ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 AC /r","V","V","FMA","","rw,r,r","","" +"VFNMADD213PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFNMADD213PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfnmadd213ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 AC /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFNMADD213PS ymm1, ymmV, ymm2/m256","VFNMADD213PS ymm2/m256, ymmV, ymm1","vfnmadd213ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 AC /r","V","V","FMA","","rw,r,r","","" +"VFNMADD213PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFNMADD213PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfnmadd213ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 AC /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFNMADD213PS zmm1{er}, {k}{z}, zmmV, zmm2","VFNMADD213PS zmm2, zmmV, {k}{z}, zmm1{er}","vfnmadd213ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 AC /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD213PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFNMADD213PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfnmadd213ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 AC /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFNMADD213SD xmm1{er}, {k}{z}, xmmV, xmm2","VFNMADD213SD xmm2, xmmV, {k}{z}, xmm1{er}","vfnmadd213sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 AD /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD213SD xmm1, xmmV, xmm2/m64","VFNMADD213SD xmm2/m64, xmmV, xmm1","vfnmadd213sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 AD /r","V","V","FMA","","rw,r,r","","" +"VFNMADD213SD xmm1, {k}{z}, xmmV, xmm2/m64","VFNMADD213SD xmm2/m64, xmmV, {k}{z}, xmm1","vfnmadd213sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 AD /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFNMADD213SS xmm1{er}, {k}{z}, xmmV, xmm2","VFNMADD213SS xmm2, xmmV, {k}{z}, xmm1{er}","vfnmadd213ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 AD /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD213SS xmm1, xmmV, xmm2/m32","VFNMADD213SS xmm2/m32, xmmV, xmm1","vfnmadd213ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 AD /r","V","V","FMA","","rw,r,r","","" +"VFNMADD213SS xmm1, {k}{z}, xmmV, xmm2/m32","VFNMADD213SS xmm2/m32, xmmV, {k}{z}, xmm1","vfnmadd213ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 AD /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFNMADD231PD xmm1, xmmV, xmm2/m128","VFNMADD231PD xmm2/m128, xmmV, xmm1","vfnmadd231pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 BC /r","V","V","FMA","","rw,r,r","","" +"VFNMADD231PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFNMADD231PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfnmadd231pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 BC /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFNMADD231PD ymm1, ymmV, ymm2/m256","VFNMADD231PD ymm2/m256, ymmV, ymm1","vfnmadd231pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 BC /r","V","V","FMA","","rw,r,r","","" +"VFNMADD231PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFNMADD231PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfnmadd231pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 BC /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFNMADD231PD zmm1{er}, {k}{z}, zmmV, zmm2","VFNMADD231PD zmm2, zmmV, {k}{z}, zmm1{er}","vfnmadd231pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 BC /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD231PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFNMADD231PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfnmadd231pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 BC /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFNMADD231PS xmm1, xmmV, xmm2/m128","VFNMADD231PS xmm2/m128, xmmV, xmm1","vfnmadd231ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 BC /r","V","V","FMA","","rw,r,r","","" +"VFNMADD231PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFNMADD231PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfnmadd231ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 BC /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFNMADD231PS ymm1, ymmV, ymm2/m256","VFNMADD231PS ymm2/m256, ymmV, ymm1","vfnmadd231ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 BC /r","V","V","FMA","","rw,r,r","","" +"VFNMADD231PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFNMADD231PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfnmadd231ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 BC /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFNMADD231PS zmm1{er}, {k}{z}, zmmV, zmm2","VFNMADD231PS zmm2, zmmV, {k}{z}, zmm1{er}","vfnmadd231ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 BC /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD231PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFNMADD231PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfnmadd231ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 BC /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFNMADD231SD xmm1{er}, {k}{z}, xmmV, xmm2","VFNMADD231SD xmm2, xmmV, {k}{z}, xmm1{er}","vfnmadd231sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 BD /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD231SD xmm1, xmmV, xmm2/m64","VFNMADD231SD xmm2/m64, xmmV, xmm1","vfnmadd231sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 BD /r","V","V","FMA","","rw,r,r","","" +"VFNMADD231SD xmm1, {k}{z}, xmmV, xmm2/m64","VFNMADD231SD xmm2/m64, xmmV, {k}{z}, xmm1","vfnmadd231sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 BD /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFNMADD231SS xmm1{er}, {k}{z}, xmmV, xmm2","VFNMADD231SS xmm2, xmmV, {k}{z}, xmm1{er}","vfnmadd231ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 BD /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMADD231SS xmm1, xmmV, xmm2/m32","VFNMADD231SS xmm2/m32, xmmV, xmm1","vfnmadd231ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 BD /r","V","V","FMA","","rw,r,r","","" +"VFNMADD231SS xmm1, {k}{z}, xmmV, xmm2/m32","VFNMADD231SS xmm2/m32, xmmV, {k}{z}, xmm1","vfnmadd231ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 BD /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFNMADDPD xmm1, xmmV, xmmIH, xmm2/m128","VFNMADDPD xmm2/m128, xmmIH, xmmV, xmm1","vfnmaddpd xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 79 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDPD xmm1, xmmV, xmm2/m128, xmmIH","VFNMADDPD xmmIH, xmm2/m128, xmmV, xmm1","vfnmaddpd xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 79 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDPD ymm1, ymmV, ymmIH, ymm2/m256","VFNMADDPD ymm2/m256, ymmIH, ymmV, ymm1","vfnmaddpd ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 79 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDPD ymm1, ymmV, ymm2/m256, ymmIH","VFNMADDPD ymmIH, ymm2/m256, ymmV, ymm1","vfnmaddpd ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 79 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDPS xmm1, xmmV, xmmIH, xmm2/m128","VFNMADDPS xmm2/m128, xmmIH, xmmV, xmm1","vfnmaddps xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 78 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDPS xmm1, xmmV, xmm2/m128, xmmIH","VFNMADDPS xmmIH, xmm2/m128, xmmV, xmm1","vfnmaddps xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 78 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDPS ymm1, ymmV, ymmIH, ymm2/m256","VFNMADDPS ymm2/m256, ymmIH, ymmV, ymm1","vfnmaddps ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 78 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDPS ymm1, ymmV, ymm2/m256, ymmIH","VFNMADDPS ymmIH, ymm2/m256, ymmV, ymm1","vfnmaddps ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 78 /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDSD xmm1, xmmV, xmmIH, xmm2/m64","VFNMADDSD xmm2/m64, xmmIH, xmmV, xmm1","vfnmaddsd xmm2/m64, xmmIH, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W1 7B /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDSD xmm1, xmmV, xmm2/m64, xmmIH","VFNMADDSD xmmIH, xmm2/m64, xmmV, xmm1","vfnmaddsd xmmIH, xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W0 7B /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDSS xmm1, xmmV, xmmIH, xmm2/m32","VFNMADDSS xmm2/m32, xmmIH, xmmV, xmm1","vfnmaddss xmm2/m32, xmmIH, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W1 7A /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMADDSS xmm1, xmmV, xmm2/m32, xmmIH","VFNMADDSS xmmIH, xmm2/m32, xmmV, xmm1","vfnmaddss xmmIH, xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W0 7A /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUB132PD xmm1, xmmV, xmm2/m128","VFNMSUB132PD xmm2/m128, xmmV, xmm1","vfnmsub132pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 9E /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB132PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFNMSUB132PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfnmsub132pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 9E /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFNMSUB132PD ymm1, ymmV, ymm2/m256","VFNMSUB132PD ymm2/m256, ymmV, ymm1","vfnmsub132pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 9E /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB132PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFNMSUB132PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfnmsub132pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 9E /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFNMSUB132PD zmm1{er}, {k}{z}, zmmV, zmm2","VFNMSUB132PD zmm2, zmmV, {k}{z}, zmm1{er}","vfnmsub132pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 9E /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB132PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFNMSUB132PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfnmsub132pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 9E /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFNMSUB132PS xmm1, xmmV, xmm2/m128","VFNMSUB132PS xmm2/m128, xmmV, xmm1","vfnmsub132ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 9E /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB132PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFNMSUB132PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfnmsub132ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 9E /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFNMSUB132PS ymm1, ymmV, ymm2/m256","VFNMSUB132PS ymm2/m256, ymmV, ymm1","vfnmsub132ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 9E /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB132PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFNMSUB132PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfnmsub132ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 9E /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFNMSUB132PS zmm1{er}, {k}{z}, zmmV, zmm2","VFNMSUB132PS zmm2, zmmV, {k}{z}, zmm1{er}","vfnmsub132ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 9E /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB132PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFNMSUB132PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfnmsub132ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 9E /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFNMSUB132SD xmm1{er}, {k}{z}, xmmV, xmm2","VFNMSUB132SD xmm2, xmmV, {k}{z}, xmm1{er}","vfnmsub132sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 9F /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB132SD xmm1, xmmV, xmm2/m64","VFNMSUB132SD xmm2/m64, xmmV, xmm1","vfnmsub132sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 9F /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB132SD xmm1, {k}{z}, xmmV, xmm2/m64","VFNMSUB132SD xmm2/m64, xmmV, {k}{z}, xmm1","vfnmsub132sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 9F /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFNMSUB132SS xmm1{er}, {k}{z}, xmmV, xmm2","VFNMSUB132SS xmm2, xmmV, {k}{z}, xmm1{er}","vfnmsub132ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 9F /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB132SS xmm1, xmmV, xmm2/m32","VFNMSUB132SS xmm2/m32, xmmV, xmm1","vfnmsub132ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 9F /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB132SS xmm1, {k}{z}, xmmV, xmm2/m32","VFNMSUB132SS xmm2/m32, xmmV, {k}{z}, xmm1","vfnmsub132ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 9F /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFNMSUB213PD xmm1, xmmV, xmm2/m128","VFNMSUB213PD xmm2/m128, xmmV, xmm1","vfnmsub213pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 AE /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB213PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFNMSUB213PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfnmsub213pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 AE /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFNMSUB213PD ymm1, ymmV, ymm2/m256","VFNMSUB213PD ymm2/m256, ymmV, ymm1","vfnmsub213pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 AE /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB213PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFNMSUB213PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfnmsub213pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 AE /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFNMSUB213PD zmm1{er}, {k}{z}, zmmV, zmm2","VFNMSUB213PD zmm2, zmmV, {k}{z}, zmm1{er}","vfnmsub213pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 AE /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB213PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFNMSUB213PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfnmsub213pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 AE /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFNMSUB213PS xmm1, xmmV, xmm2/m128","VFNMSUB213PS xmm2/m128, xmmV, xmm1","vfnmsub213ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 AE /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB213PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFNMSUB213PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfnmsub213ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 AE /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFNMSUB213PS ymm1, ymmV, ymm2/m256","VFNMSUB213PS ymm2/m256, ymmV, ymm1","vfnmsub213ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 AE /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB213PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFNMSUB213PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfnmsub213ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 AE /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFNMSUB213PS zmm1{er}, {k}{z}, zmmV, zmm2","VFNMSUB213PS zmm2, zmmV, {k}{z}, zmm1{er}","vfnmsub213ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 AE /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB213PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFNMSUB213PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfnmsub213ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 AE /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFNMSUB213SD xmm1{er}, {k}{z}, xmmV, xmm2","VFNMSUB213SD xmm2, xmmV, {k}{z}, xmm1{er}","vfnmsub213sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 AF /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB213SD xmm1, xmmV, xmm2/m64","VFNMSUB213SD xmm2/m64, xmmV, xmm1","vfnmsub213sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 AF /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB213SD xmm1, {k}{z}, xmmV, xmm2/m64","VFNMSUB213SD xmm2/m64, xmmV, {k}{z}, xmm1","vfnmsub213sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 AF /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFNMSUB213SS xmm1{er}, {k}{z}, xmmV, xmm2","VFNMSUB213SS xmm2, xmmV, {k}{z}, xmm1{er}","vfnmsub213ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 AF /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB213SS xmm1, xmmV, xmm2/m32","VFNMSUB213SS xmm2/m32, xmmV, xmm1","vfnmsub213ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 AF /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB213SS xmm1, {k}{z}, xmmV, xmm2/m32","VFNMSUB213SS xmm2/m32, xmmV, {k}{z}, xmm1","vfnmsub213ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 AF /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFNMSUB231PD xmm1, xmmV, xmm2/m128","VFNMSUB231PD xmm2/m128, xmmV, xmm1","vfnmsub231pd xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W1 BE /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB231PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VFNMSUB231PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vfnmsub231pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 BE /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VFNMSUB231PD ymm1, ymmV, ymm2/m256","VFNMSUB231PD ymm2/m256, ymmV, ymm1","vfnmsub231pd ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W1 BE /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB231PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VFNMSUB231PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vfnmsub231pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 BE /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VFNMSUB231PD zmm1{er}, {k}{z}, zmmV, zmm2","VFNMSUB231PD zmm2, zmmV, {k}{z}, zmm1{er}","vfnmsub231pd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W1 BE /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB231PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VFNMSUB231PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vfnmsub231pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 BE /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VFNMSUB231PS xmm1, xmmV, xmm2/m128","VFNMSUB231PS xmm2/m128, xmmV, xmm1","vfnmsub231ps xmm2/m128, xmmV, xmm1","VEX.DDS.128.66.0F38.W0 BE /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB231PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VFNMSUB231PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vfnmsub231ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 BE /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VFNMSUB231PS ymm1, ymmV, ymm2/m256","VFNMSUB231PS ymm2/m256, ymmV, ymm1","vfnmsub231ps ymm2/m256, ymmV, ymm1","VEX.DDS.256.66.0F38.W0 BE /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB231PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VFNMSUB231PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vfnmsub231ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 BE /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VFNMSUB231PS zmm1{er}, {k}{z}, zmmV, zmm2","VFNMSUB231PS zmm2, zmmV, {k}{z}, zmm1{er}","vfnmsub231ps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.DDS.512.66.0F38.W0 BE /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB231PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VFNMSUB231PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vfnmsub231ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 BE /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VFNMSUB231SD xmm1{er}, {k}{z}, xmmV, xmm2","VFNMSUB231SD xmm2, xmmV, {k}{z}, xmm1{er}","vfnmsub231sd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W1 BF /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB231SD xmm1, xmmV, xmm2/m64","VFNMSUB231SD xmm2/m64, xmmV, xmm1","vfnmsub231sd xmm2/m64, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W1 BF /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB231SD xmm1, {k}{z}, xmmV, xmm2/m64","VFNMSUB231SD xmm2/m64, xmmV, {k}{z}, xmm1","vfnmsub231sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W1 BF /r","V","V","AVX512F","scale8","rw,r,r,r","","" +"VFNMSUB231SS xmm1{er}, {k}{z}, xmmV, xmm2","VFNMSUB231SS xmm2, xmmV, {k}{z}, xmm1{er}","vfnmsub231ss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.DDS.128.66.0F38.W0 BF /r","V","V","AVX512F","modrm_regonly","rw,r,r,r","","" +"VFNMSUB231SS xmm1, xmmV, xmm2/m32","VFNMSUB231SS xmm2/m32, xmmV, xmm1","vfnmsub231ss xmm2/m32, xmmV, xmm1","VEX.DDS.LIG.66.0F38.W0 BF /r","V","V","FMA","","rw,r,r","","" +"VFNMSUB231SS xmm1, {k}{z}, xmmV, xmm2/m32","VFNMSUB231SS xmm2/m32, xmmV, {k}{z}, xmm1","vfnmsub231ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.DDS.LIG.66.0F38.W0 BF /r","V","V","AVX512F","scale4","rw,r,r,r","","" +"VFNMSUBPD xmm1, xmmV, xmmIH, xmm2/m128","VFNMSUBPD xmm2/m128, xmmIH, xmmV, xmm1","vfnmsubpd xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 7D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBPD xmm1, xmmV, xmm2/m128, xmmIH","VFNMSUBPD xmmIH, xmm2/m128, xmmV, xmm1","vfnmsubpd xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 7D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBPD ymm1, ymmV, ymmIH, ymm2/m256","VFNMSUBPD ymm2/m256, ymmIH, ymmV, ymm1","vfnmsubpd ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 7D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBPD ymm1, ymmV, ymm2/m256, ymmIH","VFNMSUBPD ymmIH, ymm2/m256, ymmV, ymm1","vfnmsubpd ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 7D /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBPS xmm1, xmmV, xmmIH, xmm2/m128","VFNMSUBPS xmm2/m128, xmmIH, xmmV, xmm1","vfnmsubps xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 7C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBPS xmm1, xmmV, xmm2/m128, xmmIH","VFNMSUBPS xmmIH, xmm2/m128, xmmV, xmm1","vfnmsubps xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 7C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBPS ymm1, ymmV, ymmIH, ymm2/m256","VFNMSUBPS ymm2/m256, ymmIH, ymmV, ymm1","vfnmsubps ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 7C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBPS ymm1, ymmV, ymm2/m256, ymmIH","VFNMSUBPS ymmIH, ymm2/m256, ymmV, ymm1","vfnmsubps ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 7C /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBSD xmm1, xmmV, xmmIH, xmm2/m64","VFNMSUBSD xmm2/m64, xmmIH, xmmV, xmm1","vfnmsubsd xmm2/m64, xmmIH, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W1 7F /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBSD xmm1, xmmV, xmm2/m64, xmmIH","VFNMSUBSD xmmIH, xmm2/m64, xmmV, xmm1","vfnmsubsd xmmIH, xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W0 7F /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBSS xmm1, xmmV, xmmIH, xmm2/m32","VFNMSUBSS xmm2/m32, xmmIH, xmmV, xmm1","vfnmsubss xmm2/m32, xmmIH, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W1 7E /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFNMSUBSS xmm1, xmmV, xmm2/m32, xmmIH","VFNMSUBSS xmmIH, xmm2/m32, xmmV, xmm1","vfnmsubss xmmIH, xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.W0 7E /r /is4","V","V","FMA4","amd","w,r,r,r","","" +"VFPCLASSPD k1, {k}, xmm2/m128/m64bcst, imm8u","VFPCLASSPDX imm8u, xmm2/m128/m64bcst, {k}, k1","vfpclasspdx imm8u, xmm2/m128/m64bcst, {k}, k1","EVEX.128.66.0F3A.W1 66 /r ib","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r,r","Y","128" +"VFPCLASSPD k1, {k}, ymm2/m256/m64bcst, imm8u","VFPCLASSPDY imm8u, ymm2/m256/m64bcst, {k}, k1","vfpclasspdy imm8u, ymm2/m256/m64bcst, {k}, k1","EVEX.256.66.0F3A.W1 66 /r ib","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r,r","Y","256" +"VFPCLASSPD k1, {k}, zmm2/m512/m64bcst, imm8u","VFPCLASSPDZ imm8u, zmm2/m512/m64bcst, {k}, k1","vfpclasspdz imm8u, zmm2/m512/m64bcst, {k}, k1","EVEX.512.66.0F3A.W1 66 /r ib","V","V","AVX512DQ","bscale8,scale64","w,r,r,r","Y","512" +"VFPCLASSPS k1, {k}, xmm2/m128/m32bcst, imm8u","VFPCLASSPSX imm8u, xmm2/m128/m32bcst, {k}, k1","vfpclasspsx imm8u, xmm2/m128/m32bcst, {k}, k1","EVEX.128.66.0F3A.W0 66 /r ib","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r,r","Y","128" +"VFPCLASSPS k1, {k}, ymm2/m256/m32bcst, imm8u","VFPCLASSPSY imm8u, ymm2/m256/m32bcst, {k}, k1","vfpclasspsy imm8u, ymm2/m256/m32bcst, {k}, k1","EVEX.256.66.0F3A.W0 66 /r ib","V","V","AVX512DQ+AVX512VL","bscale4,scale32","w,r,r,r","Y","256" +"VFPCLASSPS k1, {k}, zmm2/m512/m32bcst, imm8u","VFPCLASSPSZ imm8u, zmm2/m512/m32bcst, {k}, k1","vfpclasspsz imm8u, zmm2/m512/m32bcst, {k}, k1","EVEX.512.66.0F3A.W0 66 /r ib","V","V","AVX512DQ","bscale4,scale64","w,r,r,r","Y","512" +"VFPCLASSSD k1, {k}, xmm2/m64, imm8u","VFPCLASSSD imm8u, xmm2/m64, {k}, k1","vfpclasssd imm8u, xmm2/m64, {k}, k1","EVEX.LIG.66.0F3A.W1 67 /r ib","V","V","AVX512DQ","scale8","w,r,r,r","","" +"VFPCLASSSS k1, {k}, xmm2/m32, imm8u","VFPCLASSSS imm8u, xmm2/m32, {k}, k1","vfpclassss imm8u, xmm2/m32, {k}, k1","EVEX.LIG.66.0F3A.W0 67 /r ib","V","V","AVX512DQ","scale4","w,r,r,r","","" +"VFRCZPD xmm1, xmm2/m128","VFRCZPD xmm2/m128, xmm1","vfrczpd xmm2/m128, xmm1","XOP.128.09.W0 81 /r","V","V","XOP","amd","w,r","","" +"VFRCZPD ymm1, ymm2/m256","VFRCZPD ymm2/m256, ymm1","vfrczpd ymm2/m256, ymm1","XOP.256.09.W0 81 /r","V","V","XOP","amd","w,r","","" +"VFRCZPS xmm1, xmm2/m128","VFRCZPS xmm2/m128, xmm1","vfrczps xmm2/m128, xmm1","XOP.128.09.W0 80 /r","V","V","XOP","amd","w,r","","" +"VFRCZPS ymm1, ymm2/m256","VFRCZPS ymm2/m256, ymm1","vfrczps ymm2/m256, ymm1","XOP.256.09.W0 80 /r","V","V","XOP","amd","w,r","","" +"VFRCZSD xmm1, xmm2/m64","VFRCZSD xmm2/m64, xmm1","vfrczsd xmm2/m64, xmm1","XOP.128.09.W0 83 /r","V","V","XOP","amd","w,r","","" +"VFRCZSS xmm1, xmm2/m32","VFRCZSS xmm2/m32, xmm1","vfrczss xmm2/m32, xmm1","XOP.128.09.W0 82 /r","V","V","XOP","amd","w,r","","" +"VGATHERDPD xmm1, {k1-k7}, vm32x","VGATHERDPD vm32x, {k1-k7}, xmm1","vgatherdpd vm32x, {k1-k7}, xmm1","EVEX.128.66.0F38.W1 92 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VGATHERDPD ymm1, {k1-k7}, vm32x","VGATHERDPD vm32x, {k1-k7}, ymm1","vgatherdpd vm32x, {k1-k7}, ymm1","EVEX.256.66.0F38.W1 92 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VGATHERDPD zmm1, {k1-k7}, vm32y","VGATHERDPD vm32y, {k1-k7}, zmm1","vgatherdpd vm32y, {k1-k7}, zmm1","EVEX.512.66.0F38.W1 92 /vsib","V","V","AVX512F","modrm_memonly,scale8","w,rw,r","","" +"VGATHERDPD xmm1, vm32x, xmmV","VGATHERDPD xmmV, vm32x, xmm1","vgatherdpd xmmV, vm32x, xmm1","VEX.DDS.128.66.0F38.W1 92 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VGATHERDPD ymm1, vm32x, ymmV","VGATHERDPD ymmV, vm32x, ymm1","vgatherdpd ymmV, vm32x, ymm1","VEX.DDS.256.66.0F38.W1 92 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VGATHERDPS xmm1, {k1-k7}, vm32x","VGATHERDPS vm32x, {k1-k7}, xmm1","vgatherdps vm32x, {k1-k7}, xmm1","EVEX.128.66.0F38.W0 92 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VGATHERDPS ymm1, {k1-k7}, vm32y","VGATHERDPS vm32y, {k1-k7}, ymm1","vgatherdps vm32y, {k1-k7}, ymm1","EVEX.256.66.0F38.W0 92 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VGATHERDPS zmm1, {k1-k7}, vm32z","VGATHERDPS vm32z, {k1-k7}, zmm1","vgatherdps vm32z, {k1-k7}, zmm1","EVEX.512.66.0F38.W0 92 /vsib","V","V","AVX512F","modrm_memonly,scale4","w,rw,r","","" +"VGATHERDPS xmm1, vm32x, xmmV","VGATHERDPS xmmV, vm32x, xmm1","vgatherdps xmmV, vm32x, xmm1","VEX.DDS.128.66.0F38.W0 92 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VGATHERDPS ymm1, vm32y, ymmV","VGATHERDPS ymmV, vm32y, ymm1","vgatherdps ymmV, vm32y, ymm1","VEX.DDS.256.66.0F38.W0 92 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VGATHERPF0DPD vm32y, {k1-k7}","VGATHERPF0DPD {k1-k7}, vm32y","vgatherpf0dpd {k1-k7}, vm32y","EVEX.512.66.0F38.W1 C6 /1","V","V","AVX512PF","modrm_memonly,scale8","r,rw","","" +"VGATHERPF0DPS vm32z, {k1-k7}","VGATHERPF0DPS {k1-k7}, vm32z","vgatherpf0dps {k1-k7}, vm32z","EVEX.512.66.0F38.W0 C6 /1","V","V","AVX512PF","modrm_memonly,scale4","r,rw","","" +"VGATHERPF0QPD vm64z, {k1-k7}","VGATHERPF0QPD {k1-k7}, vm64z","vgatherpf0qpd {k1-k7}, vm64z","EVEX.512.66.0F38.W1 C7 /1","V","V","AVX512PF","modrm_memonly,scale8","r,rw","","" +"VGATHERPF0QPS vm64z, {k1-k7}","VGATHERPF0QPS {k1-k7}, vm64z","vgatherpf0qps {k1-k7}, vm64z","EVEX.512.66.0F38.W0 C7 /1","V","V","AVX512PF","modrm_memonly,scale4","r,rw","","" +"VGATHERPF1DPD vm32y, {k1-k7}","VGATHERPF1DPD {k1-k7}, vm32y","vgatherpf1dpd {k1-k7}, vm32y","EVEX.512.66.0F38.W1 C6 /2","V","V","AVX512PF","modrm_memonly,scale8","r,rw","","" +"VGATHERPF1DPS vm32z, {k1-k7}","VGATHERPF1DPS {k1-k7}, vm32z","vgatherpf1dps {k1-k7}, vm32z","EVEX.512.66.0F38.W0 C6 /2","V","V","AVX512PF","modrm_memonly,scale4","r,rw","","" +"VGATHERPF1QPD vm64z, {k1-k7}","VGATHERPF1QPD {k1-k7}, vm64z","vgatherpf1qpd {k1-k7}, vm64z","EVEX.512.66.0F38.W1 C7 /2","V","V","AVX512PF","modrm_memonly,scale8","r,rw","","" +"VGATHERPF1QPS vm64z, {k1-k7}","VGATHERPF1QPS {k1-k7}, vm64z","vgatherpf1qps {k1-k7}, vm64z","EVEX.512.66.0F38.W0 C7 /2","V","V","AVX512PF","modrm_memonly,scale4","r,rw","","" +"VGATHERQPD xmm1, {k1-k7}, vm64x","VGATHERQPD vm64x, {k1-k7}, xmm1","vgatherqpd vm64x, {k1-k7}, xmm1","EVEX.128.66.0F38.W1 93 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VGATHERQPD ymm1, {k1-k7}, vm64y","VGATHERQPD vm64y, {k1-k7}, ymm1","vgatherqpd vm64y, {k1-k7}, ymm1","EVEX.256.66.0F38.W1 93 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VGATHERQPD zmm1, {k1-k7}, vm64z","VGATHERQPD vm64z, {k1-k7}, zmm1","vgatherqpd vm64z, {k1-k7}, zmm1","EVEX.512.66.0F38.W1 93 /vsib","V","V","AVX512F","modrm_memonly,scale8","w,rw,r","","" +"VGATHERQPD xmm1, vm64x, xmmV","VGATHERQPD xmmV, vm64x, xmm1","vgatherqpd xmmV, vm64x, xmm1","VEX.DDS.128.66.0F38.W1 93 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VGATHERQPD ymm1, vm64y, ymmV","VGATHERQPD ymmV, vm64y, ymm1","vgatherqpd ymmV, vm64y, ymm1","VEX.DDS.256.66.0F38.W1 93 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VGATHERQPS xmm1, {k1-k7}, vm64x","VGATHERQPS vm64x, {k1-k7}, xmm1","vgatherqps vm64x, {k1-k7}, xmm1","EVEX.128.66.0F38.W0 93 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VGATHERQPS xmm1, {k1-k7}, vm64y","VGATHERQPS vm64y, {k1-k7}, xmm1","vgatherqps vm64y, {k1-k7}, xmm1","EVEX.256.66.0F38.W0 93 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VGATHERQPS ymm1, {k1-k7}, vm64z","VGATHERQPS vm64z, {k1-k7}, ymm1","vgatherqps vm64z, {k1-k7}, ymm1","EVEX.512.66.0F38.W0 93 /vsib","V","V","AVX512F","modrm_memonly,scale4","w,rw,r","","" +"VGATHERQPS xmm1, vm64x, xmmV","VGATHERQPS xmmV, vm64x, xmm1","vgatherqps xmmV, vm64x, xmm1","VEX.DDS.128.66.0F38.W0 93 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VGATHERQPS xmm1, vm64y, xmmV","VGATHERQPS xmmV, vm64y, xmm1","vgatherqps xmmV, vm64y, xmm1","VEX.DDS.256.66.0F38.W0 93 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VGETEXPPD xmm1, {k}{z}, xmm2/m128/m64bcst","VGETEXPPD xmm2/m128/m64bcst, {k}{z}, xmm1","vgetexppd xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W1 42 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","","" +"VGETEXPPD ymm1, {k}{z}, ymm2/m256/m64bcst","VGETEXPPD ymm2/m256/m64bcst, {k}{z}, ymm1","vgetexppd ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W1 42 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","","" +"VGETEXPPD zmm1{sae}, {k}{z}, zmm2","VGETEXPPD zmm2, {k}{z}, zmm1{sae}","vgetexppd zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W1 42 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VGETEXPPD zmm1, {k}{z}, zmm2/m512/m64bcst","VGETEXPPD zmm2/m512/m64bcst, {k}{z}, zmm1","vgetexppd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 42 /r","V","V","AVX512F","bscale8,scale64","w,r,r","","" +"VGETEXPPS xmm1, {k}{z}, xmm2/m128/m32bcst","VGETEXPPS xmm2/m128/m32bcst, {k}{z}, xmm1","vgetexpps xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W0 42 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VGETEXPPS ymm1, {k}{z}, ymm2/m256/m32bcst","VGETEXPPS ymm2/m256/m32bcst, {k}{z}, ymm1","vgetexpps ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W0 42 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VGETEXPPS zmm1{sae}, {k}{z}, zmm2","VGETEXPPS zmm2, {k}{z}, zmm1{sae}","vgetexpps zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W0 42 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VGETEXPPS zmm1, {k}{z}, zmm2/m512/m32bcst","VGETEXPPS zmm2/m512/m32bcst, {k}{z}, zmm1","vgetexpps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 42 /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VGETEXPSD xmm1{sae}, {k}{z}, xmmV, xmm2","VGETEXPSD xmm2, xmmV, {k}{z}, xmm1{sae}","vgetexpsd xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F38.W1 43 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VGETEXPSD xmm1, {k}{z}, xmmV, xmm2/m64","VGETEXPSD xmm2/m64, xmmV, {k}{z}, xmm1","vgetexpsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W1 43 /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VGETEXPSS xmm1{sae}, {k}{z}, xmmV, xmm2","VGETEXPSS xmm2, xmmV, {k}{z}, xmm1{sae}","vgetexpss xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F38.W0 43 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VGETEXPSS xmm1, {k}{z}, xmmV, xmm2/m32","VGETEXPSS xmm2/m32, xmmV, {k}{z}, xmm1","vgetexpss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W0 43 /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VGETMANTPD xmm1, {k}{z}, xmm2/m128/m64bcst, imm8u:4","VGETMANTPD imm8u:4, xmm2/m128/m64bcst, {k}{z}, xmm1","vgetmantpd imm8u:4, xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F3A.W1 26 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VGETMANTPD ymm1, {k}{z}, ymm2/m256/m64bcst, imm8u:4","VGETMANTPD imm8u:4, ymm2/m256/m64bcst, {k}{z}, ymm1","vgetmantpd imm8u:4, ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W1 26 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VGETMANTPD zmm1{sae}, {k}{z}, zmm2, imm8u:4","VGETMANTPD imm8u:4, zmm2, {k}{z}, zmm1{sae}","vgetmantpd imm8u:4, zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F3A.W1 26 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VGETMANTPD zmm1, {k}{z}, zmm2/m512/m64bcst, imm8u:4","VGETMANTPD imm8u:4, zmm2/m512/m64bcst, {k}{z}, zmm1","vgetmantpd imm8u:4, zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W1 26 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VGETMANTPS xmm1, {k}{z}, xmm2/m128/m32bcst, imm8u:4","VGETMANTPS imm8u:4, xmm2/m128/m32bcst, {k}{z}, xmm1","vgetmantps imm8u:4, xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F3A.W0 26 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VGETMANTPS ymm1, {k}{z}, ymm2/m256/m32bcst, imm8u:4","VGETMANTPS imm8u:4, ymm2/m256/m32bcst, {k}{z}, ymm1","vgetmantps imm8u:4, ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W0 26 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VGETMANTPS zmm1{sae}, {k}{z}, zmm2, imm8u:4","VGETMANTPS imm8u:4, zmm2, {k}{z}, zmm1{sae}","vgetmantps imm8u:4, zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F3A.W0 26 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VGETMANTPS zmm1, {k}{z}, zmm2/m512/m32bcst, imm8u:4","VGETMANTPS imm8u:4, zmm2/m512/m32bcst, {k}{z}, zmm1","vgetmantps imm8u:4, zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W0 26 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VGETMANTSD xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u:4","VGETMANTSD imm8u:4, xmm2, xmmV, {k}{z}, xmm1{sae}","vgetmantsd imm8u:4, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F3A.W1 27 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r,r","","" +"VGETMANTSD xmm1, {k}{z}, xmmV, xmm2/m64, imm8u:4","VGETMANTSD imm8u:4, xmm2/m64, xmmV, {k}{z}, xmm1","vgetmantsd imm8u:4, xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F3A.W1 27 /r ib","V","V","AVX512F","scale8","w,r,r,r,r","","" +"VGETMANTSS xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u:4","VGETMANTSS imm8u:4, xmm2, xmmV, {k}{z}, xmm1{sae}","vgetmantss imm8u:4, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F3A.W0 27 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r,r","","" +"VGETMANTSS xmm1, {k}{z}, xmmV, xmm2/m32, imm8u:4","VGETMANTSS imm8u:4, xmm2/m32, xmmV, {k}{z}, xmm1","vgetmantss imm8u:4, xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F3A.W0 27 /r ib","V","V","AVX512F","scale4","w,r,r,r,r","","" +"VGF2P8AFFINEINVQB xmm1, xmmV, xmm2/m128, imm8u","VGF2P8AFFINEINVQB imm8u, xmm2/m128, xmmV, xmm1","vgf2p8affineinvqb imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 CF /r ib","V","V","GFNI+AVX","","w,r,r,r","","" +"VGF2P8AFFINEINVQB xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u","VGF2P8AFFINEINVQB imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vgf2p8affineinvqb imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W1 CF /r ib","V","V","GFNI+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VGF2P8AFFINEINVQB ymm1, ymmV, ymm2/m256, imm8u","VGF2P8AFFINEINVQB imm8u, ymm2/m256, ymmV, ymm1","vgf2p8affineinvqb imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 CF /r ib","V","V","GFNI+AVX","","w,r,r,r","","" +"VGF2P8AFFINEINVQB ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VGF2P8AFFINEINVQB imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vgf2p8affineinvqb imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 CF /r ib","V","V","GFNI+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VGF2P8AFFINEINVQB zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VGF2P8AFFINEINVQB imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vgf2p8affineinvqb imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 CF /r ib","V","V","GFNI+AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VGF2P8AFFINEQB xmm1, xmmV, xmm2/m128, imm8u","VGF2P8AFFINEQB imm8u, xmm2/m128, xmmV, xmm1","vgf2p8affineqb imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 CE /r ib","V","V","GFNI+AVX","","w,r,r,r","","" +"VGF2P8AFFINEQB xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u","VGF2P8AFFINEQB imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vgf2p8affineqb imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W1 CE /r ib","V","V","GFNI+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VGF2P8AFFINEQB ymm1, ymmV, ymm2/m256, imm8u","VGF2P8AFFINEQB imm8u, ymm2/m256, ymmV, ymm1","vgf2p8affineqb imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 CE /r ib","V","V","GFNI+AVX","","w,r,r,r","","" +"VGF2P8AFFINEQB ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VGF2P8AFFINEQB imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vgf2p8affineqb imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 CE /r ib","V","V","GFNI+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VGF2P8AFFINEQB zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VGF2P8AFFINEQB imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vgf2p8affineqb imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 CE /r ib","V","V","GFNI+AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VGF2P8MULB xmm1, xmmV, xmm2/m128","VGF2P8MULB xmm2/m128, xmmV, xmm1","vgf2p8mulb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 CF /r","V","V","GFNI+AVX","","w,r,r","","" +"VGF2P8MULB xmm1, {k}{z}, xmmV, xmm2/m128","VGF2P8MULB xmm2/m128, xmmV, {k}{z}, xmm1","vgf2p8mulb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 CF /r","V","V","GFNI+AVX512VL","scale16","w,r,r,r","","" +"VGF2P8MULB ymm1, ymmV, ymm2/m256","VGF2P8MULB ymm2/m256, ymmV, ymm1","vgf2p8mulb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 CF /r","V","V","GFNI+AVX","","w,r,r","","" +"VGF2P8MULB ymm1, {k}{z}, ymmV, ymm2/m256","VGF2P8MULB ymm2/m256, ymmV, {k}{z}, ymm1","vgf2p8mulb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 CF /r","V","V","GFNI+AVX512VL","scale32","w,r,r,r","","" +"VGF2P8MULB zmm1, {k}{z}, zmmV, zmm2/m512","VGF2P8MULB zmm2/m512, zmmV, {k}{z}, zmm1","vgf2p8mulb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 CF /r","V","V","GFNI+AVX512F","scale64","w,r,r,r","","" +"VHADDPD xmm1, xmmV, xmm2/m128","VHADDPD xmm2/m128, xmmV, xmm1","vhaddpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 7C /r","V","V","AVX","","w,r,r","","" +"VHADDPD ymm1, ymmV, ymm2/m256","VHADDPD ymm2/m256, ymmV, ymm1","vhaddpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 7C /r","V","V","AVX","","w,r,r","","" +"VHADDPS xmm1, xmmV, xmm2/m128","VHADDPS xmm2/m128, xmmV, xmm1","vhaddps xmm2/m128, xmmV, xmm1","VEX.NDS.128.F2.0F.WIG 7C /r","V","V","AVX","","w,r,r","","" +"VHADDPS ymm1, ymmV, ymm2/m256","VHADDPS ymm2/m256, ymmV, ymm1","vhaddps ymm2/m256, ymmV, ymm1","VEX.NDS.256.F2.0F.WIG 7C /r","V","V","AVX","","w,r,r","","" +"VHSUBPD xmm1, xmmV, xmm2/m128","VHSUBPD xmm2/m128, xmmV, xmm1","vhsubpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 7D /r","V","V","AVX","","w,r,r","","" +"VHSUBPD ymm1, ymmV, ymm2/m256","VHSUBPD ymm2/m256, ymmV, ymm1","vhsubpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 7D /r","V","V","AVX","","w,r,r","","" +"VHSUBPS xmm1, xmmV, xmm2/m128","VHSUBPS xmm2/m128, xmmV, xmm1","vhsubps xmm2/m128, xmmV, xmm1","VEX.NDS.128.F2.0F.WIG 7D /r","V","V","AVX","","w,r,r","","" +"VHSUBPS ymm1, ymmV, ymm2/m256","VHSUBPS ymm2/m256, ymmV, ymm1","vhsubps ymm2/m256, ymmV, ymm1","VEX.NDS.256.F2.0F.WIG 7D /r","V","V","AVX","","w,r,r","","" +"VINSERTF128 ymm1, ymmV, xmm2/m128, imm8u:1","VINSERTF128 imm8u:1, xmm2/m128, ymmV, ymm1","vinsertf128 imm8u:1, xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 18 /r ib","V","V","AVX","","w,r,r,r","","" +"VINSERTF32X4 ymm1, {k}{z}, ymmV, xmm2/m128, imm8u:1","VINSERTF32X4 imm8u:1, xmm2/m128, ymmV, {k}{z}, ymm1","vinsertf32x4 imm8u:1, xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 18 /r ib","V","V","AVX512F+AVX512VL","scale16","w,r,r,r,r","","" +"VINSERTF32X4 zmm1, {k}{z}, zmmV, xmm2/m128, imm8u:2","VINSERTF32X4 imm8u:2, xmm2/m128, zmmV, {k}{z}, zmm1","vinsertf32x4 imm8u:2, xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 18 /r ib","V","V","AVX512F","scale16","w,r,r,r,r","","" +"VINSERTF32X8 zmm1, {k}{z}, zmmV, ymm2/m256, imm8u:1","VINSERTF32X8 imm8u:1, ymm2/m256, zmmV, {k}{z}, zmm1","vinsertf32x8 imm8u:1, ymm2/m256, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 1A /r ib","V","V","AVX512DQ","scale32","w,r,r,r,r","","" +"VINSERTF64X2 ymm1, {k}{z}, ymmV, xmm2/m128, imm8u:1","VINSERTF64X2 imm8u:1, xmm2/m128, ymmV, {k}{z}, ymm1","vinsertf64x2 imm8u:1, xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 18 /r ib","V","V","AVX512DQ+AVX512VL","scale16","w,r,r,r,r","","" +"VINSERTF64X2 zmm1, {k}{z}, zmmV, xmm2/m128, imm8u:2","VINSERTF64X2 imm8u:2, xmm2/m128, zmmV, {k}{z}, zmm1","vinsertf64x2 imm8u:2, xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 18 /r ib","V","V","AVX512DQ","scale16","w,r,r,r,r","","" +"VINSERTF64X4 zmm1, {k}{z}, zmmV, ymm2/m256, imm8u:1","VINSERTF64X4 imm8u:1, ymm2/m256, zmmV, {k}{z}, zmm1","vinsertf64x4 imm8u:1, ymm2/m256, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 1A /r ib","V","V","AVX512F","scale32","w,r,r,r,r","","" +"VINSERTI128 ymm1, ymmV, xmm2/m128, imm8u:1","VINSERTI128 imm8u:1, xmm2/m128, ymmV, ymm1","vinserti128 imm8u:1, xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 38 /r ib","V","V","AVX2","","w,r,r,r","","" +"VINSERTI32X4 ymm1, {k}{z}, ymmV, xmm2/m128, imm8u:1","VINSERTI32X4 imm8u:1, xmm2/m128, ymmV, {k}{z}, ymm1","vinserti32x4 imm8u:1, xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 38 /r ib","V","V","AVX512F+AVX512VL","scale16","w,r,r,r,r","","" +"VINSERTI32X4 zmm1, {k}{z}, zmmV, xmm2/m128, imm8u:2","VINSERTI32X4 imm8u:2, xmm2/m128, zmmV, {k}{z}, zmm1","vinserti32x4 imm8u:2, xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 38 /r ib","V","V","AVX512F","scale16","w,r,r,r,r","","" +"VINSERTI32X8 zmm1, {k}{z}, zmmV, ymm2/m256, imm8u:1","VINSERTI32X8 imm8u:1, ymm2/m256, zmmV, {k}{z}, zmm1","vinserti32x8 imm8u:1, ymm2/m256, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 3A /r ib","V","V","AVX512DQ","scale32","w,r,r,r,r","","" +"VINSERTI64X2 ymm1, {k}{z}, ymmV, xmm2/m128, imm8u:1","VINSERTI64X2 imm8u:1, xmm2/m128, ymmV, {k}{z}, ymm1","vinserti64x2 imm8u:1, xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 38 /r ib","V","V","AVX512DQ+AVX512VL","scale16","w,r,r,r,r","","" +"VINSERTI64X2 zmm1, {k}{z}, zmmV, xmm2/m128, imm8u:2","VINSERTI64X2 imm8u:2, xmm2/m128, zmmV, {k}{z}, zmm1","vinserti64x2 imm8u:2, xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 38 /r ib","V","V","AVX512DQ","scale16","w,r,r,r,r","","" +"VINSERTI64X4 zmm1, {k}{z}, zmmV, ymm2/m256, imm8u:1","VINSERTI64X4 imm8u:1, ymm2/m256, zmmV, {k}{z}, zmm1","vinserti64x4 imm8u:1, ymm2/m256, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 3A /r ib","V","V","AVX512F","scale32","w,r,r,r,r","","" +"VINSERTPS xmm1, xmmV, xmm2/m32, imm8u","VINSERTPS imm8u, xmm2/m32, xmmV, xmm1","vinsertps imm8u, xmm2/m32, xmmV, xmm1","EVEX.NDS.128.66.0F3A.W0 21 /r ib","V","V","AVX512F+AVX512VL","scale4","w,r,r,r","","" +"VINSERTPS xmm1, xmmV, xmm2/m32, imm8u","VINSERTPS imm8u, xmm2/m32, xmmV, xmm1","vinsertps imm8u, xmm2/m32, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 21 /r ib","V","V","AVX","","w,r,r,r","","" +"VLDDQU xmm1, m128","VLDDQU m128, xmm1","vlddqu m128, xmm1","VEX.128.F2.0F.WIG F0 /r","V","V","AVX","modrm_memonly","w,r","","" +"VLDDQU ymm1, m256","VLDDQU m256, ymm1","vlddqu m256, ymm1","VEX.256.F2.0F.WIG F0 /r","V","V","AVX","modrm_memonly","w,r","","" +"VLDMXCSR m32","VLDMXCSR m32","vldmxcsr m32","VEX.128.0F.WIG AE /2","V","V","AVX","modrm_memonly","r","","" +"VMASKMOVDQU xmm1, xmm2","VMASKMOVDQU xmm2, xmm1","vmaskmovdqu xmm2, xmm1","VEX.128.66.0F.WIG F7 /r","V","V","AVX","modrm_regonly","r,r","","" +"VMASKMOVPD xmm1, xmmV, m128","VMASKMOVPD m128, xmmV, xmm1","vmaskmovpd m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 2D /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMASKMOVPD ymm1, ymmV, m256","VMASKMOVPD m256, ymmV, ymm1","vmaskmovpd m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 2D /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMASKMOVPD m128, xmmV, xmm1","VMASKMOVPD xmm1, xmmV, m128","vmaskmovpd xmm1, xmmV, m128","VEX.NDS.128.66.0F38.W0 2F /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMASKMOVPD m256, ymmV, ymm1","VMASKMOVPD ymm1, ymmV, m256","vmaskmovpd ymm1, ymmV, m256","VEX.NDS.256.66.0F38.W0 2F /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMASKMOVPS xmm1, xmmV, m128","VMASKMOVPS m128, xmmV, xmm1","vmaskmovps m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 2C /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMASKMOVPS ymm1, ymmV, m256","VMASKMOVPS m256, ymmV, ymm1","vmaskmovps m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 2C /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMASKMOVPS m128, xmmV, xmm1","VMASKMOVPS xmm1, xmmV, m128","vmaskmovps xmm1, xmmV, m128","VEX.NDS.128.66.0F38.W0 2E /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMASKMOVPS m256, ymmV, ymm1","VMASKMOVPS ymm1, ymmV, m256","vmaskmovps ymm1, ymmV, m256","VEX.NDS.256.66.0F38.W0 2E /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMAXPD xmm1, xmmV, xmm2/m128","VMAXPD xmm2/m128, xmmV, xmm1","vmaxpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 5F /r","V","V","AVX","","w,r,r","","" +"VMAXPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VMAXPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vmaxpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 5F /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VMAXPD ymm1, ymmV, ymm2/m256","VMAXPD ymm2/m256, ymmV, ymm1","vmaxpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 5F /r","V","V","AVX","","w,r,r","","" +"VMAXPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VMAXPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vmaxpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 5F /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VMAXPD zmm1{sae}, {k}{z}, zmmV, zmm2","VMAXPD zmm2, zmmV, {k}{z}, zmm1{sae}","vmaxpd zmm2, zmmV, {k}{z}, zmm1{sae}","EVEX.NDS.512.66.0F.W1 5F /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMAXPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VMAXPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vmaxpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 5F /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VMAXPS xmm1, xmmV, xmm2/m128","VMAXPS xmm2/m128, xmmV, xmm1","vmaxps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 5F /r","V","V","AVX","","w,r,r","","" +"VMAXPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VMAXPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vmaxps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 5F /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VMAXPS ymm1, ymmV, ymm2/m256","VMAXPS ymm2/m256, ymmV, ymm1","vmaxps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 5F /r","V","V","AVX","","w,r,r","","" +"VMAXPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VMAXPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vmaxps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 5F /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VMAXPS zmm1{sae}, {k}{z}, zmmV, zmm2","VMAXPS zmm2, zmmV, {k}{z}, zmm1{sae}","vmaxps zmm2, zmmV, {k}{z}, zmm1{sae}","EVEX.NDS.512.0F.W0 5F /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMAXPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VMAXPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vmaxps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 5F /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VMAXSD xmm1{sae}, {k}{z}, xmmV, xmm2","VMAXSD xmm2, xmmV, {k}{z}, xmm1{sae}","vmaxsd xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.F2.0F.W1 5F /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMAXSD xmm1, xmmV, xmm2/m64","VMAXSD xmm2/m64, xmmV, xmm1","vmaxsd xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 5F /r","V","V","AVX","","w,r,r","","" +"VMAXSD xmm1, {k}{z}, xmmV, xmm2/m64","VMAXSD xmm2/m64, xmmV, {k}{z}, xmm1","vmaxsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 5F /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VMAXSS xmm1{sae}, {k}{z}, xmmV, xmm2","VMAXSS xmm2, xmmV, {k}{z}, xmm1{sae}","vmaxss xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.F3.0F.W0 5F /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMAXSS xmm1, xmmV, xmm2/m32","VMAXSS xmm2/m32, xmmV, xmm1","vmaxss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 5F /r","V","V","AVX","","w,r,r","","" +"VMAXSS xmm1, {k}{z}, xmmV, xmm2/m32","VMAXSS xmm2/m32, xmmV, {k}{z}, xmm1","vmaxss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 5F /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VMCALL","VMCALL","vmcall","0F 01 C1","V","V","VTX","","","","" +"VMCLEAR m64","VMCLEAR m64","vmclear m64","66 0F C7 /6","V","V","VTX","modrm_memonly","r","","" +"VMFUNC","VMFUNC","vmfunc","0F 01 D4","V","V","","","","","" +"VMINPD xmm1, xmmV, xmm2/m128","VMINPD xmm2/m128, xmmV, xmm1","vminpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 5D /r","V","V","AVX","","w,r,r","","" +"VMINPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VMINPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vminpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 5D /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VMINPD ymm1, ymmV, ymm2/m256","VMINPD ymm2/m256, ymmV, ymm1","vminpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 5D /r","V","V","AVX","","w,r,r","","" +"VMINPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VMINPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vminpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 5D /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VMINPD zmm1{sae}, {k}{z}, zmmV, zmm2","VMINPD zmm2, zmmV, {k}{z}, zmm1{sae}","vminpd zmm2, zmmV, {k}{z}, zmm1{sae}","EVEX.NDS.512.66.0F.W1 5D /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMINPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VMINPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vminpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 5D /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VMINPS xmm1, xmmV, xmm2/m128","VMINPS xmm2/m128, xmmV, xmm1","vminps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 5D /r","V","V","AVX","","w,r,r","","" +"VMINPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VMINPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vminps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 5D /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VMINPS ymm1, ymmV, ymm2/m256","VMINPS ymm2/m256, ymmV, ymm1","vminps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 5D /r","V","V","AVX","","w,r,r","","" +"VMINPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VMINPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vminps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 5D /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VMINPS zmm1{sae}, {k}{z}, zmmV, zmm2","VMINPS zmm2, zmmV, {k}{z}, zmm1{sae}","vminps zmm2, zmmV, {k}{z}, zmm1{sae}","EVEX.NDS.512.0F.W0 5D /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMINPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VMINPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vminps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 5D /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VMINSD xmm1{sae}, {k}{z}, xmmV, xmm2","VMINSD xmm2, xmmV, {k}{z}, xmm1{sae}","vminsd xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.F2.0F.W1 5D /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMINSD xmm1, xmmV, xmm2/m64","VMINSD xmm2/m64, xmmV, xmm1","vminsd xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 5D /r","V","V","AVX","","w,r,r","","" +"VMINSD xmm1, {k}{z}, xmmV, xmm2/m64","VMINSD xmm2/m64, xmmV, {k}{z}, xmm1","vminsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 5D /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VMINSS xmm1{sae}, {k}{z}, xmmV, xmm2","VMINSS xmm2, xmmV, {k}{z}, xmm1{sae}","vminss xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.F3.0F.W0 5D /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMINSS xmm1, xmmV, xmm2/m32","VMINSS xmm2/m32, xmmV, xmm1","vminss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 5D /r","V","V","AVX","","w,r,r","","" +"VMINSS xmm1, {k}{z}, xmmV, xmm2/m32","VMINSS xmm2/m32, xmmV, {k}{z}, xmm1","vminss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 5D /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VMLAUNCH","VMLAUNCH","vmlaunch","0F 01 C2","V","V","VTX","","","","" +"VMLOAD EAX","VMLOADL EAX","vmloadl EAX","0F 01 DA","V","V","SVM","amd,modrm_regonly,operand32","r","Y","32" +"VMLOAD RAX","VMLOADQ RAX","vmloadq RAX","REX.W 0F 01 DA","N.S.","V","SVM","amd,modrm_regonly","r","Y","64" +"VMLOAD AX","VMLOADW AX","vmloadw AX","0F 01 DA","V","V","SVM","amd,modrm_regonly,operand16","r","Y","16" +"VMMCALL","VMMCALL","vmmcall","0F 01 D9","V","V","SVM","amd","","","" +"VMOVAPD xmm2/m128, xmm1","VMOVAPD xmm1, xmm2/m128","vmovapd xmm1, xmm2/m128","VEX.128.66.0F.WIG 29 /r","V","V","AVX","","w,r","","" +"VMOVAPD xmm2/m128, {k}{z}, xmm1","VMOVAPD xmm1, {k}{z}, xmm2/m128","vmovapd xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F.W1 29 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVAPD xmm1, xmm2/m128","VMOVAPD xmm2/m128, xmm1","vmovapd xmm2/m128, xmm1","VEX.128.66.0F.WIG 28 /r","V","V","AVX","","w,r","","" +"VMOVAPD xmm1, {k}{z}, xmm2/m128","VMOVAPD xmm2/m128, {k}{z}, xmm1","vmovapd xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F.W1 28 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVAPD ymm2/m256, ymm1","VMOVAPD ymm1, ymm2/m256","vmovapd ymm1, ymm2/m256","VEX.256.66.0F.WIG 29 /r","V","V","AVX","","w,r","","" +"VMOVAPD ymm2/m256, {k}{z}, ymm1","VMOVAPD ymm1, {k}{z}, ymm2/m256","vmovapd ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F.W1 29 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVAPD ymm1, ymm2/m256","VMOVAPD ymm2/m256, ymm1","vmovapd ymm2/m256, ymm1","VEX.256.66.0F.WIG 28 /r","V","V","AVX","","w,r","","" +"VMOVAPD ymm1, {k}{z}, ymm2/m256","VMOVAPD ymm2/m256, {k}{z}, ymm1","vmovapd ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F.W1 28 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVAPD zmm2/m512, {k}{z}, zmm1","VMOVAPD zmm1, {k}{z}, zmm2/m512","vmovapd zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F.W1 29 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVAPD zmm1, {k}{z}, zmm2/m512","VMOVAPD zmm2/m512, {k}{z}, zmm1","vmovapd zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F.W1 28 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVAPS xmm2/m128, xmm1","VMOVAPS xmm1, xmm2/m128","vmovaps xmm1, xmm2/m128","VEX.128.0F.WIG 29 /r","V","V","AVX","","w,r","","" +"VMOVAPS xmm2/m128, {k}{z}, xmm1","VMOVAPS xmm1, {k}{z}, xmm2/m128","vmovaps xmm1, {k}{z}, xmm2/m128","EVEX.128.0F.W0 29 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVAPS xmm1, xmm2/m128","VMOVAPS xmm2/m128, xmm1","vmovaps xmm2/m128, xmm1","VEX.128.0F.WIG 28 /r","V","V","AVX","","w,r","","" +"VMOVAPS xmm1, {k}{z}, xmm2/m128","VMOVAPS xmm2/m128, {k}{z}, xmm1","vmovaps xmm2/m128, {k}{z}, xmm1","EVEX.128.0F.W0 28 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVAPS ymm2/m256, ymm1","VMOVAPS ymm1, ymm2/m256","vmovaps ymm1, ymm2/m256","VEX.256.0F.WIG 29 /r","V","V","AVX","","w,r","","" +"VMOVAPS ymm2/m256, {k}{z}, ymm1","VMOVAPS ymm1, {k}{z}, ymm2/m256","vmovaps ymm1, {k}{z}, ymm2/m256","EVEX.256.0F.W0 29 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVAPS ymm1, ymm2/m256","VMOVAPS ymm2/m256, ymm1","vmovaps ymm2/m256, ymm1","VEX.256.0F.WIG 28 /r","V","V","AVX","","w,r","","" +"VMOVAPS ymm1, {k}{z}, ymm2/m256","VMOVAPS ymm2/m256, {k}{z}, ymm1","vmovaps ymm2/m256, {k}{z}, ymm1","EVEX.256.0F.W0 28 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVAPS zmm2/m512, {k}{z}, zmm1","VMOVAPS zmm1, {k}{z}, zmm2/m512","vmovaps zmm1, {k}{z}, zmm2/m512","EVEX.512.0F.W0 29 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVAPS zmm1, {k}{z}, zmm2/m512","VMOVAPS zmm2/m512, {k}{z}, zmm1","vmovaps zmm2/m512, {k}{z}, zmm1","EVEX.512.0F.W0 28 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVD xmm1, r/m32","VMOVD r/m32, xmm1","vmovd r/m32, xmm1","EVEX.128.66.0F.W0 6E /r","V","V","AVX512F+AVX512VL","scale4","w,r","","" +"VMOVD xmm1, r/m32","VMOVD r/m32, xmm1","vmovd r/m32, xmm1","VEX.128.66.0F.W0 6E /r","V","V","AVX","","w,r","","" +"VMOVD r/m32, xmm1","VMOVD xmm1, r/m32","vmovd xmm1, r/m32","EVEX.128.66.0F.W0 7E /r","V","V","AVX512F+AVX512VL","scale4","w,r","","" +"VMOVD r/m32, xmm1","VMOVD xmm1, r/m32","vmovd xmm1, r/m32","VEX.128.66.0F.W0 7E /r","V","V","AVX","","w,r","","" +"VMOVDDUP xmm1, xmm2/m64","VMOVDDUP xmm2/m64, xmm1","vmovddup xmm2/m64, xmm1","VEX.128.F2.0F.WIG 12 /r","V","V","AVX","","w,r","","" +"VMOVDDUP xmm1, {k}{z}, xmm2/m64","VMOVDDUP xmm2/m64, {k}{z}, xmm1","vmovddup xmm2/m64, {k}{z}, xmm1","EVEX.128.F2.0F.W1 12 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VMOVDDUP ymm1, ymm2/m256","VMOVDDUP ymm2/m256, ymm1","vmovddup ymm2/m256, ymm1","VEX.256.F2.0F.WIG 12 /r","V","V","AVX","","w,r","","" +"VMOVDDUP ymm1, {k}{z}, ymm2/m256","VMOVDDUP ymm2/m256, {k}{z}, ymm1","vmovddup ymm2/m256, {k}{z}, ymm1","EVEX.256.F2.0F.W1 12 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVDDUP zmm1, {k}{z}, zmm2/m512","VMOVDDUP zmm2/m512, {k}{z}, zmm1","vmovddup zmm2/m512, {k}{z}, zmm1","EVEX.512.F2.0F.W1 12 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVDQA xmm2/m128, xmm1","VMOVDQA xmm1, xmm2/m128","vmovdqa xmm1, xmm2/m128","VEX.128.66.0F.WIG 7F /r","V","V","AVX","","w,r","","" +"VMOVDQA xmm1, xmm2/m128","VMOVDQA xmm2/m128, xmm1","vmovdqa xmm2/m128, xmm1","VEX.128.66.0F.WIG 6F /r","V","V","AVX","","w,r","","" +"VMOVDQA ymm2/m256, ymm1","VMOVDQA ymm1, ymm2/m256","vmovdqa ymm1, ymm2/m256","VEX.256.66.0F.WIG 7F /r","V","V","AVX","","w,r","","" +"VMOVDQA ymm1, ymm2/m256","VMOVDQA ymm2/m256, ymm1","vmovdqa ymm2/m256, ymm1","VEX.256.66.0F.WIG 6F /r","V","V","AVX","","w,r","","" +"VMOVDQA32 xmm2/m128, {k}{z}, xmm1","VMOVDQA32 xmm1, {k}{z}, xmm2/m128","vmovdqa32 xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F.W0 7F /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVDQA32 xmm1, {k}{z}, xmm2/m128","VMOVDQA32 xmm2/m128, {k}{z}, xmm1","vmovdqa32 xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F.W0 6F /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVDQA32 ymm2/m256, {k}{z}, ymm1","VMOVDQA32 ymm1, {k}{z}, ymm2/m256","vmovdqa32 ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F.W0 7F /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVDQA32 ymm1, {k}{z}, ymm2/m256","VMOVDQA32 ymm2/m256, {k}{z}, ymm1","vmovdqa32 ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F.W0 6F /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVDQA32 zmm2/m512, {k}{z}, zmm1","VMOVDQA32 zmm1, {k}{z}, zmm2/m512","vmovdqa32 zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F.W0 7F /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVDQA32 zmm1, {k}{z}, zmm2/m512","VMOVDQA32 zmm2/m512, {k}{z}, zmm1","vmovdqa32 zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F.W0 6F /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVDQA64 xmm2/m128, {k}{z}, xmm1","VMOVDQA64 xmm1, {k}{z}, xmm2/m128","vmovdqa64 xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F.W1 7F /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","Y","128" +"VMOVDQA64 xmm1, {k}{z}, xmm2/m128","VMOVDQA64 xmm2/m128, {k}{z}, xmm1","vmovdqa64 xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F.W1 6F /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","Y","128" +"VMOVDQA64 ymm2/m256, {k}{z}, ymm1","VMOVDQA64 ymm1, {k}{z}, ymm2/m256","vmovdqa64 ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F.W1 7F /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","Y","256" +"VMOVDQA64 ymm1, {k}{z}, ymm2/m256","VMOVDQA64 ymm2/m256, {k}{z}, ymm1","vmovdqa64 ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F.W1 6F /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","Y","256" +"VMOVDQA64 zmm2/m512, {k}{z}, zmm1","VMOVDQA64 zmm1, {k}{z}, zmm2/m512","vmovdqa64 zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F.W1 7F /r","V","V","AVX512F","scale64","w,r,r","Y","512" +"VMOVDQA64 zmm1, {k}{z}, zmm2/m512","VMOVDQA64 zmm2/m512, {k}{z}, zmm1","vmovdqa64 zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F.W1 6F /r","V","V","AVX512F","scale64","w,r,r","Y","512" +"VMOVDQU xmm2/m128, xmm1","VMOVDQU xmm1, xmm2/m128","vmovdqu xmm1, xmm2/m128","VEX.128.F3.0F.WIG 7F /r","V","V","AVX","","w,r","","" +"VMOVDQU xmm1, xmm2/m128","VMOVDQU xmm2/m128, xmm1","vmovdqu xmm2/m128, xmm1","VEX.128.F3.0F.WIG 6F /r","V","V","AVX","","w,r","","" +"VMOVDQU ymm2/m256, ymm1","VMOVDQU ymm1, ymm2/m256","vmovdqu ymm1, ymm2/m256","VEX.256.F3.0F.WIG 7F /r","V","V","AVX","","w,r","","" +"VMOVDQU ymm1, ymm2/m256","VMOVDQU ymm2/m256, ymm1","vmovdqu ymm2/m256, ymm1","VEX.256.F3.0F.WIG 6F /r","V","V","AVX","","w,r","","" +"VMOVDQU16 xmm2/m128, {k}{z}, xmm1","VMOVDQU16 xmm1, {k}{z}, xmm2/m128","vmovdqu16 xmm1, {k}{z}, xmm2/m128","EVEX.128.F2.0F.W1 7F /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VMOVDQU16 xmm1, {k}{z}, xmm2/m128","VMOVDQU16 xmm2/m128, {k}{z}, xmm1","vmovdqu16 xmm2/m128, {k}{z}, xmm1","EVEX.128.F2.0F.W1 6F /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VMOVDQU16 ymm2/m256, {k}{z}, ymm1","VMOVDQU16 ymm1, {k}{z}, ymm2/m256","vmovdqu16 ymm1, {k}{z}, ymm2/m256","EVEX.256.F2.0F.W1 7F /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r","","" +"VMOVDQU16 ymm1, {k}{z}, ymm2/m256","VMOVDQU16 ymm2/m256, {k}{z}, ymm1","vmovdqu16 ymm2/m256, {k}{z}, ymm1","EVEX.256.F2.0F.W1 6F /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r","","" +"VMOVDQU16 zmm2/m512, {k}{z}, zmm1","VMOVDQU16 zmm1, {k}{z}, zmm2/m512","vmovdqu16 zmm1, {k}{z}, zmm2/m512","EVEX.512.F2.0F.W1 7F /r","V","V","AVX512BW","scale64","w,r,r","","" +"VMOVDQU16 zmm1, {k}{z}, zmm2/m512","VMOVDQU16 zmm2/m512, {k}{z}, zmm1","vmovdqu16 zmm2/m512, {k}{z}, zmm1","EVEX.512.F2.0F.W1 6F /r","V","V","AVX512BW","scale64","w,r,r","","" +"VMOVDQU32 xmm2/m128, {k}{z}, xmm1","VMOVDQU32 xmm1, {k}{z}, xmm2/m128","vmovdqu32 xmm1, {k}{z}, xmm2/m128","EVEX.128.F3.0F.W0 7F /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","Y","128" +"VMOVDQU32 xmm1, {k}{z}, xmm2/m128","VMOVDQU32 xmm2/m128, {k}{z}, xmm1","vmovdqu32 xmm2/m128, {k}{z}, xmm1","EVEX.128.F3.0F.W0 6F /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","Y","128" +"VMOVDQU32 ymm2/m256, {k}{z}, ymm1","VMOVDQU32 ymm1, {k}{z}, ymm2/m256","vmovdqu32 ymm1, {k}{z}, ymm2/m256","EVEX.256.F3.0F.W0 7F /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","Y","256" +"VMOVDQU32 ymm1, {k}{z}, ymm2/m256","VMOVDQU32 ymm2/m256, {k}{z}, ymm1","vmovdqu32 ymm2/m256, {k}{z}, ymm1","EVEX.256.F3.0F.W0 6F /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","Y","256" +"VMOVDQU32 zmm2/m512, {k}{z}, zmm1","VMOVDQU32 zmm1, {k}{z}, zmm2/m512","vmovdqu32 zmm1, {k}{z}, zmm2/m512","EVEX.512.F3.0F.W0 7F /r","V","V","AVX512F","scale64","w,r,r","Y","512" +"VMOVDQU32 zmm1, {k}{z}, zmm2/m512","VMOVDQU32 zmm2/m512, {k}{z}, zmm1","vmovdqu32 zmm2/m512, {k}{z}, zmm1","EVEX.512.F3.0F.W0 6F /r","V","V","AVX512F","scale64","w,r,r","Y","512" +"VMOVDQU64 xmm2/m128, {k}{z}, xmm1","VMOVDQU64 xmm1, {k}{z}, xmm2/m128","vmovdqu64 xmm1, {k}{z}, xmm2/m128","EVEX.128.F3.0F.W1 7F /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","Y","128" +"VMOVDQU64 xmm1, {k}{z}, xmm2/m128","VMOVDQU64 xmm2/m128, {k}{z}, xmm1","vmovdqu64 xmm2/m128, {k}{z}, xmm1","EVEX.128.F3.0F.W1 6F /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","Y","128" +"VMOVDQU64 ymm2/m256, {k}{z}, ymm1","VMOVDQU64 ymm1, {k}{z}, ymm2/m256","vmovdqu64 ymm1, {k}{z}, ymm2/m256","EVEX.256.F3.0F.W1 7F /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","Y","256" +"VMOVDQU64 ymm1, {k}{z}, ymm2/m256","VMOVDQU64 ymm2/m256, {k}{z}, ymm1","vmovdqu64 ymm2/m256, {k}{z}, ymm1","EVEX.256.F3.0F.W1 6F /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","Y","256" +"VMOVDQU64 zmm2/m512, {k}{z}, zmm1","VMOVDQU64 zmm1, {k}{z}, zmm2/m512","vmovdqu64 zmm1, {k}{z}, zmm2/m512","EVEX.512.F3.0F.W1 7F /r","V","V","AVX512F","scale64","w,r,r","Y","512" +"VMOVDQU64 zmm1, {k}{z}, zmm2/m512","VMOVDQU64 zmm2/m512, {k}{z}, zmm1","vmovdqu64 zmm2/m512, {k}{z}, zmm1","EVEX.512.F3.0F.W1 6F /r","V","V","AVX512F","scale64","w,r,r","Y","512" +"VMOVDQU8 xmm2/m128, {k}{z}, xmm1","VMOVDQU8 xmm1, {k}{z}, xmm2/m128","vmovdqu8 xmm1, {k}{z}, xmm2/m128","EVEX.128.F2.0F.W0 7F /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","Y","128" +"VMOVDQU8 xmm1, {k}{z}, xmm2/m128","VMOVDQU8 xmm2/m128, {k}{z}, xmm1","vmovdqu8 xmm2/m128, {k}{z}, xmm1","EVEX.128.F2.0F.W0 6F /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","Y","128" +"VMOVDQU8 ymm2/m256, {k}{z}, ymm1","VMOVDQU8 ymm1, {k}{z}, ymm2/m256","vmovdqu8 ymm1, {k}{z}, ymm2/m256","EVEX.256.F2.0F.W0 7F /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r","Y","256" +"VMOVDQU8 ymm1, {k}{z}, ymm2/m256","VMOVDQU8 ymm2/m256, {k}{z}, ymm1","vmovdqu8 ymm2/m256, {k}{z}, ymm1","EVEX.256.F2.0F.W0 6F /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r","Y","256" +"VMOVDQU8 zmm2/m512, {k}{z}, zmm1","VMOVDQU8 zmm1, {k}{z}, zmm2/m512","vmovdqu8 zmm1, {k}{z}, zmm2/m512","EVEX.512.F2.0F.W0 7F /r","V","V","AVX512BW","scale64","w,r,r","Y","512" +"VMOVDQU8 zmm1, {k}{z}, zmm2/m512","VMOVDQU8 zmm2/m512, {k}{z}, zmm1","vmovdqu8 zmm2/m512, {k}{z}, zmm1","EVEX.512.F2.0F.W0 6F /r","V","V","AVX512BW","scale64","w,r,r","Y","512" +"VMOVHLPS xmm1, xmmV, xmm2","VMOVHLPS xmm2, xmmV, xmm1","vmovhlps xmm2, xmmV, xmm1","EVEX.NDS.128.0F.W0 12 /r","V","V","AVX512F+AVX512VL","modrm_regonly","w,r,r","","" +"VMOVHLPS xmm1, xmmV, xmm2","VMOVHLPS xmm2, xmmV, xmm1","vmovhlps xmm2, xmmV, xmm1","VEX.NDS.128.0F.WIG 12 /r","V","V","AVX","modrm_regonly","w,r,r","","" +"VMOVHPD xmm1, xmmV, m64","VMOVHPD m64, xmmV, xmm1","vmovhpd m64, xmmV, xmm1","EVEX.NDS.LIG.66.0F.W1 16 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,r,r","","" +"VMOVHPD xmm1, xmmV, m64","VMOVHPD m64, xmmV, xmm1","vmovhpd m64, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 16 /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMOVHPD m64, xmm1","VMOVHPD xmm1, m64","vmovhpd xmm1, m64","EVEX.LIG.66.0F.W1 17 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,r","","" +"VMOVHPD m64, xmm1","VMOVHPD xmm1, m64","vmovhpd xmm1, m64","VEX.128.66.0F.WIG 17 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVHPS xmm1, xmmV, m64","VMOVHPS m64, xmmV, xmm1","vmovhps m64, xmmV, xmm1","EVEX.NDS.128.0F.W0 16 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,r,r","","" +"VMOVHPS xmm1, xmmV, m64","VMOVHPS m64, xmmV, xmm1","vmovhps m64, xmmV, xmm1","VEX.NDS.128.0F.WIG 16 /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMOVHPS m64, xmm1","VMOVHPS xmm1, m64","vmovhps xmm1, m64","EVEX.128.0F.W0 17 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,r","","" +"VMOVHPS m64, xmm1","VMOVHPS xmm1, m64","vmovhps xmm1, m64","VEX.128.0F.WIG 17 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVLHPS xmm1, xmmV, xmm2","VMOVLHPS xmm2, xmmV, xmm1","vmovlhps xmm2, xmmV, xmm1","EVEX.NDS.128.0F.W0 16 /r","V","V","AVX512F+AVX512VL","modrm_regonly","w,r,r","","" +"VMOVLHPS xmm1, xmmV, xmm2","VMOVLHPS xmm2, xmmV, xmm1","vmovlhps xmm2, xmmV, xmm1","VEX.NDS.128.0F.WIG 16 /r","V","V","AVX","modrm_regonly","w,r,r","","" +"VMOVLPD xmm1, xmmV, m64","VMOVLPD m64, xmmV, xmm1","vmovlpd m64, xmmV, xmm1","EVEX.NDS.LIG.66.0F.W1 12 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,r,r","","" +"VMOVLPD xmm1, xmmV, m64","VMOVLPD m64, xmmV, xmm1","vmovlpd m64, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 12 /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMOVLPD m64, xmm1","VMOVLPD xmm1, m64","vmovlpd xmm1, m64","EVEX.LIG.66.0F.W1 13 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,r","","" +"VMOVLPD m64, xmm1","VMOVLPD xmm1, m64","vmovlpd xmm1, m64","VEX.128.66.0F.WIG 13 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVLPS xmm1, xmmV, m64","VMOVLPS m64, xmmV, xmm1","vmovlps m64, xmmV, xmm1","EVEX.NDS.128.0F.W0 12 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,r,r","","" +"VMOVLPS xmm1, xmmV, m64","VMOVLPS m64, xmmV, xmm1","vmovlps m64, xmmV, xmm1","VEX.NDS.128.0F.WIG 12 /r","V","V","AVX","modrm_memonly","w,r,r","","" +"VMOVLPS m64, xmm1","VMOVLPS xmm1, m64","vmovlps xmm1, m64","EVEX.128.0F.W0 13 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,r","","" +"VMOVLPS m64, xmm1","VMOVLPS xmm1, m64","vmovlps xmm1, m64","VEX.128.0F.WIG 13 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVMSKPD r32, xmm2","VMOVMSKPD xmm2, r32","vmovmskpd xmm2, r32","VEX.128.66.0F.WIG 50 /r","V","V","AVX","modrm_regonly","w,r","","" +"VMOVMSKPD r32, ymm2","VMOVMSKPD ymm2, r32","vmovmskpd ymm2, r32","VEX.256.66.0F.WIG 50 /r","V","V","AVX","modrm_regonly","w,r","","" +"VMOVMSKPS r32, xmm2","VMOVMSKPS xmm2, r32","vmovmskps xmm2, r32","VEX.128.0F.WIG 50 /r","V","V","AVX","modrm_regonly","w,r","","" +"VMOVMSKPS r32, ymm2","VMOVMSKPS ymm2, r32","vmovmskps ymm2, r32","VEX.256.0F.WIG 50 /r","V","V","AVX","modrm_regonly","w,r","","" +"VMOVNTDQ m128, xmm1","VMOVNTDQ xmm1, m128","vmovntdq xmm1, m128","EVEX.128.66.0F.W0 E7 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale16","w,r","","" +"VMOVNTDQ m128, xmm1","VMOVNTDQ xmm1, m128","vmovntdq xmm1, m128","VEX.128.66.0F.WIG E7 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVNTDQ m256, ymm1","VMOVNTDQ ymm1, m256","vmovntdq ymm1, m256","EVEX.256.66.0F.W0 E7 /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale32","w,r","","" +"VMOVNTDQ m256, ymm1","VMOVNTDQ ymm1, m256","vmovntdq ymm1, m256","VEX.256.66.0F.WIG E7 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVNTDQ m512, zmm1","VMOVNTDQ zmm1, m512","vmovntdq zmm1, m512","EVEX.512.66.0F.W0 E7 /r","V","V","AVX512F","modrm_memonly,scale64","w,r","","" +"VMOVNTDQA xmm1, m128","VMOVNTDQA m128, xmm1","vmovntdqa m128, xmm1","EVEX.128.66.0F38.W0 2A /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale16","w,r","","" +"VMOVNTDQA xmm1, m128","VMOVNTDQA m128, xmm1","vmovntdqa m128, xmm1","VEX.128.66.0F38.WIG 2A /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVNTDQA ymm1, m256","VMOVNTDQA m256, ymm1","vmovntdqa m256, ymm1","EVEX.256.66.0F38.W0 2A /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale32","w,r","","" +"VMOVNTDQA ymm1, m256","VMOVNTDQA m256, ymm1","vmovntdqa m256, ymm1","VEX.256.66.0F38.WIG 2A /r","V","V","AVX2","modrm_memonly","w,r","","" +"VMOVNTDQA zmm1, m512","VMOVNTDQA m512, zmm1","vmovntdqa m512, zmm1","EVEX.512.66.0F38.W0 2A /r","V","V","AVX512F","modrm_memonly,scale64","w,r","","" +"VMOVNTPD m128, xmm1","VMOVNTPD xmm1, m128","vmovntpd xmm1, m128","EVEX.128.66.0F.W1 2B /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale16","w,r","","" +"VMOVNTPD m128, xmm1","VMOVNTPD xmm1, m128","vmovntpd xmm1, m128","VEX.128.66.0F.WIG 2B /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVNTPD m256, ymm1","VMOVNTPD ymm1, m256","vmovntpd ymm1, m256","EVEX.256.66.0F.W1 2B /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale32","w,r","","" +"VMOVNTPD m256, ymm1","VMOVNTPD ymm1, m256","vmovntpd ymm1, m256","VEX.256.66.0F.WIG 2B /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVNTPD m512, zmm1","VMOVNTPD zmm1, m512","vmovntpd zmm1, m512","EVEX.512.66.0F.W1 2B /r","V","V","AVX512F","modrm_memonly,scale64","w,r","","" +"VMOVNTPS m128, xmm1","VMOVNTPS xmm1, m128","vmovntps xmm1, m128","EVEX.128.0F.W0 2B /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale16","w,r","","" +"VMOVNTPS m128, xmm1","VMOVNTPS xmm1, m128","vmovntps xmm1, m128","VEX.128.0F.WIG 2B /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVNTPS m256, ymm1","VMOVNTPS ymm1, m256","vmovntps ymm1, m256","EVEX.256.0F.W0 2B /r","V","V","AVX512F+AVX512VL","modrm_memonly,scale32","w,r","","" +"VMOVNTPS m256, ymm1","VMOVNTPS ymm1, m256","vmovntps ymm1, m256","VEX.256.0F.WIG 2B /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVNTPS m512, zmm1","VMOVNTPS zmm1, m512","vmovntps zmm1, m512","EVEX.512.0F.W0 2B /r","V","V","AVX512F","modrm_memonly,scale64","w,r","","" +"VMOVQ xmm1, r/m64","VMOVQ r/m64, xmm1","vmovq r/m64, xmm1","EVEX.128.66.0F.W1 6E /r","N.S.","V","AVX512F+AVX512VL","scale8","w,r","","" +"VMOVQ xmm1, r/m64","VMOVQ r/m64, xmm1","vmovq r/m64, xmm1","VEX.128.66.0F.W1 6E /r","N.S.","V","AVX","","w,r","","" +"VMOVQ r/m64, xmm1","VMOVQ xmm1, r/m64","vmovq xmm1, r/m64","EVEX.128.66.0F.W1 7E /r","N.S.","V","AVX512F+AVX512VL","scale8","w,r","","" +"VMOVQ r/m64, xmm1","VMOVQ xmm1, r/m64","vmovq xmm1, r/m64","VEX.128.66.0F.W1 7E /r","N.S.","V","AVX","","w,r","","" +"VMOVQ xmm2/m64, xmm1","VMOVQ xmm1, xmm2/m64","vmovq xmm1, xmm2/m64","EVEX.LIG.66.0F.W1 D6 /r","V","V","AVX512F+AVX512VL","scale8","w,r","","" +"VMOVQ xmm2/m64, xmm1","VMOVQ xmm1, xmm2/m64","vmovq xmm1, xmm2/m64","VEX.128.66.0F.WIG D6 /r","V","V","AVX","","w,r","","" +"VMOVQ xmm1, xmm2/m64","VMOVQ xmm2/m64, xmm1","vmovq xmm2/m64, xmm1","EVEX.LIG.F3.0F.W1 7E /r","V","V","AVX512F+AVX512VL","scale8","w,r","","" +"VMOVQ xmm1, xmm2/m64","VMOVQ xmm2/m64, xmm1","vmovq xmm2/m64, xmm1","VEX.128.F3.0F.WIG 7E /r","V","V","AVX","","w,r","","" +"VMOVSD xmm1, m64","VMOVSD m64, xmm1","vmovsd m64, xmm1","VEX.LIG.F2.0F.WIG 10 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVSD xmm1, {k}{z}, m64","VMOVSD m64, {k}{z}, xmm1","vmovsd m64, {k}{z}, xmm1","EVEX.LIG.F2.0F.W1 10 /r","V","V","AVX512F","modrm_memonly,scale8","w,r,r","","" +"VMOVSD m64, xmm1","VMOVSD xmm1, m64","vmovsd xmm1, m64","VEX.LIG.F2.0F.WIG 11 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVSD xmm2, xmmV, xmm1","VMOVSD xmm1, xmmV, xmm2","vmovsd xmm1, xmmV, xmm2","VEX.NDS.LIG.F2.0F.WIG 11 /r","V","V","AVX","modrm_regonly","w,r,r","","" +"VMOVSD xmm2, {k}{z}, xmmV, xmm1","VMOVSD xmm1, xmmV, {k}{z}, xmm2","vmovsd xmm1, xmmV, {k}{z}, xmm2","EVEX.NDS.LIG.F2.0F.W1 11 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMOVSD m64, {k}, xmm1","VMOVSD xmm1, {k}, m64","vmovsd xmm1, {k}, m64","EVEX.LIG.F2.0F.W1 11 /r","V","V","AVX512F","modrm_memonly,scale8","w,r,r","","" +"VMOVSD xmm1, xmmV, xmm2","VMOVSD xmm2, xmmV, xmm1","vmovsd xmm2, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 10 /r","V","V","AVX","modrm_regonly","w,r,r","","" +"VMOVSD xmm1, {k}{z}, xmmV, xmm2","VMOVSD xmm2, xmmV, {k}{z}, xmm1","vmovsd xmm2, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 10 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMOVSHDUP xmm1, xmm2/m128","VMOVSHDUP xmm2/m128, xmm1","vmovshdup xmm2/m128, xmm1","VEX.128.F3.0F.WIG 16 /r","V","V","AVX","","w,r","","" +"VMOVSHDUP xmm1, {k}{z}, xmm2/m128","VMOVSHDUP xmm2/m128, {k}{z}, xmm1","vmovshdup xmm2/m128, {k}{z}, xmm1","EVEX.128.F3.0F.W0 16 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVSHDUP ymm1, ymm2/m256","VMOVSHDUP ymm2/m256, ymm1","vmovshdup ymm2/m256, ymm1","VEX.256.F3.0F.WIG 16 /r","V","V","AVX","","w,r","","" +"VMOVSHDUP ymm1, {k}{z}, ymm2/m256","VMOVSHDUP ymm2/m256, {k}{z}, ymm1","vmovshdup ymm2/m256, {k}{z}, ymm1","EVEX.256.F3.0F.W0 16 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVSHDUP zmm1, {k}{z}, zmm2/m512","VMOVSHDUP zmm2/m512, {k}{z}, zmm1","vmovshdup zmm2/m512, {k}{z}, zmm1","EVEX.512.F3.0F.W0 16 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVSLDUP xmm1, xmm2/m128","VMOVSLDUP xmm2/m128, xmm1","vmovsldup xmm2/m128, xmm1","VEX.128.F3.0F.WIG 12 /r","V","V","AVX","","w,r","","" +"VMOVSLDUP xmm1, {k}{z}, xmm2/m128","VMOVSLDUP xmm2/m128, {k}{z}, xmm1","vmovsldup xmm2/m128, {k}{z}, xmm1","EVEX.128.F3.0F.W0 12 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVSLDUP ymm1, ymm2/m256","VMOVSLDUP ymm2/m256, ymm1","vmovsldup ymm2/m256, ymm1","VEX.256.F3.0F.WIG 12 /r","V","V","AVX","","w,r","","" +"VMOVSLDUP ymm1, {k}{z}, ymm2/m256","VMOVSLDUP ymm2/m256, {k}{z}, ymm1","vmovsldup ymm2/m256, {k}{z}, ymm1","EVEX.256.F3.0F.W0 12 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVSLDUP zmm1, {k}{z}, zmm2/m512","VMOVSLDUP zmm2/m512, {k}{z}, zmm1","vmovsldup zmm2/m512, {k}{z}, zmm1","EVEX.512.F3.0F.W0 12 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVSS xmm1, m32","VMOVSS m32, xmm1","vmovss m32, xmm1","VEX.LIG.F3.0F.WIG 10 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVSS xmm1, {k}{z}, m32","VMOVSS m32, {k}{z}, xmm1","vmovss m32, {k}{z}, xmm1","EVEX.LIG.F3.0F.W0 10 /r","V","V","AVX512F","modrm_memonly,scale4","w,r,r","","" +"VMOVSS m32, xmm1","VMOVSS xmm1, m32","vmovss xmm1, m32","VEX.LIG.F3.0F.WIG 11 /r","V","V","AVX","modrm_memonly","w,r","","" +"VMOVSS xmm2, xmmV, xmm1","VMOVSS xmm1, xmmV, xmm2","vmovss xmm1, xmmV, xmm2","VEX.NDS.LIG.F3.0F.WIG 11 /r","V","V","AVX","modrm_regonly","w,r,r","","" +"VMOVSS xmm2, {k}{z}, xmmV, xmm1","VMOVSS xmm1, xmmV, {k}{z}, xmm2","vmovss xmm1, xmmV, {k}{z}, xmm2","EVEX.NDS.LIG.F3.0F.W0 11 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMOVSS m32, {k}, xmm1","VMOVSS xmm1, {k}, m32","vmovss xmm1, {k}, m32","EVEX.LIG.F3.0F.W0 11 /r","V","V","AVX512F","modrm_memonly,scale4","w,r,r","","" +"VMOVSS xmm1, xmmV, xmm2","VMOVSS xmm2, xmmV, xmm1","vmovss xmm2, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 10 /r","V","V","AVX","modrm_regonly","w,r,r","","" +"VMOVSS xmm1, {k}{z}, xmmV, xmm2","VMOVSS xmm2, xmmV, {k}{z}, xmm1","vmovss xmm2, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 10 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMOVUPD xmm2/m128, xmm1","VMOVUPD xmm1, xmm2/m128","vmovupd xmm1, xmm2/m128","VEX.128.66.0F.WIG 11 /r","V","V","AVX","","w,r","","" +"VMOVUPD xmm2/m128, {k}{z}, xmm1","VMOVUPD xmm1, {k}{z}, xmm2/m128","vmovupd xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F.W1 11 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVUPD xmm1, xmm2/m128","VMOVUPD xmm2/m128, xmm1","vmovupd xmm2/m128, xmm1","VEX.128.66.0F.WIG 10 /r","V","V","AVX","","w,r","","" +"VMOVUPD xmm1, {k}{z}, xmm2/m128","VMOVUPD xmm2/m128, {k}{z}, xmm1","vmovupd xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F.W1 10 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVUPD ymm2/m256, ymm1","VMOVUPD ymm1, ymm2/m256","vmovupd ymm1, ymm2/m256","VEX.256.66.0F.WIG 11 /r","V","V","AVX","","w,r","","" +"VMOVUPD ymm2/m256, {k}{z}, ymm1","VMOVUPD ymm1, {k}{z}, ymm2/m256","vmovupd ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F.W1 11 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVUPD ymm1, ymm2/m256","VMOVUPD ymm2/m256, ymm1","vmovupd ymm2/m256, ymm1","VEX.256.66.0F.WIG 10 /r","V","V","AVX","","w,r","","" +"VMOVUPD ymm1, {k}{z}, ymm2/m256","VMOVUPD ymm2/m256, {k}{z}, ymm1","vmovupd ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F.W1 10 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVUPD zmm2/m512, {k}{z}, zmm1","VMOVUPD zmm1, {k}{z}, zmm2/m512","vmovupd zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F.W1 11 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVUPD zmm1, {k}{z}, zmm2/m512","VMOVUPD zmm2/m512, {k}{z}, zmm1","vmovupd zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F.W1 10 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVUPS xmm2/m128, xmm1","VMOVUPS xmm1, xmm2/m128","vmovups xmm1, xmm2/m128","VEX.128.0F.WIG 11 /r","V","V","AVX","","w,r","","" +"VMOVUPS xmm2/m128, {k}{z}, xmm1","VMOVUPS xmm1, {k}{z}, xmm2/m128","vmovups xmm1, {k}{z}, xmm2/m128","EVEX.128.0F.W0 11 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVUPS xmm1, xmm2/m128","VMOVUPS xmm2/m128, xmm1","vmovups xmm2/m128, xmm1","VEX.128.0F.WIG 10 /r","V","V","AVX","","w,r","","" +"VMOVUPS xmm1, {k}{z}, xmm2/m128","VMOVUPS xmm2/m128, {k}{z}, xmm1","vmovups xmm2/m128, {k}{z}, xmm1","EVEX.128.0F.W0 10 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VMOVUPS ymm2/m256, ymm1","VMOVUPS ymm1, ymm2/m256","vmovups ymm1, ymm2/m256","VEX.256.0F.WIG 11 /r","V","V","AVX","","w,r","","" +"VMOVUPS ymm2/m256, {k}{z}, ymm1","VMOVUPS ymm1, {k}{z}, ymm2/m256","vmovups ymm1, {k}{z}, ymm2/m256","EVEX.256.0F.W0 11 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVUPS ymm1, ymm2/m256","VMOVUPS ymm2/m256, ymm1","vmovups ymm2/m256, ymm1","VEX.256.0F.WIG 10 /r","V","V","AVX","","w,r","","" +"VMOVUPS ymm1, {k}{z}, ymm2/m256","VMOVUPS ymm2/m256, {k}{z}, ymm1","vmovups ymm2/m256, {k}{z}, ymm1","EVEX.256.0F.W0 10 /r","V","V","AVX512F+AVX512VL","scale32","w,r,r","","" +"VMOVUPS zmm2/m512, {k}{z}, zmm1","VMOVUPS zmm1, {k}{z}, zmm2/m512","vmovups zmm1, {k}{z}, zmm2/m512","EVEX.512.0F.W0 11 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMOVUPS zmm1, {k}{z}, zmm2/m512","VMOVUPS zmm2/m512, {k}{z}, zmm1","vmovups zmm2/m512, {k}{z}, zmm1","EVEX.512.0F.W0 10 /r","V","V","AVX512F","scale64","w,r,r","","" +"VMPSADBW xmm1, xmmV, xmm2/m128, imm8u","VMPSADBW imm8u, xmm2/m128, xmmV, xmm1","vmpsadbw imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 42 /r ib","V","V","AVX","","w,r,r,r","","" +"VMPSADBW ymm1, ymmV, ymm2/m256, imm8u","VMPSADBW imm8u, ymm2/m256, ymmV, ymm1","vmpsadbw imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.WIG 42 /r ib","V","V","AVX2","","w,r,r,r","","" +"VMPTRLD m64","VMPTRLD m64","vmptrld m64","0F C7 /6","V","V","VTX","modrm_memonly","r","","" +"VMPTRST m64","VMPTRST m64","vmptrst m64","0F C7 /7","V","V","VTX","modrm_memonly","w","","" +"VMREAD r/m32, r32","VMREAD r32, r/m32","vmread r32, r/m32","0F 78 /r","V","N.S.","VTX","","rw,r","","" +"VMREAD r/m64, r64","VMREAD r64, r/m64","vmread r64, r/m64","0F 78 /r","N.S.","V","VTX","default64","rw,r","","" +"VMRESUME","VMRESUME","vmresume","0F 01 C3","V","V","VTX","","","","" +"VMRUN EAX","VMRUNL EAX","vmrunl EAX","0F 01 D8","V","V","SVM","amd,modrm_regonly,operand32","r","Y","32" +"VMRUN RAX","VMRUNQ RAX","vmrunq RAX","REX.W 0F 01 D8","N.S.","V","SVM","amd,modrm_regonly","r","Y","64" +"VMRUN AX","VMRUNW AX","vmrunw AX","0F 01 D8","V","V","SVM","amd,modrm_regonly,operand16","r","Y","16" +"VMSAVE","VMSAVE","vmsave","0F 01 DB","V","V","SVM","amd","","","" +"VMULPD xmm1, xmmV, xmm2/m128","VMULPD xmm2/m128, xmmV, xmm1","vmulpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 59 /r","V","V","AVX","","w,r,r","","" +"VMULPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VMULPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vmulpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 59 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VMULPD ymm1, ymmV, ymm2/m256","VMULPD ymm2/m256, ymmV, ymm1","vmulpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 59 /r","V","V","AVX","","w,r,r","","" +"VMULPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VMULPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vmulpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 59 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VMULPD zmm1{er}, {k}{z}, zmmV, zmm2","VMULPD zmm2, zmmV, {k}{z}, zmm1{er}","vmulpd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.66.0F.W1 59 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMULPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VMULPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vmulpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 59 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VMULPS xmm1, xmmV, xmm2/m128","VMULPS xmm2/m128, xmmV, xmm1","vmulps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 59 /r","V","V","AVX","","w,r,r","","" +"VMULPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VMULPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vmulps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 59 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VMULPS ymm1, ymmV, ymm2/m256","VMULPS ymm2/m256, ymmV, ymm1","vmulps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 59 /r","V","V","AVX","","w,r,r","","" +"VMULPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VMULPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vmulps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 59 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VMULPS zmm1{er}, {k}{z}, zmmV, zmm2","VMULPS zmm2, zmmV, {k}{z}, zmm1{er}","vmulps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.0F.W0 59 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMULPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VMULPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vmulps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 59 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VMULSD xmm1{er}, {k}{z}, xmmV, xmm2","VMULSD xmm2, xmmV, {k}{z}, xmm1{er}","vmulsd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F2.0F.W1 59 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMULSD xmm1, xmmV, xmm2/m64","VMULSD xmm2/m64, xmmV, xmm1","vmulsd xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 59 /r","V","V","AVX","","w,r,r","","" +"VMULSD xmm1, {k}{z}, xmmV, xmm2/m64","VMULSD xmm2/m64, xmmV, {k}{z}, xmm1","vmulsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 59 /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VMULSS xmm1{er}, {k}{z}, xmmV, xmm2","VMULSS xmm2, xmmV, {k}{z}, xmm1{er}","vmulss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F3.0F.W0 59 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VMULSS xmm1, xmmV, xmm2/m32","VMULSS xmm2/m32, xmmV, xmm1","vmulss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 59 /r","V","V","AVX","","w,r,r","","" +"VMULSS xmm1, {k}{z}, xmmV, xmm2/m32","VMULSS xmm2/m32, xmmV, {k}{z}, xmm1","vmulss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 59 /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VMWRITE r32, r/m32","VMWRITE r/m32, r32","vmwrite r/m32, r32","0F 79 /r","V","N.S.","VTX","","r,r","","" +"VMWRITE r64, r/m64","VMWRITE r/m64, r64","vmwrite r/m64, r64","0F 79 /r","N.S.","V","VTX","default64","r,r","","" +"VMXOFF","VMXOFF","vmxoff","0F 01 C4","V","V","VTX","","","","" +"VMXON m64","VMXON m64","vmxon m64","F3 0F C7 /6","V","V","VTX","modrm_memonly","r","","" +"VORPD xmm1, xmmV, xmm2/m128","VORPD xmm2/m128, xmmV, xmm1","vorpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 56 /r","V","V","AVX","","w,r,r","","" +"VORPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VORPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vorpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 56 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VORPD ymm1, ymmV, ymm2/m256","VORPD ymm2/m256, ymmV, ymm1","vorpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 56 /r","V","V","AVX","","w,r,r","","" +"VORPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VORPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vorpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 56 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VORPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VORPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vorpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 56 /r","V","V","AVX512DQ","bscale8,scale64","w,r,r,r","","" +"VORPS xmm1, xmmV, xmm2/m128","VORPS xmm2/m128, xmmV, xmm1","vorps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 56 /r","V","V","AVX","","w,r,r","","" +"VORPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VORPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vorps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 56 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VORPS ymm1, ymmV, ymm2/m256","VORPS ymm2/m256, ymmV, ymm1","vorps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 56 /r","V","V","AVX","","w,r,r","","" +"VORPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VORPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vorps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 56 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VORPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VORPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vorps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 56 /r","V","V","AVX512DQ","bscale4,scale64","w,r,r,r","","" +"VP4DPWSSD zmm1, {k}{z}, zmmV+3, m128","VP4DPWSSD m128, zmmV+3, {k}{z}, zmm1","vp4dpwssd m128, zmmV+3, {k}{z}, zmm1","EVEX.DDS.512.F2.0F38.W0 52 /r","V","V","AVX512_4VNNIW","modrm_memonly,scale16","rw,r,r,r","","" +"VP4DPWSSDS zmm1, {k}{z}, zmmV+3, m128","VP4DPWSSDS m128, zmmV+3, {k}{z}, zmm1","vp4dpwssds m128, zmmV+3, {k}{z}, zmm1","EVEX.DDS.512.F2.0F38.W0 53 /r","V","V","AVX512_4VNNIW","modrm_memonly,scale16","rw,r,r,r","","" +"VPABSB xmm1, xmm2/m128","VPABSB xmm2/m128, xmm1","vpabsb xmm2/m128, xmm1","VEX.128.66.0F38.WIG 1C /r","V","V","AVX","","w,r","","" +"VPABSB xmm1, {k}{z}, xmm2/m128","VPABSB xmm2/m128, {k}{z}, xmm1","vpabsb xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 1C /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPABSB ymm1, ymm2/m256","VPABSB ymm2/m256, ymm1","vpabsb ymm2/m256, ymm1","VEX.256.66.0F38.WIG 1C /r","V","V","AVX2","","w,r","","" +"VPABSB ymm1, {k}{z}, ymm2/m256","VPABSB ymm2/m256, {k}{z}, ymm1","vpabsb ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 1C /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r","","" +"VPABSB zmm1, {k}{z}, zmm2/m512","VPABSB zmm2/m512, {k}{z}, zmm1","vpabsb zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 1C /r","V","V","AVX512BW","scale64","w,r,r","","" +"VPABSD xmm1, xmm2/m128","VPABSD xmm2/m128, xmm1","vpabsd xmm2/m128, xmm1","VEX.128.66.0F38.WIG 1E /r","V","V","AVX","","w,r","","" +"VPABSD xmm1, {k}{z}, xmm2/m128/m32bcst","VPABSD xmm2/m128/m32bcst, {k}{z}, xmm1","vpabsd xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W0 1E /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VPABSD ymm1, ymm2/m256","VPABSD ymm2/m256, ymm1","vpabsd ymm2/m256, ymm1","VEX.256.66.0F38.WIG 1E /r","V","V","AVX2","","w,r","","" +"VPABSD ymm1, {k}{z}, ymm2/m256/m32bcst","VPABSD ymm2/m256/m32bcst, {k}{z}, ymm1","vpabsd ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W0 1E /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VPABSD zmm1, {k}{z}, zmm2/m512/m32bcst","VPABSD zmm2/m512/m32bcst, {k}{z}, zmm1","vpabsd zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 1E /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VPABSQ xmm1, {k}{z}, xmm2/m128/m64bcst","VPABSQ xmm2/m128/m64bcst, {k}{z}, xmm1","vpabsq xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W1 1F /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","","" +"VPABSQ ymm1, {k}{z}, ymm2/m256/m64bcst","VPABSQ ymm2/m256/m64bcst, {k}{z}, ymm1","vpabsq ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W1 1F /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","","" +"VPABSQ zmm1, {k}{z}, zmm2/m512/m64bcst","VPABSQ zmm2/m512/m64bcst, {k}{z}, zmm1","vpabsq zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 1F /r","V","V","AVX512F","bscale8,scale64","w,r,r","","" +"VPABSW xmm1, xmm2/m128","VPABSW xmm2/m128, xmm1","vpabsw xmm2/m128, xmm1","VEX.128.66.0F38.WIG 1D /r","V","V","AVX","","w,r","","" +"VPABSW xmm1, {k}{z}, xmm2/m128","VPABSW xmm2/m128, {k}{z}, xmm1","vpabsw xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 1D /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPABSW ymm1, ymm2/m256","VPABSW ymm2/m256, ymm1","vpabsw ymm2/m256, ymm1","VEX.256.66.0F38.WIG 1D /r","V","V","AVX2","","w,r","","" +"VPABSW ymm1, {k}{z}, ymm2/m256","VPABSW ymm2/m256, {k}{z}, ymm1","vpabsw ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 1D /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r","","" +"VPABSW zmm1, {k}{z}, zmm2/m512","VPABSW zmm2/m512, {k}{z}, zmm1","vpabsw zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 1D /r","V","V","AVX512BW","scale64","w,r,r","","" +"VPACKSSDW xmm1, xmmV, xmm2/m128","VPACKSSDW xmm2/m128, xmmV, xmm1","vpackssdw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 6B /r","V","V","AVX","","w,r,r","","" +"VPACKSSDW xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPACKSSDW xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpackssdw xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 6B /r","V","V","AVX512BW+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPACKSSDW ymm1, ymmV, ymm2/m256","VPACKSSDW ymm2/m256, ymmV, ymm1","vpackssdw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 6B /r","V","V","AVX2","","w,r,r","","" +"VPACKSSDW ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPACKSSDW ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpackssdw ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 6B /r","V","V","AVX512BW+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPACKSSDW zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPACKSSDW zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpackssdw zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 6B /r","V","V","AVX512BW","bscale4,scale64","w,r,r,r","","" +"VPACKSSWB xmm1, xmmV, xmm2/m128","VPACKSSWB xmm2/m128, xmmV, xmm1","vpacksswb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 63 /r","V","V","AVX","","w,r,r","","" +"VPACKSSWB xmm1, {k}{z}, xmmV, xmm2/m128","VPACKSSWB xmm2/m128, xmmV, {k}{z}, xmm1","vpacksswb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG 63 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPACKSSWB ymm1, ymmV, ymm2/m256","VPACKSSWB ymm2/m256, ymmV, ymm1","vpacksswb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 63 /r","V","V","AVX2","","w,r,r","","" +"VPACKSSWB ymm1, {k}{z}, ymmV, ymm2/m256","VPACKSSWB ymm2/m256, ymmV, {k}{z}, ymm1","vpacksswb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG 63 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPACKSSWB zmm1, {k}{z}, zmmV, zmm2/m512","VPACKSSWB zmm2/m512, zmmV, {k}{z}, zmm1","vpacksswb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG 63 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPACKUSDW xmm1, xmmV, xmm2/m128","VPACKUSDW xmm2/m128, xmmV, xmm1","vpackusdw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 2B /r","V","V","AVX","","w,r,r","","" +"VPACKUSDW xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPACKUSDW xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpackusdw xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 2B /r","V","V","AVX512BW+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPACKUSDW ymm1, ymmV, ymm2/m256","VPACKUSDW ymm2/m256, ymmV, ymm1","vpackusdw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 2B /r","V","V","AVX2","","w,r,r","","" +"VPACKUSDW ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPACKUSDW ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpackusdw ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 2B /r","V","V","AVX512BW+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPACKUSDW zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPACKUSDW zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpackusdw zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 2B /r","V","V","AVX512BW","bscale4,scale64","w,r,r,r","","" +"VPACKUSWB xmm1, xmmV, xmm2/m128","VPACKUSWB xmm2/m128, xmmV, xmm1","vpackuswb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 67 /r","V","V","AVX","","w,r,r","","" +"VPACKUSWB xmm1, {k}{z}, xmmV, xmm2/m128","VPACKUSWB xmm2/m128, xmmV, {k}{z}, xmm1","vpackuswb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG 67 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPACKUSWB ymm1, ymmV, ymm2/m256","VPACKUSWB ymm2/m256, ymmV, ymm1","vpackuswb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 67 /r","V","V","AVX2","","w,r,r","","" +"VPACKUSWB ymm1, {k}{z}, ymmV, ymm2/m256","VPACKUSWB ymm2/m256, ymmV, {k}{z}, ymm1","vpackuswb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG 67 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPACKUSWB zmm1, {k}{z}, zmmV, zmm2/m512","VPACKUSWB zmm2/m512, zmmV, {k}{z}, zmm1","vpackuswb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG 67 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPADDB xmm1, xmmV, xmm2/m128","VPADDB xmm2/m128, xmmV, xmm1","vpaddb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG FC /r","V","V","AVX","","w,r,r","","" +"VPADDB xmm1, {k}{z}, xmmV, xmm2/m128","VPADDB xmm2/m128, xmmV, {k}{z}, xmm1","vpaddb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG FC /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPADDB ymm1, ymmV, ymm2/m256","VPADDB ymm2/m256, ymmV, ymm1","vpaddb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG FC /r","V","V","AVX2","","w,r,r","","" +"VPADDB ymm1, {k}{z}, ymmV, ymm2/m256","VPADDB ymm2/m256, ymmV, {k}{z}, ymm1","vpaddb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG FC /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPADDB zmm1, {k}{z}, zmmV, zmm2/m512","VPADDB zmm2/m512, zmmV, {k}{z}, zmm1","vpaddb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG FC /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPADDD xmm1, xmmV, xmm2/m128","VPADDD xmm2/m128, xmmV, xmm1","vpaddd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG FE /r","V","V","AVX","","w,r,r","","" +"VPADDD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPADDD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpaddd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 FE /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPADDD ymm1, ymmV, ymm2/m256","VPADDD ymm2/m256, ymmV, ymm1","vpaddd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG FE /r","V","V","AVX2","","w,r,r","","" +"VPADDD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPADDD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpaddd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 FE /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPADDD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPADDD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpaddd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 FE /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPADDQ xmm1, xmmV, xmm2/m128","VPADDQ xmm2/m128, xmmV, xmm1","vpaddq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG D4 /r","V","V","AVX","","w,r,r","","" +"VPADDQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPADDQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpaddq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 D4 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPADDQ ymm1, ymmV, ymm2/m256","VPADDQ ymm2/m256, ymmV, ymm1","vpaddq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG D4 /r","V","V","AVX2","","w,r,r","","" +"VPADDQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPADDQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpaddq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 D4 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPADDQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPADDQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpaddq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 D4 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPADDSB xmm1, xmmV, xmm2/m128","VPADDSB xmm2/m128, xmmV, xmm1","vpaddsb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG EC /r","V","V","AVX","","w,r,r","","" +"VPADDSB xmm1, {k}{z}, xmmV, xmm2/m128","VPADDSB xmm2/m128, xmmV, {k}{z}, xmm1","vpaddsb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG EC /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPADDSB ymm1, ymmV, ymm2/m256","VPADDSB ymm2/m256, ymmV, ymm1","vpaddsb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG EC /r","V","V","AVX2","","w,r,r","","" +"VPADDSB ymm1, {k}{z}, ymmV, ymm2/m256","VPADDSB ymm2/m256, ymmV, {k}{z}, ymm1","vpaddsb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG EC /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPADDSB zmm1, {k}{z}, zmmV, zmm2/m512","VPADDSB zmm2/m512, zmmV, {k}{z}, zmm1","vpaddsb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG EC /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPADDSW xmm1, xmmV, xmm2/m128","VPADDSW xmm2/m128, xmmV, xmm1","vpaddsw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG ED /r","V","V","AVX","","w,r,r","","" +"VPADDSW xmm1, {k}{z}, xmmV, xmm2/m128","VPADDSW xmm2/m128, xmmV, {k}{z}, xmm1","vpaddsw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG ED /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPADDSW ymm1, ymmV, ymm2/m256","VPADDSW ymm2/m256, ymmV, ymm1","vpaddsw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG ED /r","V","V","AVX2","","w,r,r","","" +"VPADDSW ymm1, {k}{z}, ymmV, ymm2/m256","VPADDSW ymm2/m256, ymmV, {k}{z}, ymm1","vpaddsw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG ED /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPADDSW zmm1, {k}{z}, zmmV, zmm2/m512","VPADDSW zmm2/m512, zmmV, {k}{z}, zmm1","vpaddsw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG ED /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPADDUSB xmm1, xmmV, xmm2/m128","VPADDUSB xmm2/m128, xmmV, xmm1","vpaddusb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG DC /r","V","V","AVX","","w,r,r","","" +"VPADDUSB xmm1, {k}{z}, xmmV, xmm2/m128","VPADDUSB xmm2/m128, xmmV, {k}{z}, xmm1","vpaddusb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG DC /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPADDUSB ymm1, ymmV, ymm2/m256","VPADDUSB ymm2/m256, ymmV, ymm1","vpaddusb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG DC /r","V","V","AVX2","","w,r,r","","" +"VPADDUSB ymm1, {k}{z}, ymmV, ymm2/m256","VPADDUSB ymm2/m256, ymmV, {k}{z}, ymm1","vpaddusb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG DC /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPADDUSB zmm1, {k}{z}, zmmV, zmm2/m512","VPADDUSB zmm2/m512, zmmV, {k}{z}, zmm1","vpaddusb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG DC /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPADDUSW xmm1, xmmV, xmm2/m128","VPADDUSW xmm2/m128, xmmV, xmm1","vpaddusw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG DD /r","V","V","AVX","","w,r,r","","" +"VPADDUSW xmm1, {k}{z}, xmmV, xmm2/m128","VPADDUSW xmm2/m128, xmmV, {k}{z}, xmm1","vpaddusw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG DD /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPADDUSW ymm1, ymmV, ymm2/m256","VPADDUSW ymm2/m256, ymmV, ymm1","vpaddusw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG DD /r","V","V","AVX2","","w,r,r","","" +"VPADDUSW ymm1, {k}{z}, ymmV, ymm2/m256","VPADDUSW ymm2/m256, ymmV, {k}{z}, ymm1","vpaddusw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG DD /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPADDUSW zmm1, {k}{z}, zmmV, zmm2/m512","VPADDUSW zmm2/m512, zmmV, {k}{z}, zmm1","vpaddusw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG DD /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPADDW xmm1, xmmV, xmm2/m128","VPADDW xmm2/m128, xmmV, xmm1","vpaddw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG FD /r","V","V","AVX","","w,r,r","","" +"VPADDW xmm1, {k}{z}, xmmV, xmm2/m128","VPADDW xmm2/m128, xmmV, {k}{z}, xmm1","vpaddw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG FD /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPADDW ymm1, ymmV, ymm2/m256","VPADDW ymm2/m256, ymmV, ymm1","vpaddw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG FD /r","V","V","AVX2","","w,r,r","","" +"VPADDW ymm1, {k}{z}, ymmV, ymm2/m256","VPADDW ymm2/m256, ymmV, {k}{z}, ymm1","vpaddw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG FD /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPADDW zmm1, {k}{z}, zmmV, zmm2/m512","VPADDW zmm2/m512, zmmV, {k}{z}, zmm1","vpaddw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG FD /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPALIGNR xmm1, xmmV, xmm2/m128, imm8u","VPALIGNR imm8u, xmm2/m128, xmmV, xmm1","vpalignr imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 0F /r ib","V","V","AVX","","w,r,r,r","","" +"VPALIGNR xmm1, {k}{z}, xmmV, xmm2/m128, imm8u","VPALIGNR imm8u, xmm2/m128, xmmV, {k}{z}, xmm1","vpalignr imm8u, xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.WIG 0F /r ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r,r","","" +"VPALIGNR ymm1, ymmV, ymm2/m256, imm8u","VPALIGNR imm8u, ymm2/m256, ymmV, ymm1","vpalignr imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.WIG 0F /r ib","V","V","AVX2","","w,r,r,r","","" +"VPALIGNR ymm1, {k}{z}, ymmV, ymm2/m256, imm8u","VPALIGNR imm8u, ymm2/m256, ymmV, {k}{z}, ymm1","vpalignr imm8u, ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.WIG 0F /r ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r,r","","" +"VPALIGNR zmm1, {k}{z}, zmmV, zmm2/m512, imm8u","VPALIGNR imm8u, zmm2/m512, zmmV, {k}{z}, zmm1","vpalignr imm8u, zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.WIG 0F /r ib","V","V","AVX512BW","scale64","w,r,r,r,r","","" +"VPAND xmm1, xmmV, xmm2/m128","VPAND xmm2/m128, xmmV, xmm1","vpand xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG DB /r","V","V","AVX","","w,r,r","","" +"VPAND ymm1, ymmV, ymm2/m256","VPAND ymm2/m256, ymmV, ymm1","vpand ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG DB /r","V","V","AVX2","","w,r,r","","" +"VPANDD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPANDD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpandd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 DB /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPANDD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPANDD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpandd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 DB /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPANDD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPANDD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpandd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 DB /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPANDN xmm1, xmmV, xmm2/m128","VPANDN xmm2/m128, xmmV, xmm1","vpandn xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG DF /r","V","V","AVX","","w,r,r","","" +"VPANDN ymm1, ymmV, ymm2/m256","VPANDN ymm2/m256, ymmV, ymm1","vpandn ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG DF /r","V","V","AVX2","","w,r,r","","" +"VPANDND xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPANDND xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpandnd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 DF /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPANDND ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPANDND ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpandnd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 DF /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPANDND zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPANDND zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpandnd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 DF /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPANDNQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPANDNQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpandnq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 DF /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPANDNQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPANDNQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpandnq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 DF /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPANDNQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPANDNQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpandnq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 DF /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPANDQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPANDQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpandq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 DB /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPANDQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPANDQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpandq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 DB /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPANDQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPANDQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpandq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 DB /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPAVGB xmm1, xmmV, xmm2/m128","VPAVGB xmm2/m128, xmmV, xmm1","vpavgb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG E0 /r","V","V","AVX","","w,r,r","","" +"VPAVGB xmm1, {k}{z}, xmmV, xmm2/m128","VPAVGB xmm2/m128, xmmV, {k}{z}, xmm1","vpavgb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG E0 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPAVGB ymm1, ymmV, ymm2/m256","VPAVGB ymm2/m256, ymmV, ymm1","vpavgb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG E0 /r","V","V","AVX2","","w,r,r","","" +"VPAVGB ymm1, {k}{z}, ymmV, ymm2/m256","VPAVGB ymm2/m256, ymmV, {k}{z}, ymm1","vpavgb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG E0 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPAVGB zmm1, {k}{z}, zmmV, zmm2/m512","VPAVGB zmm2/m512, zmmV, {k}{z}, zmm1","vpavgb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG E0 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPAVGW xmm1, xmmV, xmm2/m128","VPAVGW xmm2/m128, xmmV, xmm1","vpavgw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG E3 /r","V","V","AVX","","w,r,r","","" +"VPAVGW xmm1, {k}{z}, xmmV, xmm2/m128","VPAVGW xmm2/m128, xmmV, {k}{z}, xmm1","vpavgw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG E3 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPAVGW ymm1, ymmV, ymm2/m256","VPAVGW ymm2/m256, ymmV, ymm1","vpavgw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG E3 /r","V","V","AVX2","","w,r,r","","" +"VPAVGW ymm1, {k}{z}, ymmV, ymm2/m256","VPAVGW ymm2/m256, ymmV, {k}{z}, ymm1","vpavgw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG E3 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPAVGW zmm1, {k}{z}, zmmV, zmm2/m512","VPAVGW zmm2/m512, zmmV, {k}{z}, zmm1","vpavgw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG E3 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPBLENDD xmm1, xmmV, xmm2/m128, imm8u","VPBLENDD imm8u, xmm2/m128, xmmV, xmm1","vpblendd imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 02 /r ib","V","V","AVX2","","w,r,r,r","","" +"VPBLENDD ymm1, ymmV, ymm2/m256, imm8u","VPBLENDD imm8u, ymm2/m256, ymmV, ymm1","vpblendd imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 02 /r ib","V","V","AVX2","","w,r,r,r","","" +"VPBLENDMB xmm1, {k}{z}, xmmV, xmm2/m128","VPBLENDMB xmm2/m128, xmmV, {k}{z}, xmm1","vpblendmb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 66 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPBLENDMB ymm1, {k}{z}, ymmV, ymm2/m256","VPBLENDMB ymm2/m256, ymmV, {k}{z}, ymm1","vpblendmb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 66 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPBLENDMB zmm1, {k}{z}, zmmV, zmm2/m512","VPBLENDMB zmm2/m512, zmmV, {k}{z}, zmm1","vpblendmb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 66 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPBLENDMD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPBLENDMD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpblendmd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 64 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPBLENDMD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPBLENDMD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpblendmd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 64 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPBLENDMD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPBLENDMD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpblendmd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 64 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPBLENDMQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPBLENDMQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpblendmq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 64 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPBLENDMQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPBLENDMQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpblendmq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 64 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPBLENDMQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPBLENDMQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpblendmq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 64 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPBLENDMW xmm1, {k}{z}, xmmV, xmm2/m128","VPBLENDMW xmm2/m128, xmmV, {k}{z}, xmm1","vpblendmw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 66 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPBLENDMW ymm1, {k}{z}, ymmV, ymm2/m256","VPBLENDMW ymm2/m256, ymmV, {k}{z}, ymm1","vpblendmw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 66 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPBLENDMW zmm1, {k}{z}, zmmV, zmm2/m512","VPBLENDMW zmm2/m512, zmmV, {k}{z}, zmm1","vpblendmw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 66 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPBLENDVB xmm1, xmmV, xmm2/m128, xmmIH","VPBLENDVB xmmIH, xmm2/m128, xmmV, xmm1","vpblendvb xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 4C /r /is4","V","V","AVX","","w,r,r,r","","" +"VPBLENDVB ymm1, ymmV, ymm2/m256, ymmIH","VPBLENDVB ymmIH, ymm2/m256, ymmV, ymm1","vpblendvb ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 4C /r /is4","V","V","AVX2","","w,r,r,r","","" +"VPBLENDW xmm1, xmmV, xmm2/m128, imm8u","VPBLENDW imm8u, xmm2/m128, xmmV, xmm1","vpblendw imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 0E /r ib","V","V","AVX","","w,r,r,r","","" +"VPBLENDW ymm1, ymmV, ymm2/m256, imm8u","VPBLENDW imm8u, ymm2/m256, ymmV, ymm1","vpblendw imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.WIG 0E /r ib","V","V","AVX2","","w,r,r,r","","" +"VPBROADCASTB xmm1, {k}{z}, rmr32","VPBROADCASTB rmr32, {k}{z}, xmm1","vpbroadcastb rmr32, {k}{z}, xmm1","EVEX.128.66.0F38.W0 7A /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r,r","","" +"VPBROADCASTB ymm1, {k}{z}, rmr32","VPBROADCASTB rmr32, {k}{z}, ymm1","vpbroadcastb rmr32, {k}{z}, ymm1","EVEX.256.66.0F38.W0 7A /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r,r","","" +"VPBROADCASTB zmm1, {k}{z}, rmr32","VPBROADCASTB rmr32, {k}{z}, zmm1","vpbroadcastb rmr32, {k}{z}, zmm1","EVEX.512.66.0F38.W0 7A /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"VPBROADCASTB xmm1, xmm2/m8","VPBROADCASTB xmm2/m8, xmm1","vpbroadcastb xmm2/m8, xmm1","VEX.128.66.0F38.W0 78 /r","V","V","AVX2","","w,r","","" +"VPBROADCASTB ymm1, xmm2/m8","VPBROADCASTB xmm2/m8, ymm1","vpbroadcastb xmm2/m8, ymm1","VEX.256.66.0F38.W0 78 /r","V","V","AVX2","","w,r","","" +"VPBROADCASTB xmm1, {k}{z}, xmm2/m8","VPBROADCASTB xmm2/m8, {k}{z}, xmm1","vpbroadcastb xmm2/m8, {k}{z}, xmm1","EVEX.128.66.0F38.W0 78 /r","V","V","AVX512BW+AVX512VL","scale1","w,r,r","","" +"VPBROADCASTB ymm1, {k}{z}, xmm2/m8","VPBROADCASTB xmm2/m8, {k}{z}, ymm1","vpbroadcastb xmm2/m8, {k}{z}, ymm1","EVEX.256.66.0F38.W0 78 /r","V","V","AVX512BW+AVX512VL","scale1","w,r,r","","" +"VPBROADCASTB zmm1, {k}{z}, xmm2/m8","VPBROADCASTB xmm2/m8, {k}{z}, zmm1","vpbroadcastb xmm2/m8, {k}{z}, zmm1","EVEX.512.66.0F38.W0 78 /r","V","V","AVX512BW","scale1","w,r,r","","" +"VPBROADCASTD xmm1, {k}{z}, rmr32","VPBROADCASTD rmr32, {k}{z}, xmm1","vpbroadcastd rmr32, {k}{z}, xmm1","EVEX.128.66.0F38.W0 7C /r","V","V","AVX512F+AVX512VL","modrm_regonly","w,r,r","","" +"VPBROADCASTD ymm1, {k}{z}, rmr32","VPBROADCASTD rmr32, {k}{z}, ymm1","vpbroadcastd rmr32, {k}{z}, ymm1","EVEX.256.66.0F38.W0 7C /r","V","V","AVX512F+AVX512VL","modrm_regonly","w,r,r","","" +"VPBROADCASTD zmm1, {k}{z}, rmr32","VPBROADCASTD rmr32, {k}{z}, zmm1","vpbroadcastd rmr32, {k}{z}, zmm1","EVEX.512.66.0F38.W0 7C /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VPBROADCASTD xmm1, xmm2/m32","VPBROADCASTD xmm2/m32, xmm1","vpbroadcastd xmm2/m32, xmm1","VEX.128.66.0F38.W0 58 /r","V","V","AVX2","","w,r","","" +"VPBROADCASTD ymm1, xmm2/m32","VPBROADCASTD xmm2/m32, ymm1","vpbroadcastd xmm2/m32, ymm1","VEX.256.66.0F38.W0 58 /r","V","V","AVX2","","w,r","","" +"VPBROADCASTD xmm1, {k}{z}, xmm2/m32","VPBROADCASTD xmm2/m32, {k}{z}, xmm1","vpbroadcastd xmm2/m32, {k}{z}, xmm1","EVEX.128.66.0F38.W0 58 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPBROADCASTD ymm1, {k}{z}, xmm2/m32","VPBROADCASTD xmm2/m32, {k}{z}, ymm1","vpbroadcastd xmm2/m32, {k}{z}, ymm1","EVEX.256.66.0F38.W0 58 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPBROADCASTD zmm1, {k}{z}, xmm2/m32","VPBROADCASTD xmm2/m32, {k}{z}, zmm1","vpbroadcastd xmm2/m32, {k}{z}, zmm1","EVEX.512.66.0F38.W0 58 /r","V","V","AVX512F","scale4","w,r,r","","" +"VPBROADCASTMB2Q xmm1, k2","VPBROADCASTMB2Q k2, xmm1","vpbroadcastmb2q k2, xmm1","EVEX.128.F3.0F38.W1 2A /r","V","V","AVX512CD+AVX512VL","modrm_regonly","w,r","","" +"VPBROADCASTMB2Q ymm1, k2","VPBROADCASTMB2Q k2, ymm1","vpbroadcastmb2q k2, ymm1","EVEX.256.F3.0F38.W1 2A /r","V","V","AVX512CD+AVX512VL","modrm_regonly","w,r","","" +"VPBROADCASTMB2Q zmm1, k2","VPBROADCASTMB2Q k2, zmm1","vpbroadcastmb2q k2, zmm1","EVEX.512.F3.0F38.W1 2A /r","V","V","AVX512CD","modrm_regonly","w,r","","" +"VPBROADCASTMW2D xmm1, k2","VPBROADCASTMW2D k2, xmm1","vpbroadcastmw2d k2, xmm1","EVEX.128.F3.0F38.W0 3A /r","V","V","AVX512CD+AVX512VL","modrm_regonly","w,r","","" +"VPBROADCASTMW2D ymm1, k2","VPBROADCASTMW2D k2, ymm1","vpbroadcastmw2d k2, ymm1","EVEX.256.F3.0F38.W0 3A /r","V","V","AVX512CD+AVX512VL","modrm_regonly","w,r","","" +"VPBROADCASTMW2D zmm1, k2","VPBROADCASTMW2D k2, zmm1","vpbroadcastmw2d k2, zmm1","EVEX.512.F3.0F38.W0 3A /r","V","V","AVX512CD","modrm_regonly","w,r","","" +"VPBROADCASTQ xmm1, {k}{z}, rmr64","VPBROADCASTQ rmr64, {k}{z}, xmm1","vpbroadcastq rmr64, {k}{z}, xmm1","EVEX.128.66.0F38.W1 7C /r","N.S.","V","AVX512F+AVX512VL","modrm_regonly","w,r,r","","" +"VPBROADCASTQ ymm1, {k}{z}, rmr64","VPBROADCASTQ rmr64, {k}{z}, ymm1","vpbroadcastq rmr64, {k}{z}, ymm1","EVEX.256.66.0F38.W1 7C /r","N.S.","V","AVX512F+AVX512VL","modrm_regonly","w,r,r","","" +"VPBROADCASTQ zmm1, {k}{z}, rmr64","VPBROADCASTQ rmr64, {k}{z}, zmm1","vpbroadcastq rmr64, {k}{z}, zmm1","EVEX.512.66.0F38.W1 7C /r","N.S.","V","AVX512F","modrm_regonly","w,r,r","","" +"VPBROADCASTQ xmm1, xmm2/m64","VPBROADCASTQ xmm2/m64, xmm1","vpbroadcastq xmm2/m64, xmm1","VEX.128.66.0F38.W0 59 /r","V","V","AVX2","","w,r","","" +"VPBROADCASTQ ymm1, xmm2/m64","VPBROADCASTQ xmm2/m64, ymm1","vpbroadcastq xmm2/m64, ymm1","VEX.256.66.0F38.W0 59 /r","V","V","AVX2","","w,r","","" +"VPBROADCASTQ xmm1, {k}{z}, xmm2/m64","VPBROADCASTQ xmm2/m64, {k}{z}, xmm1","vpbroadcastq xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.W1 59 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPBROADCASTQ ymm1, {k}{z}, xmm2/m64","VPBROADCASTQ xmm2/m64, {k}{z}, ymm1","vpbroadcastq xmm2/m64, {k}{z}, ymm1","EVEX.256.66.0F38.W1 59 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPBROADCASTQ zmm1, {k}{z}, xmm2/m64","VPBROADCASTQ xmm2/m64, {k}{z}, zmm1","vpbroadcastq xmm2/m64, {k}{z}, zmm1","EVEX.512.66.0F38.W1 59 /r","V","V","AVX512F","scale8","w,r,r","","" +"VPBROADCASTW xmm1, {k}{z}, rmr32","VPBROADCASTW rmr32, {k}{z}, xmm1","vpbroadcastw rmr32, {k}{z}, xmm1","EVEX.128.66.0F38.W0 7B /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r,r","","" +"VPBROADCASTW ymm1, {k}{z}, rmr32","VPBROADCASTW rmr32, {k}{z}, ymm1","vpbroadcastw rmr32, {k}{z}, ymm1","EVEX.256.66.0F38.W0 7B /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r,r","","" +"VPBROADCASTW zmm1, {k}{z}, rmr32","VPBROADCASTW rmr32, {k}{z}, zmm1","vpbroadcastw rmr32, {k}{z}, zmm1","EVEX.512.66.0F38.W0 7B /r","V","V","AVX512BW","modrm_regonly","w,r,r","","" +"VPBROADCASTW xmm1, xmm2/m16","VPBROADCASTW xmm2/m16, xmm1","vpbroadcastw xmm2/m16, xmm1","VEX.128.66.0F38.W0 79 /r","V","V","AVX2","","w,r","","" +"VPBROADCASTW ymm1, xmm2/m16","VPBROADCASTW xmm2/m16, ymm1","vpbroadcastw xmm2/m16, ymm1","VEX.256.66.0F38.W0 79 /r","V","V","AVX2","","w,r","","" +"VPBROADCASTW xmm1, {k}{z}, xmm2/m16","VPBROADCASTW xmm2/m16, {k}{z}, xmm1","vpbroadcastw xmm2/m16, {k}{z}, xmm1","EVEX.128.66.0F38.W0 79 /r","V","V","AVX512BW+AVX512VL","scale2","w,r,r","","" +"VPBROADCASTW ymm1, {k}{z}, xmm2/m16","VPBROADCASTW xmm2/m16, {k}{z}, ymm1","vpbroadcastw xmm2/m16, {k}{z}, ymm1","EVEX.256.66.0F38.W0 79 /r","V","V","AVX512BW+AVX512VL","scale2","w,r,r","","" +"VPBROADCASTW zmm1, {k}{z}, xmm2/m16","VPBROADCASTW xmm2/m16, {k}{z}, zmm1","vpbroadcastw xmm2/m16, {k}{z}, zmm1","EVEX.512.66.0F38.W0 79 /r","V","V","AVX512BW","scale2","w,r,r","","" +"VPCLMULQDQ xmm1, xmmV, xmm2/m128, imm8u","VPCLMULQDQ imm8u, xmm2/m128, xmmV, xmm1","vpclmulqdq imm8u, xmm2/m128, xmmV, xmm1","EVEX.NDS.128.66.0F3A.WIG 44 /r ib","V","V","VPCLMULQDQ+AVX512VL","scale16","w,r,r,r","","" +"VPCLMULQDQ xmm1, xmmV, xmm2/m128, imm8u","VPCLMULQDQ imm8u, xmm2/m128, xmmV, xmm1","vpclmulqdq imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 44 /r ib","V","V","PCLMULQDQ+AVX","","w,r,r,r","","" +"VPCLMULQDQ ymm1, ymmV, ymm2/m256, imm8u","VPCLMULQDQ imm8u, ymm2/m256, ymmV, ymm1","vpclmulqdq imm8u, ymm2/m256, ymmV, ymm1","EVEX.NDS.256.66.0F3A.WIG 44 /r ib","V","V","VPCLMULQDQ+AVX512VL","scale32","w,r,r,r","","" +"VPCLMULQDQ ymm1, ymmV, ymm2/m256, imm8u","VPCLMULQDQ imm8u, ymm2/m256, ymmV, ymm1","vpclmulqdq imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.WIG 44 /r ib","V","V","VPCLMULQDQ","","w,r,r,r","","" +"VPCLMULQDQ zmm1, zmmV, zmm2/m512, imm8u","VPCLMULQDQ imm8u, zmm2/m512, zmmV, zmm1","vpclmulqdq imm8u, zmm2/m512, zmmV, zmm1","EVEX.NDS.512.66.0F3A.WIG 44 /r ib","V","V","VPCLMULQDQ+AVX512F","scale64","w,r,r,r","","" +"VPCMOV xmm1, xmmV, xmmIH, xmm2/m128","VPCMOV xmm2/m128, xmmIH, xmmV, xmm1","vpcmov xmm2/m128, xmmIH, xmmV, xmm1","XOP.NDS.128.08.W1 A2 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPCMOV xmm1, xmmV, xmm2/m128, xmmIH","VPCMOV xmmIH, xmm2/m128, xmmV, xmm1","vpcmov xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 A2 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPCMOV ymm1, ymmV, ymmIH, ymm2/m256","VPCMOV ymm2/m256, ymmIH, ymmV, ymm1","vpcmov ymm2/m256, ymmIH, ymmV, ymm1","XOP.NDS.256.08.W1 A2 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPCMOV ymm1, ymmV, ymm2/m256, ymmIH","VPCMOV ymmIH, ymm2/m256, ymmV, ymm1","vpcmov ymmIH, ymm2/m256, ymmV, ymm1","XOP.NDS.256.08.W0 A2 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPCMPB k1, {k}, xmmV, xmm2/m128, imm8u","VPCMPB imm8u, xmm2/m128, xmmV, {k}, k1","vpcmpb imm8u, xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F3A.W0 3F /r ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r,r","","" +"VPCMPB k1, {k}, ymmV, ymm2/m256, imm8u","VPCMPB imm8u, ymm2/m256, ymmV, {k}, k1","vpcmpb imm8u, ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F3A.W0 3F /r ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r,r","","" +"VPCMPB k1, {k}, zmmV, zmm2/m512, imm8u","VPCMPB imm8u, zmm2/m512, zmmV, {k}, k1","vpcmpb imm8u, zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F3A.W0 3F /r ib","V","V","AVX512BW","scale64","w,r,r,r,r","","" +"VPCMPD k1, {k}, xmmV, xmm2/m128/m32bcst, imm8u","VPCMPD imm8u, xmm2/m128/m32bcst, xmmV, {k}, k1","vpcmpd imm8u, xmm2/m128/m32bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F3A.W0 1F /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r,r","","" +"VPCMPD k1, {k}, ymmV, ymm2/m256/m32bcst, imm8u","VPCMPD imm8u, ymm2/m256/m32bcst, ymmV, {k}, k1","vpcmpd imm8u, ymm2/m256/m32bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F3A.W0 1F /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VPCMPD k1, {k}, zmmV, zmm2/m512/m32bcst, imm8u","VPCMPD imm8u, zmm2/m512/m32bcst, zmmV, {k}, k1","vpcmpd imm8u, zmm2/m512/m32bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F3A.W0 1F /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r,r","","" +"VPCMPEQB xmm1, xmmV, xmm2/m128","VPCMPEQB xmm2/m128, xmmV, xmm1","vpcmpeqb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 74 /r","V","V","AVX","","w,r,r","","" +"VPCMPEQB k1, {k}, xmmV, xmm2/m128","VPCMPEQB xmm2/m128, xmmV, {k}, k1","vpcmpeqb xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F.WIG 74 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPCMPEQB ymm1, ymmV, ymm2/m256","VPCMPEQB ymm2/m256, ymmV, ymm1","vpcmpeqb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 74 /r","V","V","AVX2","","w,r,r","","" +"VPCMPEQB k1, {k}, ymmV, ymm2/m256","VPCMPEQB ymm2/m256, ymmV, {k}, k1","vpcmpeqb ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F.WIG 74 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPCMPEQB k1, {k}, zmmV, zmm2/m512","VPCMPEQB zmm2/m512, zmmV, {k}, k1","vpcmpeqb zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F.WIG 74 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPCMPEQD xmm1, xmmV, xmm2/m128","VPCMPEQD xmm2/m128, xmmV, xmm1","vpcmpeqd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 76 /r","V","V","AVX","","w,r,r","","" +"VPCMPEQD k1, {k}, xmmV, xmm2/m128/m32bcst","VPCMPEQD xmm2/m128/m32bcst, xmmV, {k}, k1","vpcmpeqd xmm2/m128/m32bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F.W0 76 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPCMPEQD ymm1, ymmV, ymm2/m256","VPCMPEQD ymm2/m256, ymmV, ymm1","vpcmpeqd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 76 /r","V","V","AVX2","","w,r,r","","" +"VPCMPEQD k1, {k}, ymmV, ymm2/m256/m32bcst","VPCMPEQD ymm2/m256/m32bcst, ymmV, {k}, k1","vpcmpeqd ymm2/m256/m32bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F.W0 76 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPCMPEQD k1, {k}, zmmV, zmm2/m512/m32bcst","VPCMPEQD zmm2/m512/m32bcst, zmmV, {k}, k1","vpcmpeqd zmm2/m512/m32bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F.W0 76 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPCMPEQQ xmm1, xmmV, xmm2/m128","VPCMPEQQ xmm2/m128, xmmV, xmm1","vpcmpeqq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 29 /r","V","V","AVX","","w,r,r","","" +"VPCMPEQQ k1, {k}, xmmV, xmm2/m128/m64bcst","VPCMPEQQ xmm2/m128/m64bcst, xmmV, {k}, k1","vpcmpeqq xmm2/m128/m64bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F38.W1 29 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPCMPEQQ ymm1, ymmV, ymm2/m256","VPCMPEQQ ymm2/m256, ymmV, ymm1","vpcmpeqq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 29 /r","V","V","AVX2","","w,r,r","","" +"VPCMPEQQ k1, {k}, ymmV, ymm2/m256/m64bcst","VPCMPEQQ ymm2/m256/m64bcst, ymmV, {k}, k1","vpcmpeqq ymm2/m256/m64bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F38.W1 29 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPCMPEQQ k1, {k}, zmmV, zmm2/m512/m64bcst","VPCMPEQQ zmm2/m512/m64bcst, zmmV, {k}, k1","vpcmpeqq zmm2/m512/m64bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F38.W1 29 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPCMPEQW xmm1, xmmV, xmm2/m128","VPCMPEQW xmm2/m128, xmmV, xmm1","vpcmpeqw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 75 /r","V","V","AVX","","w,r,r","","" +"VPCMPEQW k1, {k}, xmmV, xmm2/m128","VPCMPEQW xmm2/m128, xmmV, {k}, k1","vpcmpeqw xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F.WIG 75 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPCMPEQW ymm1, ymmV, ymm2/m256","VPCMPEQW ymm2/m256, ymmV, ymm1","vpcmpeqw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 75 /r","V","V","AVX2","","w,r,r","","" +"VPCMPEQW k1, {k}, ymmV, ymm2/m256","VPCMPEQW ymm2/m256, ymmV, {k}, k1","vpcmpeqw ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F.WIG 75 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPCMPEQW k1, {k}, zmmV, zmm2/m512","VPCMPEQW zmm2/m512, zmmV, {k}, k1","vpcmpeqw zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F.WIG 75 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPCMPESTRI xmm1, xmm2/m128, imm8u","VPCMPESTRI imm8u, xmm2/m128, xmm1","vpcmpestri imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.WIG 61 /r ib","V","V","AVX","","r,r,r","","" +"VPCMPESTRM xmm1, xmm2/m128, imm8u","VPCMPESTRM imm8u, xmm2/m128, xmm1","vpcmpestrm imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.WIG 60 /r ib","V","V","AVX","","r,r,r","","" +"VPCMPGTB xmm1, xmmV, xmm2/m128","VPCMPGTB xmm2/m128, xmmV, xmm1","vpcmpgtb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 64 /r","V","V","AVX","","w,r,r","","" +"VPCMPGTB k1, {k}, xmmV, xmm2/m128","VPCMPGTB xmm2/m128, xmmV, {k}, k1","vpcmpgtb xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F.WIG 64 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPCMPGTB ymm1, ymmV, ymm2/m256","VPCMPGTB ymm2/m256, ymmV, ymm1","vpcmpgtb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 64 /r","V","V","AVX2","","w,r,r","","" +"VPCMPGTB k1, {k}, ymmV, ymm2/m256","VPCMPGTB ymm2/m256, ymmV, {k}, k1","vpcmpgtb ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F.WIG 64 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPCMPGTB k1, {k}, zmmV, zmm2/m512","VPCMPGTB zmm2/m512, zmmV, {k}, k1","vpcmpgtb zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F.WIG 64 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPCMPGTD xmm1, xmmV, xmm2/m128","VPCMPGTD xmm2/m128, xmmV, xmm1","vpcmpgtd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 66 /r","V","V","AVX","","w,r,r","","" +"VPCMPGTD k1, {k}, xmmV, xmm2/m128/m32bcst","VPCMPGTD xmm2/m128/m32bcst, xmmV, {k}, k1","vpcmpgtd xmm2/m128/m32bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F.W0 66 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPCMPGTD ymm1, ymmV, ymm2/m256","VPCMPGTD ymm2/m256, ymmV, ymm1","vpcmpgtd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 66 /r","V","V","AVX2","","w,r,r","","" +"VPCMPGTD k1, {k}, ymmV, ymm2/m256/m32bcst","VPCMPGTD ymm2/m256/m32bcst, ymmV, {k}, k1","vpcmpgtd ymm2/m256/m32bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F.W0 66 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPCMPGTD k1, {k}, zmmV, zmm2/m512/m32bcst","VPCMPGTD zmm2/m512/m32bcst, zmmV, {k}, k1","vpcmpgtd zmm2/m512/m32bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F.W0 66 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPCMPGTQ xmm1, xmmV, xmm2/m128","VPCMPGTQ xmm2/m128, xmmV, xmm1","vpcmpgtq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 37 /r","V","V","AVX","","w,r,r","","" +"VPCMPGTQ k1, {k}, xmmV, xmm2/m128/m64bcst","VPCMPGTQ xmm2/m128/m64bcst, xmmV, {k}, k1","vpcmpgtq xmm2/m128/m64bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F38.W1 37 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPCMPGTQ ymm1, ymmV, ymm2/m256","VPCMPGTQ ymm2/m256, ymmV, ymm1","vpcmpgtq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 37 /r","V","V","AVX2","","w,r,r","","" +"VPCMPGTQ k1, {k}, ymmV, ymm2/m256/m64bcst","VPCMPGTQ ymm2/m256/m64bcst, ymmV, {k}, k1","vpcmpgtq ymm2/m256/m64bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F38.W1 37 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPCMPGTQ k1, {k}, zmmV, zmm2/m512/m64bcst","VPCMPGTQ zmm2/m512/m64bcst, zmmV, {k}, k1","vpcmpgtq zmm2/m512/m64bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F38.W1 37 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPCMPGTW xmm1, xmmV, xmm2/m128","VPCMPGTW xmm2/m128, xmmV, xmm1","vpcmpgtw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 65 /r","V","V","AVX","","w,r,r","","" +"VPCMPGTW k1, {k}, xmmV, xmm2/m128","VPCMPGTW xmm2/m128, xmmV, {k}, k1","vpcmpgtw xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F.WIG 65 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPCMPGTW ymm1, ymmV, ymm2/m256","VPCMPGTW ymm2/m256, ymmV, ymm1","vpcmpgtw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 65 /r","V","V","AVX2","","w,r,r","","" +"VPCMPGTW k1, {k}, ymmV, ymm2/m256","VPCMPGTW ymm2/m256, ymmV, {k}, k1","vpcmpgtw ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F.WIG 65 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPCMPGTW k1, {k}, zmmV, zmm2/m512","VPCMPGTW zmm2/m512, zmmV, {k}, k1","vpcmpgtw zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F.WIG 65 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPCMPISTRI xmm1, xmm2/m128, imm8u","VPCMPISTRI imm8u, xmm2/m128, xmm1","vpcmpistri imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.WIG 63 /r ib","V","V","AVX","","r,r,r","","" +"VPCMPISTRM xmm1, xmm2/m128, imm8u","VPCMPISTRM imm8u, xmm2/m128, xmm1","vpcmpistrm imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.WIG 62 /r ib","V","V","AVX","","r,r,r","","" +"VPCMPQ k1, {k}, xmmV, xmm2/m128/m64bcst, imm8u","VPCMPQ imm8u, xmm2/m128/m64bcst, xmmV, {k}, k1","vpcmpq imm8u, xmm2/m128/m64bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F3A.W1 1F /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VPCMPQ k1, {k}, ymmV, ymm2/m256/m64bcst, imm8u","VPCMPQ imm8u, ymm2/m256/m64bcst, ymmV, {k}, k1","vpcmpq imm8u, ymm2/m256/m64bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F3A.W1 1F /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VPCMPQ k1, {k}, zmmV, zmm2/m512/m64bcst, imm8u","VPCMPQ imm8u, zmm2/m512/m64bcst, zmmV, {k}, k1","vpcmpq imm8u, zmm2/m512/m64bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F3A.W1 1F /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VPCMPUB k1, {k}, xmmV, xmm2/m128, imm8u","VPCMPUB imm8u, xmm2/m128, xmmV, {k}, k1","vpcmpub imm8u, xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F3A.W0 3E /r ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r,r","","" +"VPCMPUB k1, {k}, ymmV, ymm2/m256, imm8u","VPCMPUB imm8u, ymm2/m256, ymmV, {k}, k1","vpcmpub imm8u, ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F3A.W0 3E /r ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r,r","","" +"VPCMPUB k1, {k}, zmmV, zmm2/m512, imm8u","VPCMPUB imm8u, zmm2/m512, zmmV, {k}, k1","vpcmpub imm8u, zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F3A.W0 3E /r ib","V","V","AVX512BW","scale64","w,r,r,r,r","","" +"VPCMPUD k1, {k}, xmmV, xmm2/m128/m32bcst, imm8u","VPCMPUD imm8u, xmm2/m128/m32bcst, xmmV, {k}, k1","vpcmpud imm8u, xmm2/m128/m32bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F3A.W0 1E /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r,r","","" +"VPCMPUD k1, {k}, ymmV, ymm2/m256/m32bcst, imm8u","VPCMPUD imm8u, ymm2/m256/m32bcst, ymmV, {k}, k1","vpcmpud imm8u, ymm2/m256/m32bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F3A.W0 1E /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VPCMPUD k1, {k}, zmmV, zmm2/m512/m32bcst, imm8u","VPCMPUD imm8u, zmm2/m512/m32bcst, zmmV, {k}, k1","vpcmpud imm8u, zmm2/m512/m32bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F3A.W0 1E /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r,r","","" +"VPCMPUQ k1, {k}, xmmV, xmm2/m128/m64bcst, imm8u","VPCMPUQ imm8u, xmm2/m128/m64bcst, xmmV, {k}, k1","vpcmpuq imm8u, xmm2/m128/m64bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F3A.W1 1E /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VPCMPUQ k1, {k}, ymmV, ymm2/m256/m64bcst, imm8u","VPCMPUQ imm8u, ymm2/m256/m64bcst, ymmV, {k}, k1","vpcmpuq imm8u, ymm2/m256/m64bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F3A.W1 1E /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VPCMPUQ k1, {k}, zmmV, zmm2/m512/m64bcst, imm8u","VPCMPUQ imm8u, zmm2/m512/m64bcst, zmmV, {k}, k1","vpcmpuq imm8u, zmm2/m512/m64bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F3A.W1 1E /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VPCMPUW k1, {k}, xmmV, xmm2/m128, imm8u","VPCMPUW imm8u, xmm2/m128, xmmV, {k}, k1","vpcmpuw imm8u, xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F3A.W1 3E /r ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r,r","","" +"VPCMPUW k1, {k}, ymmV, ymm2/m256, imm8u","VPCMPUW imm8u, ymm2/m256, ymmV, {k}, k1","vpcmpuw imm8u, ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F3A.W1 3E /r ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r,r","","" +"VPCMPUW k1, {k}, zmmV, zmm2/m512, imm8u","VPCMPUW imm8u, zmm2/m512, zmmV, {k}, k1","vpcmpuw imm8u, zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F3A.W1 3E /r ib","V","V","AVX512BW","scale64","w,r,r,r,r","","" +"VPCMPW k1, {k}, xmmV, xmm2/m128, imm8u","VPCMPW imm8u, xmm2/m128, xmmV, {k}, k1","vpcmpw imm8u, xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F3A.W1 3F /r ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r,r","","" +"VPCMPW k1, {k}, ymmV, ymm2/m256, imm8u","VPCMPW imm8u, ymm2/m256, ymmV, {k}, k1","vpcmpw imm8u, ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F3A.W1 3F /r ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r,r","","" +"VPCMPW k1, {k}, zmmV, zmm2/m512, imm8u","VPCMPW imm8u, zmm2/m512, zmmV, {k}, k1","vpcmpw imm8u, zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F3A.W1 3F /r ib","V","V","AVX512BW","scale64","w,r,r,r,r","","" +"VPCOMB xmm1, xmmV, xmm2/m128, imm8u","VPCOMB imm8u, xmm2/m128, xmmV, xmm1","vpcomb imm8u, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 CC /r ib","V","V","XOP","amd","w,r,r,r","","" +"VPCOMD xmm1, xmmV, xmm2/m128, imm8u","VPCOMD imm8u, xmm2/m128, xmmV, xmm1","vpcomd imm8u, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 CE /r ib","V","V","XOP","amd","w,r,r,r","","" +"VPCOMPRESSB xmm2/m128, {k}{z}, xmm1","VPCOMPRESSB xmm1, {k}{z}, xmm2/m128","vpcompressb xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F38.W0 63 /r","V","V","AVX512_VBMI2+AVX512VL","scale1","w,r,r","","" +"VPCOMPRESSB ymm2/m256, {k}{z}, ymm1","VPCOMPRESSB ymm1, {k}{z}, ymm2/m256","vpcompressb ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F38.W0 63 /r","V","V","AVX512_VBMI2+AVX512VL","scale1","w,r,r","","" +"VPCOMPRESSB zmm2/m512, {k}{z}, zmm1","VPCOMPRESSB zmm1, {k}{z}, zmm2/m512","vpcompressb zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F38.W0 63 /r","V","V","AVX512_VBMI2","scale1","w,r,r","","" +"VPCOMPRESSD xmm2/m128, {k}{z}, xmm1","VPCOMPRESSD xmm1, {k}{z}, xmm2/m128","vpcompressd xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F38.W0 8B /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPCOMPRESSD ymm2/m256, {k}{z}, ymm1","VPCOMPRESSD ymm1, {k}{z}, ymm2/m256","vpcompressd ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F38.W0 8B /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPCOMPRESSD zmm2/m512, {k}{z}, zmm1","VPCOMPRESSD zmm1, {k}{z}, zmm2/m512","vpcompressd zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F38.W0 8B /r","V","V","AVX512F","scale4","w,r,r","","" +"VPCOMPRESSQ xmm2/m128, {k}{z}, xmm1","VPCOMPRESSQ xmm1, {k}{z}, xmm2/m128","vpcompressq xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F38.W1 8B /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPCOMPRESSQ ymm2/m256, {k}{z}, ymm1","VPCOMPRESSQ ymm1, {k}{z}, ymm2/m256","vpcompressq ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F38.W1 8B /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPCOMPRESSQ zmm2/m512, {k}{z}, zmm1","VPCOMPRESSQ zmm1, {k}{z}, zmm2/m512","vpcompressq zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F38.W1 8B /r","V","V","AVX512F","scale8","w,r,r","","" +"VPCOMPRESSW xmm2/m128, {k}{z}, xmm1","VPCOMPRESSW xmm1, {k}{z}, xmm2/m128","vpcompressw xmm1, {k}{z}, xmm2/m128","EVEX.128.66.0F38.W1 63 /r","V","V","AVX512_VBMI2+AVX512VL","scale2","w,r,r","","" +"VPCOMPRESSW ymm2/m256, {k}{z}, ymm1","VPCOMPRESSW ymm1, {k}{z}, ymm2/m256","vpcompressw ymm1, {k}{z}, ymm2/m256","EVEX.256.66.0F38.W1 63 /r","V","V","AVX512_VBMI2+AVX512VL","scale2","w,r,r","","" +"VPCOMPRESSW zmm2/m512, {k}{z}, zmm1","VPCOMPRESSW zmm1, {k}{z}, zmm2/m512","vpcompressw zmm1, {k}{z}, zmm2/m512","EVEX.512.66.0F38.W1 63 /r","V","V","AVX512_VBMI2","scale2","w,r,r","","" +"VPCOMQ xmm1, xmmV, xmm2/m128, imm8u","VPCOMQ imm8u, xmm2/m128, xmmV, xmm1","vpcomq imm8u, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 CF /r ib","V","V","XOP","amd","w,r,r,r","","" +"VPCOMUB xmm1, xmmV, xmm2/m128, imm8u","VPCOMUB imm8u, xmm2/m128, xmmV, xmm1","vpcomub imm8u, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 EC /r ib","V","V","XOP","amd","w,r,r,r","","" +"VPCOMUD xmm1, xmmV, xmm2/m128, imm8u","VPCOMUD imm8u, xmm2/m128, xmmV, xmm1","vpcomud imm8u, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 EE /r ib","V","V","XOP","amd","w,r,r,r","","" +"VPCOMUQ xmm1, xmmV, xmm2/m128, imm8u","VPCOMUQ imm8u, xmm2/m128, xmmV, xmm1","vpcomuq imm8u, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 EF /r ib","V","V","XOP","amd","w,r,r,r","","" +"VPCOMUW xmm1, xmmV, xmm2/m128, imm8u","VPCOMUW imm8u, xmm2/m128, xmmV, xmm1","vpcomuw imm8u, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 ED /r ib","V","V","XOP","amd","w,r,r,r","","" +"VPCOMW xmm1, xmmV, xmm2/m128, imm8u","VPCOMW imm8u, xmm2/m128, xmmV, xmm1","vpcomw imm8u, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 CD /r ib","V","V","XOP","amd","w,r,r,r","","" +"VPCONFLICTD xmm1, {k}{z}, xmm2/m128/m32bcst","VPCONFLICTD xmm2/m128/m32bcst, {k}{z}, xmm1","vpconflictd xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W0 C4 /r","V","V","AVX512CD+AVX512VL","bscale4,scale16","w,r,r","","" +"VPCONFLICTD ymm1, {k}{z}, ymm2/m256/m32bcst","VPCONFLICTD ymm2/m256/m32bcst, {k}{z}, ymm1","vpconflictd ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W0 C4 /r","V","V","AVX512CD+AVX512VL","bscale4,scale32","w,r,r","","" +"VPCONFLICTD zmm1, {k}{z}, zmm2/m512/m32bcst","VPCONFLICTD zmm2/m512/m32bcst, {k}{z}, zmm1","vpconflictd zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 C4 /r","V","V","AVX512CD","bscale4,scale64","w,r,r","","" +"VPCONFLICTQ xmm1, {k}{z}, xmm2/m128/m64bcst","VPCONFLICTQ xmm2/m128/m64bcst, {k}{z}, xmm1","vpconflictq xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W1 C4 /r","V","V","AVX512CD+AVX512VL","bscale8,scale16","w,r,r","","" +"VPCONFLICTQ ymm1, {k}{z}, ymm2/m256/m64bcst","VPCONFLICTQ ymm2/m256/m64bcst, {k}{z}, ymm1","vpconflictq ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W1 C4 /r","V","V","AVX512CD+AVX512VL","bscale8,scale32","w,r,r","","" +"VPCONFLICTQ zmm1, {k}{z}, zmm2/m512/m64bcst","VPCONFLICTQ zmm2/m512/m64bcst, {k}{z}, zmm1","vpconflictq zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 C4 /r","V","V","AVX512CD","bscale8,scale64","w,r,r","","" +"VPDPBUSD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPDPBUSD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpdpbusd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 50 /r","V","V","AVX512_VNNI+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPDPBUSD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPDPBUSD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpdpbusd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 50 /r","V","V","AVX512_VNNI+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPDPBUSD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPDPBUSD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpdpbusd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 50 /r","V","V","AVX512_VNNI","bscale4,scale64","rw,r,r,r","","" +"VPDPBUSDS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPDPBUSDS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpdpbusds xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 51 /r","V","V","AVX512_VNNI+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPDPBUSDS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPDPBUSDS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpdpbusds ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 51 /r","V","V","AVX512_VNNI+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPDPBUSDS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPDPBUSDS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpdpbusds zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 51 /r","V","V","AVX512_VNNI","bscale4,scale64","rw,r,r,r","","" +"VPDPWSSD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPDPWSSD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpdpwssd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 52 /r","V","V","AVX512_VNNI+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPDPWSSD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPDPWSSD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpdpwssd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 52 /r","V","V","AVX512_VNNI+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPDPWSSD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPDPWSSD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpdpwssd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 52 /r","V","V","AVX512_VNNI","bscale4,scale64","rw,r,r,r","","" +"VPDPWSSDS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPDPWSSDS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpdpwssds xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 53 /r","V","V","AVX512_VNNI+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPDPWSSDS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPDPWSSDS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpdpwssds ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 53 /r","V","V","AVX512_VNNI+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPDPWSSDS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPDPWSSDS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpdpwssds zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 53 /r","V","V","AVX512_VNNI","bscale4,scale64","rw,r,r,r","","" +"VPERM2F128 ymm1, ymmV, ymm2/m256, imm8u","VPERM2F128 imm8u, ymm2/m256, ymmV, ymm1","vperm2f128 imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 06 /r ib","V","V","AVX","","w,r,r,r","","" +"VPERM2I128 ymm1, ymmV, ymm2/m256, imm8u","VPERM2I128 imm8u, ymm2/m256, ymmV, ymm1","vperm2i128 imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 46 /r ib","V","V","AVX2","","w,r,r,r","","" +"VPERMB xmm1, {k}{z}, xmmV, xmm2/m128","VPERMB xmm2/m128, xmmV, {k}{z}, xmm1","vpermb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 8D /r","V","V","AVX512_VBMI+AVX512VL","scale16","w,r,r,r","","" +"VPERMB ymm1, {k}{z}, ymmV, ymm2/m256","VPERMB ymm2/m256, ymmV, {k}{z}, ymm1","vpermb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 8D /r","V","V","AVX512_VBMI+AVX512VL","scale32","w,r,r,r","","" +"VPERMB zmm1, {k}{z}, zmmV, zmm2/m512","VPERMB zmm2/m512, zmmV, {k}{z}, zmm1","vpermb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 8D /r","V","V","AVX512_VBMI","scale64","w,r,r,r","","" +"VPERMD ymm1, ymmV, ymm2/m256","VPERMD ymm2/m256, ymmV, ymm1","vpermd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 36 /r","V","V","AVX2","","w,r,r","","" +"VPERMD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPERMD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpermd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 36 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPERMD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPERMD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpermd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 36 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPERMI2B xmm1, {k}{z}, xmmV, xmm2/m128","VPERMI2B xmm2/m128, xmmV, {k}{z}, xmm1","vpermi2b xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 75 /r","V","V","AVX512_VBMI+AVX512VL","scale16","rw,r,r,r","","" +"VPERMI2B ymm1, {k}{z}, ymmV, ymm2/m256","VPERMI2B ymm2/m256, ymmV, {k}{z}, ymm1","vpermi2b ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 75 /r","V","V","AVX512_VBMI+AVX512VL","scale32","rw,r,r,r","","" +"VPERMI2B zmm1, {k}{z}, zmmV, zmm2/m512","VPERMI2B zmm2/m512, zmmV, {k}{z}, zmm1","vpermi2b zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 75 /r","V","V","AVX512_VBMI","scale64","rw,r,r,r","","" +"VPERMI2D xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPERMI2D xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpermi2d xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 76 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPERMI2D ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPERMI2D ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpermi2d ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 76 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPERMI2D zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPERMI2D zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpermi2d zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 76 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VPERMI2PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPERMI2PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpermi2pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 77 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VPERMI2PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPERMI2PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpermi2pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 77 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VPERMI2PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPERMI2PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpermi2pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 77 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VPERMI2PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPERMI2PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpermi2ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 77 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPERMI2PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPERMI2PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpermi2ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 77 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPERMI2PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPERMI2PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpermi2ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 77 /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VPERMI2Q xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPERMI2Q xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpermi2q xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 76 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VPERMI2Q ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPERMI2Q ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpermi2q ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 76 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VPERMI2Q zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPERMI2Q zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpermi2q zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 76 /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VPERMI2W xmm1, {k}{z}, xmmV, xmm2/m128","VPERMI2W xmm2/m128, xmmV, {k}{z}, xmm1","vpermi2w xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 75 /r","V","V","AVX512BW+AVX512VL","scale16","rw,r,r,r","","" +"VPERMI2W ymm1, {k}{z}, ymmV, ymm2/m256","VPERMI2W ymm2/m256, ymmV, {k}{z}, ymm1","vpermi2w ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 75 /r","V","V","AVX512BW+AVX512VL","scale32","rw,r,r,r","","" +"VPERMI2W zmm1, {k}{z}, zmmV, zmm2/m512","VPERMI2W zmm2/m512, zmmV, {k}{z}, zmm1","vpermi2w zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 75 /r","V","V","AVX512BW","scale64","rw,r,r,r","","" +"VPERMIL2PD xmm1, xmmV, xmmIH, xmm2/m128, imm8u","VPERMIL2PD imm8u, xmm2/m128, xmmIH, xmmV, xmm1","vpermil2pd imm8u, xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 49 /r /is4","V","V","XOP","amd","w,r,r,r,r","","" +"VPERMIL2PD xmm1, xmmV, xmm2/m128, xmmIH, imm8u","VPERMIL2PD imm8u, xmmIH, xmm2/m128, xmmV, xmm1","vpermil2pd imm8u, xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 49 /r /is4","V","V","XOP","amd","w,r,r,r,r","","" +"VPERMIL2PD ymm1, ymmV, ymmIH, ymm2/m256, imm8u","VPERMIL2PD imm8u, ymm2/m256, ymmIH, ymmV, ymm1","vpermil2pd imm8u, ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 49 /r /is4","V","V","XOP","amd","w,r,r,r,r","","" +"VPERMIL2PD ymm1, ymmV, ymm2/m256, ymmIH, imm8u","VPERMIL2PD imm8u, ymmIH, ymm2/m256, ymmV, ymm1","vpermil2pd imm8u, ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 49 /r /is4","V","V","XOP","amd","w,r,r,r,r","","" +"VPERMIL2PS xmm1, xmmV, xmmIH, xmm2/m128, imm8u","VPERMIL2PS imm8u, xmm2/m128, xmmIH, xmmV, xmm1","vpermil2ps imm8u, xmm2/m128, xmmIH, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 48 /r /is4","V","V","XOP","amd","w,r,r,r,r","","" +"VPERMIL2PS xmm1, xmmV, xmm2/m128, xmmIH, imm8u","VPERMIL2PS imm8u, xmmIH, xmm2/m128, xmmV, xmm1","vpermil2ps imm8u, xmmIH, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 48 /r /is4","V","V","XOP","amd","w,r,r,r,r","","" +"VPERMIL2PS ymm1, ymmV, ymmIH, ymm2/m256, imm8u","VPERMIL2PS imm8u, ymm2/m256, ymmIH, ymmV, ymm1","vpermil2ps imm8u, ymm2/m256, ymmIH, ymmV, ymm1","VEX.NDS.256.66.0F3A.W1 48 /r /is4","V","V","XOP","amd","w,r,r,r,r","","" +"VPERMIL2PS ymm1, ymmV, ymm2/m256, ymmIH, imm8u","VPERMIL2PS imm8u, ymmIH, ymm2/m256, ymmV, ymm1","vpermil2ps imm8u, ymmIH, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F3A.W0 48 /r /is4","V","V","XOP","amd","w,r,r,r,r","","" +"VPERMILPD xmm1, xmm2/m128, imm8u","VPERMILPD imm8u, xmm2/m128, xmm1","vpermilpd imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.W0 05 /r ib","V","V","AVX","","w,r,r","","" +"VPERMILPD xmm1, {k}{z}, xmm2/m128/m64bcst, imm8u","VPERMILPD imm8u, xmm2/m128/m64bcst, {k}{z}, xmm1","vpermilpd imm8u, xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F3A.W1 05 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPERMILPD ymm1, ymm2/m256, imm8u","VPERMILPD imm8u, ymm2/m256, ymm1","vpermilpd imm8u, ymm2/m256, ymm1","VEX.256.66.0F3A.W0 05 /r ib","V","V","AVX","","w,r,r","","" +"VPERMILPD ymm1, {k}{z}, ymm2/m256/m64bcst, imm8u","VPERMILPD imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","vpermilpd imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W1 05 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPERMILPD zmm1, {k}{z}, zmm2/m512/m64bcst, imm8u","VPERMILPD imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","vpermilpd imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W1 05 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPERMILPD xmm1, xmmV, xmm2/m128","VPERMILPD xmm2/m128, xmmV, xmm1","vpermilpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 0D /r","V","V","AVX","","w,r,r","","" +"VPERMILPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPERMILPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpermilpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 0D /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPERMILPD ymm1, ymmV, ymm2/m256","VPERMILPD ymm2/m256, ymmV, ymm1","vpermilpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 0D /r","V","V","AVX","","w,r,r","","" +"VPERMILPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPERMILPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpermilpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 0D /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPERMILPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPERMILPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpermilpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 0D /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPERMILPS xmm1, xmm2/m128, imm8u","VPERMILPS imm8u, xmm2/m128, xmm1","vpermilps imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.W0 04 /r ib","V","V","AVX","","w,r,r","","" +"VPERMILPS xmm1, {k}{z}, xmm2/m128/m32bcst, imm8u","VPERMILPS imm8u, xmm2/m128/m32bcst, {k}{z}, xmm1","vpermilps imm8u, xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F3A.W0 04 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPERMILPS ymm1, ymm2/m256, imm8u","VPERMILPS imm8u, ymm2/m256, ymm1","vpermilps imm8u, ymm2/m256, ymm1","VEX.256.66.0F3A.W0 04 /r ib","V","V","AVX","","w,r,r","","" +"VPERMILPS ymm1, {k}{z}, ymm2/m256/m32bcst, imm8u","VPERMILPS imm8u, ymm2/m256/m32bcst, {k}{z}, ymm1","vpermilps imm8u, ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W0 04 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPERMILPS zmm1, {k}{z}, zmm2/m512/m32bcst, imm8u","VPERMILPS imm8u, zmm2/m512/m32bcst, {k}{z}, zmm1","vpermilps imm8u, zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W0 04 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPERMILPS xmm1, xmmV, xmm2/m128","VPERMILPS xmm2/m128, xmmV, xmm1","vpermilps xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 0C /r","V","V","AVX","","w,r,r","","" +"VPERMILPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPERMILPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpermilps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 0C /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPERMILPS ymm1, ymmV, ymm2/m256","VPERMILPS ymm2/m256, ymmV, ymm1","vpermilps ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 0C /r","V","V","AVX","","w,r,r","","" +"VPERMILPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPERMILPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpermilps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 0C /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPERMILPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPERMILPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpermilps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 0C /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPERMPD ymm1, ymm2/m256, imm8u","VPERMPD imm8u, ymm2/m256, ymm1","vpermpd imm8u, ymm2/m256, ymm1","VEX.256.66.0F3A.W1 01 /r ib","V","V","AVX2","","w,r,r","","" +"VPERMPD ymm1, {k}{z}, ymm2/m256/m64bcst, imm8u","VPERMPD imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","vpermpd imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W1 01 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPERMPD zmm1, {k}{z}, zmm2/m512/m64bcst, imm8u","VPERMPD imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","vpermpd imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W1 01 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPERMPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPERMPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpermpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 16 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPERMPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPERMPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpermpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 16 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPERMPS ymm1, ymmV, ymm2/m256","VPERMPS ymm2/m256, ymmV, ymm1","vpermps ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 16 /r","V","V","AVX2","","w,r,r","","" +"VPERMPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPERMPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpermps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 16 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPERMPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPERMPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpermps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 16 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPERMQ ymm1, ymm2/m256, imm8u","VPERMQ imm8u, ymm2/m256, ymm1","vpermq imm8u, ymm2/m256, ymm1","VEX.256.66.0F3A.W1 00 /r ib","V","V","AVX2","","w,r,r","","" +"VPERMQ ymm1, {k}{z}, ymm2/m256/m64bcst, imm8u","VPERMQ imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","vpermq imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W1 00 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPERMQ zmm1, {k}{z}, zmm2/m512/m64bcst, imm8u","VPERMQ imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","vpermq imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W1 00 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPERMQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPERMQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpermq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 36 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPERMQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPERMQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpermq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 36 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPERMT2B xmm1, {k}{z}, xmmV, xmm2/m128","VPERMT2B xmm2/m128, xmmV, {k}{z}, xmm1","vpermt2b xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 7D /r","V","V","AVX512_VBMI+AVX512VL","scale16","rw,r,r,r","","" +"VPERMT2B ymm1, {k}{z}, ymmV, ymm2/m256","VPERMT2B ymm2/m256, ymmV, {k}{z}, ymm1","vpermt2b ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 7D /r","V","V","AVX512_VBMI+AVX512VL","scale32","rw,r,r,r","","" +"VPERMT2B zmm1, {k}{z}, zmmV, zmm2/m512","VPERMT2B zmm2/m512, zmmV, {k}{z}, zmm1","vpermt2b zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 7D /r","V","V","AVX512_VBMI","scale64","rw,r,r,r","","" +"VPERMT2D xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPERMT2D xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpermt2d xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 7E /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPERMT2D ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPERMT2D ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpermt2d ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 7E /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPERMT2D zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPERMT2D zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpermt2d zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 7E /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VPERMT2PD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPERMT2PD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpermt2pd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 7F /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VPERMT2PD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPERMT2PD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpermt2pd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 7F /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VPERMT2PD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPERMT2PD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpermt2pd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 7F /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VPERMT2PS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPERMT2PS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpermt2ps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 7F /r","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPERMT2PS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPERMT2PS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpermt2ps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 7F /r","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPERMT2PS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPERMT2PS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpermt2ps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 7F /r","V","V","AVX512F","bscale4,scale64","rw,r,r,r","","" +"VPERMT2Q xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPERMT2Q xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpermt2q xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 7E /r","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VPERMT2Q ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPERMT2Q ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpermt2q ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 7E /r","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VPERMT2Q zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPERMT2Q zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpermt2q zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 7E /r","V","V","AVX512F","bscale8,scale64","rw,r,r,r","","" +"VPERMT2W xmm1, {k}{z}, xmmV, xmm2/m128","VPERMT2W xmm2/m128, xmmV, {k}{z}, xmm1","vpermt2w xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 7D /r","V","V","AVX512BW+AVX512VL","scale16","rw,r,r,r","","" +"VPERMT2W ymm1, {k}{z}, ymmV, ymm2/m256","VPERMT2W ymm2/m256, ymmV, {k}{z}, ymm1","vpermt2w ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 7D /r","V","V","AVX512BW+AVX512VL","scale32","rw,r,r,r","","" +"VPERMT2W zmm1, {k}{z}, zmmV, zmm2/m512","VPERMT2W zmm2/m512, zmmV, {k}{z}, zmm1","vpermt2w zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 7D /r","V","V","AVX512BW","scale64","rw,r,r,r","","" +"VPERMW xmm1, {k}{z}, xmmV, xmm2/m128","VPERMW xmm2/m128, xmmV, {k}{z}, xmm1","vpermw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 8D /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPERMW ymm1, {k}{z}, ymmV, ymm2/m256","VPERMW ymm2/m256, ymmV, {k}{z}, ymm1","vpermw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 8D /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPERMW zmm1, {k}{z}, zmmV, zmm2/m512","VPERMW zmm2/m512, zmmV, {k}{z}, zmm1","vpermw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 8D /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPEXPANDB xmm1, {k}{z}, xmm2/m128","VPEXPANDB xmm2/m128, {k}{z}, xmm1","vpexpandb xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.W0 62 /r","V","V","AVX512_VBMI2+AVX512VL","scale1","w,r,r","","" +"VPEXPANDB ymm1, {k}{z}, ymm2/m256","VPEXPANDB ymm2/m256, {k}{z}, ymm1","vpexpandb ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.W0 62 /r","V","V","AVX512_VBMI2+AVX512VL","scale1","w,r,r","","" +"VPEXPANDB zmm1, {k}{z}, zmm2/m512","VPEXPANDB zmm2/m512, {k}{z}, zmm1","vpexpandb zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.W0 62 /r","V","V","AVX512_VBMI2","scale1","w,r,r","","" +"VPEXPANDD xmm1, {k}{z}, xmm2/m128","VPEXPANDD xmm2/m128, {k}{z}, xmm1","vpexpandd xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.W0 89 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPEXPANDD ymm1, {k}{z}, ymm2/m256","VPEXPANDD ymm2/m256, {k}{z}, ymm1","vpexpandd ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.W0 89 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPEXPANDD zmm1, {k}{z}, zmm2/m512","VPEXPANDD zmm2/m512, {k}{z}, zmm1","vpexpandd zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.W0 89 /r","V","V","AVX512F","scale4","w,r,r","","" +"VPEXPANDQ xmm1, {k}{z}, xmm2/m128","VPEXPANDQ xmm2/m128, {k}{z}, xmm1","vpexpandq xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.W1 89 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPEXPANDQ ymm1, {k}{z}, ymm2/m256","VPEXPANDQ ymm2/m256, {k}{z}, ymm1","vpexpandq ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.W1 89 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPEXPANDQ zmm1, {k}{z}, zmm2/m512","VPEXPANDQ zmm2/m512, {k}{z}, zmm1","vpexpandq zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.W1 89 /r","V","V","AVX512F","scale8","w,r,r","","" +"VPEXPANDW xmm1, {k}{z}, xmm2/m128","VPEXPANDW xmm2/m128, {k}{z}, xmm1","vpexpandw xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.W1 62 /r","V","V","AVX512_VBMI2+AVX512VL","scale2","w,r,r","","" +"VPEXPANDW ymm1, {k}{z}, ymm2/m256","VPEXPANDW ymm2/m256, {k}{z}, ymm1","vpexpandw ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.W1 62 /r","V","V","AVX512_VBMI2+AVX512VL","scale2","w,r,r","","" +"VPEXPANDW zmm1, {k}{z}, zmm2/m512","VPEXPANDW zmm2/m512, {k}{z}, zmm1","vpexpandw zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.W1 62 /r","V","V","AVX512_VBMI2","scale2","w,r,r","","" +"VPEXTRB r32/m8, xmm1, imm8u","VPEXTRB imm8u, xmm1, r32/m8","vpextrb imm8u, xmm1, r32/m8","EVEX.128.66.0F3A.WIG 14 /r ib","V","V","AVX512BW+AVX512VL","scale1","w,r,r","","" +"VPEXTRB r32/m8, xmm1, imm8u","VPEXTRB imm8u, xmm1, r32/m8","vpextrb imm8u, xmm1, r32/m8","VEX.128.66.0F3A.WIG 14 /r ib","V","V","AVX","","w,r,r","","" +"VPEXTRD r/m32, xmm1, imm8u","VPEXTRD imm8u, xmm1, r/m32","vpextrd imm8u, xmm1, r/m32","EVEX.128.66.0F3A.W0 16 /r ib","V","V","AVX512DQ+AVX512VL","scale4","w,r,r","","" +"VPEXTRD r/m32, xmm1, imm8u","VPEXTRD imm8u, xmm1, r/m32","vpextrd imm8u, xmm1, r/m32","VEX.128.66.0F3A.W0 16 /r ib","V","V","AVX","","w,r,r","","" +"VPEXTRQ r/m64, xmm1, imm8u","VPEXTRQ imm8u, xmm1, r/m64","vpextrq imm8u, xmm1, r/m64","EVEX.128.66.0F3A.W1 16 /r ib","N.S.","V","AVX512DQ+AVX512VL","scale8","w,r,r","","" +"VPEXTRQ r/m64, xmm1, imm8u","VPEXTRQ imm8u, xmm1, r/m64","vpextrq imm8u, xmm1, r/m64","VEX.128.66.0F3A.W1 16 /r ib","N.S.","V","AVX","","w,r,r","","" +"VPEXTRW r32/m16, xmm1, imm8u","VPEXTRW imm8u, xmm1, r32/m16","vpextrw imm8u, xmm1, r32/m16","EVEX.128.66.0F3A.WIG 15 /r ib","V","V","AVX512BW+AVX512VL","scale2","w,r,r","","" +"VPEXTRW r32/m16, xmm1, imm8u","VPEXTRW imm8u, xmm1, r32/m16","vpextrw imm8u, xmm1, r32/m16","VEX.128.66.0F3A.WIG 15 /r ib","V","V","AVX","","w,r,r","","" +"VPEXTRW r32, xmm2, imm8u","VPEXTRW imm8u, xmm2, r32","vpextrw imm8u, xmm2, r32","EVEX.128.66.0F.WIG C5 /r ib","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r,r","","" +"VPEXTRW r32, xmm2, imm8u","VPEXTRW imm8u, xmm2, r32","vpextrw imm8u, xmm2, r32","VEX.128.66.0F.WIG C5 /r ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPGATHERDD xmm1, {k1-k7}, vm32x","VPGATHERDD vm32x, {k1-k7}, xmm1","vpgatherdd vm32x, {k1-k7}, xmm1","EVEX.128.66.0F38.W0 90 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VPGATHERDD ymm1, {k1-k7}, vm32y","VPGATHERDD vm32y, {k1-k7}, ymm1","vpgatherdd vm32y, {k1-k7}, ymm1","EVEX.256.66.0F38.W0 90 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VPGATHERDD zmm1, {k1-k7}, vm32z","VPGATHERDD vm32z, {k1-k7}, zmm1","vpgatherdd vm32z, {k1-k7}, zmm1","EVEX.512.66.0F38.W0 90 /vsib","V","V","AVX512F","modrm_memonly,scale4","w,rw,r","","" +"VPGATHERDD xmm1, vm32x, xmmV","VPGATHERDD xmmV, vm32x, xmm1","vpgatherdd xmmV, vm32x, xmm1","VEX.DDS.128.66.0F38.W0 90 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VPGATHERDD ymm1, vm32y, ymmV","VPGATHERDD ymmV, vm32y, ymm1","vpgatherdd ymmV, vm32y, ymm1","VEX.DDS.256.66.0F38.W0 90 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VPGATHERDQ xmm1, {k1-k7}, vm32x","VPGATHERDQ vm32x, {k1-k7}, xmm1","vpgatherdq vm32x, {k1-k7}, xmm1","EVEX.128.66.0F38.W1 90 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VPGATHERDQ ymm1, {k1-k7}, vm32x","VPGATHERDQ vm32x, {k1-k7}, ymm1","vpgatherdq vm32x, {k1-k7}, ymm1","EVEX.256.66.0F38.W1 90 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VPGATHERDQ zmm1, {k1-k7}, vm32y","VPGATHERDQ vm32y, {k1-k7}, zmm1","vpgatherdq vm32y, {k1-k7}, zmm1","EVEX.512.66.0F38.W1 90 /vsib","V","V","AVX512F","modrm_memonly,scale8","w,rw,r","","" +"VPGATHERDQ xmm1, vm32x, xmmV","VPGATHERDQ xmmV, vm32x, xmm1","vpgatherdq xmmV, vm32x, xmm1","VEX.DDS.128.66.0F38.W1 90 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VPGATHERDQ ymm1, vm32x, ymmV","VPGATHERDQ ymmV, vm32x, ymm1","vpgatherdq ymmV, vm32x, ymm1","VEX.DDS.256.66.0F38.W1 90 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VPGATHERQD xmm1, {k1-k7}, vm64x","VPGATHERQD vm64x, {k1-k7}, xmm1","vpgatherqd vm64x, {k1-k7}, xmm1","EVEX.128.66.0F38.W0 91 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VPGATHERQD xmm1, {k1-k7}, vm64y","VPGATHERQD vm64y, {k1-k7}, xmm1","vpgatherqd vm64y, {k1-k7}, xmm1","EVEX.256.66.0F38.W0 91 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VPGATHERQD ymm1, {k1-k7}, vm64z","VPGATHERQD vm64z, {k1-k7}, ymm1","vpgatherqd vm64z, {k1-k7}, ymm1","EVEX.512.66.0F38.W0 91 /vsib","V","V","AVX512F","modrm_memonly,scale4","w,rw,r","","" +"VPGATHERQD xmm1, vm64x, xmmV","VPGATHERQD xmmV, vm64x, xmm1","vpgatherqd xmmV, vm64x, xmm1","VEX.DDS.128.66.0F38.W0 91 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VPGATHERQD xmm1, vm64y, xmmV","VPGATHERQD xmmV, vm64y, xmm1","vpgatherqd xmmV, vm64y, xmm1","VEX.DDS.256.66.0F38.W0 91 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VPGATHERQQ xmm1, {k1-k7}, vm64x","VPGATHERQQ vm64x, {k1-k7}, xmm1","vpgatherqq vm64x, {k1-k7}, xmm1","EVEX.128.66.0F38.W1 91 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VPGATHERQQ ymm1, {k1-k7}, vm64y","VPGATHERQQ vm64y, {k1-k7}, ymm1","vpgatherqq vm64y, {k1-k7}, ymm1","EVEX.256.66.0F38.W1 91 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VPGATHERQQ zmm1, {k1-k7}, vm64z","VPGATHERQQ vm64z, {k1-k7}, zmm1","vpgatherqq vm64z, {k1-k7}, zmm1","EVEX.512.66.0F38.W1 91 /vsib","V","V","AVX512F","modrm_memonly,scale8","w,rw,r","","" +"VPGATHERQQ xmm1, vm64x, xmmV","VPGATHERQQ xmmV, vm64x, xmm1","vpgatherqq xmmV, vm64x, xmm1","VEX.DDS.128.66.0F38.W1 91 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VPGATHERQQ ymm1, vm64y, ymmV","VPGATHERQQ ymmV, vm64y, ymm1","vpgatherqq ymmV, vm64y, ymm1","VEX.DDS.256.66.0F38.W1 91 /r","V","V","AVX2","modrm_memonly","rw,r,rw","","" +"VPHADDBD xmm1, xmm2/m128","VPHADDBD xmm2/m128, xmm1","vphaddbd xmm2/m128, xmm1","XOP.128.09.W0 C2 /r","V","V","XOP","amd","w,r","","" +"VPHADDBQ xmm1, xmm2/m128","VPHADDBQ xmm2/m128, xmm1","vphaddbq xmm2/m128, xmm1","XOP.128.09.W0 C3 /r","V","V","XOP","amd","w,r","","" +"VPHADDBW xmm1, xmm2/m128","VPHADDBW xmm2/m128, xmm1","vphaddbw xmm2/m128, xmm1","XOP.128.09.W0 C1 /r","V","V","XOP","amd","w,r","","" +"VPHADDD xmm1, xmmV, xmm2/m128","VPHADDD xmm2/m128, xmmV, xmm1","vphaddd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 02 /r","V","V","AVX","","w,r,r","","" +"VPHADDD ymm1, ymmV, ymm2/m256","VPHADDD ymm2/m256, ymmV, ymm1","vphaddd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 02 /r","V","V","AVX2","","w,r,r","","" +"VPHADDDQ xmm1, xmm2/m128","VPHADDDQ xmm2/m128, xmm1","vphadddq xmm2/m128, xmm1","XOP.128.09.W0 CB /r","V","V","XOP","amd","w,r","","" +"VPHADDSW xmm1, xmmV, xmm2/m128","VPHADDSW xmm2/m128, xmmV, xmm1","vphaddsw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 03 /r","V","V","AVX","","w,r,r","","" +"VPHADDSW ymm1, ymmV, ymm2/m256","VPHADDSW ymm2/m256, ymmV, ymm1","vphaddsw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 03 /r","V","V","AVX2","","w,r,r","","" +"VPHADDUBD xmm1, xmm2/m128","VPHADDUBD xmm2/m128, xmm1","vphaddubd xmm2/m128, xmm1","XOP.128.09.W0 D2 /r","V","V","XOP","amd","w,r","","" +"VPHADDUBQ xmm1, xmm2/m128","VPHADDUBQ xmm2/m128, xmm1","vphaddubq xmm2/m128, xmm1","XOP.128.09.W0 D3 /r","V","V","XOP","amd","w,r","","" +"VPHADDUBW xmm1, xmm2/m128","VPHADDUBW xmm2/m128, xmm1","vphaddubw xmm2/m128, xmm1","XOP.128.09.W0 D1 /r","V","V","XOP","amd","w,r","","" +"VPHADDUDQ xmm1, xmm2/m128","VPHADDUDQ xmm2/m128, xmm1","vphaddudq xmm2/m128, xmm1","XOP.128.09.W0 DB /r","V","V","XOP","amd","w,r","","" +"VPHADDUWD xmm1, xmm2/m128","VPHADDUWD xmm2/m128, xmm1","vphadduwd xmm2/m128, xmm1","XOP.128.09.W0 D6 /r","V","V","XOP","amd","w,r","","" +"VPHADDUWQ xmm1, xmm2/m128","VPHADDUWQ xmm2/m128, xmm1","vphadduwq xmm2/m128, xmm1","XOP.128.09.W0 D7 /r","V","V","XOP","amd","w,r","","" +"VPHADDW xmm1, xmmV, xmm2/m128","VPHADDW xmm2/m128, xmmV, xmm1","vphaddw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 01 /r","V","V","AVX","","w,r,r","","" +"VPHADDW ymm1, ymmV, ymm2/m256","VPHADDW ymm2/m256, ymmV, ymm1","vphaddw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 01 /r","V","V","AVX2","","w,r,r","","" +"VPHADDWD xmm1, xmm2/m128","VPHADDWD xmm2/m128, xmm1","vphaddwd xmm2/m128, xmm1","XOP.128.09.W0 C6 /r","V","V","XOP","amd","w,r","","" +"VPHADDWQ xmm1, xmm2/m128","VPHADDWQ xmm2/m128, xmm1","vphaddwq xmm2/m128, xmm1","XOP.128.09.W0 C7 /r","V","V","XOP","amd","w,r","","" +"VPHMINPOSUW xmm1, xmm2/m128","VPHMINPOSUW xmm2/m128, xmm1","vphminposuw xmm2/m128, xmm1","VEX.128.66.0F38.WIG 41 /r","V","V","AVX","","w,r","","" +"VPHSUBBW xmm1, xmm2/m128","VPHSUBBW xmm2/m128, xmm1","vphsubbw xmm2/m128, xmm1","XOP.128.09.W0 E1 /r","V","V","XOP","amd","w,r","","" +"VPHSUBD xmm1, xmmV, xmm2/m128","VPHSUBD xmm2/m128, xmmV, xmm1","vphsubd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 06 /r","V","V","AVX","","w,r,r","","" +"VPHSUBD ymm1, ymmV, ymm2/m256","VPHSUBD ymm2/m256, ymmV, ymm1","vphsubd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 06 /r","V","V","AVX2","","w,r,r","","" +"VPHSUBDQ xmm1, xmm2/m128","VPHSUBDQ xmm2/m128, xmm1","vphsubdq xmm2/m128, xmm1","XOP.128.09.W0 E3 /r","V","V","XOP","amd","w,r","","" +"VPHSUBSW xmm1, xmmV, xmm2/m128","VPHSUBSW xmm2/m128, xmmV, xmm1","vphsubsw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 07 /r","V","V","AVX","","w,r,r","","" +"VPHSUBSW ymm1, ymmV, ymm2/m256","VPHSUBSW ymm2/m256, ymmV, ymm1","vphsubsw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 07 /r","V","V","AVX2","","w,r,r","","" +"VPHSUBW xmm1, xmmV, xmm2/m128","VPHSUBW xmm2/m128, xmmV, xmm1","vphsubw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 05 /r","V","V","AVX","","w,r,r","","" +"VPHSUBW ymm1, ymmV, ymm2/m256","VPHSUBW ymm2/m256, ymmV, ymm1","vphsubw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 05 /r","V","V","AVX2","","w,r,r","","" +"VPHSUBWD xmm1, xmm2/m128","VPHSUBWD xmm2/m128, xmm1","vphsubwd xmm2/m128, xmm1","XOP.128.09.W0 E2 /r","V","V","XOP","amd","w,r","","" +"VPINSRB xmm1, xmmV, r32/m8, imm8u","VPINSRB imm8u, r32/m8, xmmV, xmm1","vpinsrb imm8u, r32/m8, xmmV, xmm1","EVEX.NDS.128.66.0F3A.WIG 20 /r ib","V","V","AVX512BW+AVX512VL","scale1","w,r,r,r","","" +"VPINSRB xmm1, xmmV, r32/m8, imm8u","VPINSRB imm8u, r32/m8, xmmV, xmm1","vpinsrb imm8u, r32/m8, xmmV, xmm1","VEX.NDS.128.66.0F3A.WIG 20 /r ib","V","V","AVX","","w,r,r,r","","" +"VPINSRD xmm1, xmmV, r/m32, imm8u","VPINSRD imm8u, r/m32, xmmV, xmm1","vpinsrd imm8u, r/m32, xmmV, xmm1","EVEX.NDS.128.66.0F3A.W0 22 /r ib","V","V","AVX512DQ+AVX512VL","scale4","w,r,r,r","","" +"VPINSRD xmm1, xmmV, r/m32, imm8u","VPINSRD imm8u, r/m32, xmmV, xmm1","vpinsrd imm8u, r/m32, xmmV, xmm1","VEX.NDS.128.66.0F3A.W0 22 /r ib","V","V","AVX","","w,r,r,r","","" +"VPINSRQ xmm1, xmmV, r/m64, imm8u","VPINSRQ imm8u, r/m64, xmmV, xmm1","vpinsrq imm8u, r/m64, xmmV, xmm1","EVEX.NDS.128.66.0F3A.W1 22 /r ib","N.S.","V","AVX512DQ+AVX512VL","scale8","w,r,r,r","","" +"VPINSRQ xmm1, xmmV, r/m64, imm8u","VPINSRQ imm8u, r/m64, xmmV, xmm1","vpinsrq imm8u, r/m64, xmmV, xmm1","VEX.NDS.128.66.0F3A.W1 22 /r ib","N.S.","V","AVX","","w,r,r,r","","" +"VPINSRW xmm1, xmmV, r32/m16, imm8u","VPINSRW imm8u, r32/m16, xmmV, xmm1","vpinsrw imm8u, r32/m16, xmmV, xmm1","EVEX.NDS.128.66.0F.WIG C4 /r ib","V","V","AVX512BW+AVX512VL","scale2","w,r,r,r","","" +"VPINSRW xmm1, xmmV, r32/m16, imm8u","VPINSRW imm8u, r32/m16, xmmV, xmm1","vpinsrw imm8u, r32/m16, xmmV, xmm1","VEX.NDS.128.66.0F.WIG C4 /r ib","V","V","AVX","","w,r,r,r","","" +"VPLZCNTD xmm1, {k}{z}, xmm2/m128/m32bcst","VPLZCNTD xmm2/m128/m32bcst, {k}{z}, xmm1","vplzcntd xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W0 44 /r","V","V","AVX512CD+AVX512VL","bscale4,scale16","w,r,r","","" +"VPLZCNTD ymm1, {k}{z}, ymm2/m256/m32bcst","VPLZCNTD ymm2/m256/m32bcst, {k}{z}, ymm1","vplzcntd ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W0 44 /r","V","V","AVX512CD+AVX512VL","bscale4,scale32","w,r,r","","" +"VPLZCNTD zmm1, {k}{z}, zmm2/m512/m32bcst","VPLZCNTD zmm2/m512/m32bcst, {k}{z}, zmm1","vplzcntd zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 44 /r","V","V","AVX512CD","bscale4,scale64","w,r,r","","" +"VPLZCNTQ xmm1, {k}{z}, xmm2/m128/m64bcst","VPLZCNTQ xmm2/m128/m64bcst, {k}{z}, xmm1","vplzcntq xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W1 44 /r","V","V","AVX512CD+AVX512VL","bscale8,scale16","w,r,r","","" +"VPLZCNTQ ymm1, {k}{z}, ymm2/m256/m64bcst","VPLZCNTQ ymm2/m256/m64bcst, {k}{z}, ymm1","vplzcntq ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W1 44 /r","V","V","AVX512CD+AVX512VL","bscale8,scale32","w,r,r","","" +"VPLZCNTQ zmm1, {k}{z}, zmm2/m512/m64bcst","VPLZCNTQ zmm2/m512/m64bcst, {k}{z}, zmm1","vplzcntq zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 44 /r","V","V","AVX512CD","bscale8,scale64","w,r,r","","" +"VPMACSDD xmm1, xmmV, xmm2/m128, xmmIH","VPMACSDD xmmIH, xmm2/m128, xmmV, xmm1","vpmacsdd xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 9E /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSDQH xmm1, xmmV, xmm2/m128, xmmIH","VPMACSDQH xmmIH, xmm2/m128, xmmV, xmm1","vpmacsdqh xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 9F /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSDQL xmm1, xmmV, xmm2/m128, xmmIH","VPMACSDQL xmmIH, xmm2/m128, xmmV, xmm1","vpmacsdql xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 97 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSSDD xmm1, xmmV, xmm2/m128, xmmIH","VPMACSSDD xmmIH, xmm2/m128, xmmV, xmm1","vpmacssdd xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 8E /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSSDQH xmm1, xmmV, xmm2/m128, xmmIH","VPMACSSDQH xmmIH, xmm2/m128, xmmV, xmm1","vpmacssdqh xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 8F /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSSDQL xmm1, xmmV, xmm2/m128, xmmIH","VPMACSSDQL xmmIH, xmm2/m128, xmmV, xmm1","vpmacssdql xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 87 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSSWD xmm1, xmmV, xmm2/m128, xmmIH","VPMACSSWD xmmIH, xmm2/m128, xmmV, xmm1","vpmacsswd xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 86 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSSWW xmm1, xmmV, xmm2/m128, xmmIH","VPMACSSWW xmmIH, xmm2/m128, xmmV, xmm1","vpmacssww xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 85 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSWD xmm1, xmmV, xmm2/m128, xmmIH","VPMACSWD xmmIH, xmm2/m128, xmmV, xmm1","vpmacswd xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 96 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMACSWW xmm1, xmmV, xmm2/m128, xmmIH","VPMACSWW xmmIH, xmm2/m128, xmmV, xmm1","vpmacsww xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 95 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMADCSSWD xmm1, xmmV, xmm2/m128, xmmIH","VPMADCSSWD xmmIH, xmm2/m128, xmmV, xmm1","vpmadcsswd xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 A6 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMADCSWD xmm1, xmmV, xmm2/m128, xmmIH","VPMADCSWD xmmIH, xmm2/m128, xmmV, xmm1","vpmadcswd xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 B6 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPMADD52HUQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMADD52HUQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpmadd52huq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 B5 /r","V","V","AVX512_IFMA+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VPMADD52HUQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMADD52HUQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpmadd52huq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 B5 /r","V","V","AVX512_IFMA+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VPMADD52HUQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMADD52HUQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpmadd52huq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 B5 /r","V","V","AVX512_IFMA","bscale8,scale64","rw,r,r,r","","" +"VPMADD52LUQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMADD52LUQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpmadd52luq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 B4 /r","V","V","AVX512_IFMA+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VPMADD52LUQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMADD52LUQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpmadd52luq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 B4 /r","V","V","AVX512_IFMA+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VPMADD52LUQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMADD52LUQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpmadd52luq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 B4 /r","V","V","AVX512_IFMA","bscale8,scale64","rw,r,r,r","","" +"VPMADDUBSW xmm1, xmmV, xmm2/m128","VPMADDUBSW xmm2/m128, xmmV, xmm1","vpmaddubsw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 04 /r","V","V","AVX","","w,r,r","","" +"VPMADDUBSW xmm1, {k}{z}, xmmV, xmm2/m128","VPMADDUBSW xmm2/m128, xmmV, {k}{z}, xmm1","vpmaddubsw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.WIG 04 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMADDUBSW ymm1, ymmV, ymm2/m256","VPMADDUBSW ymm2/m256, ymmV, ymm1","vpmaddubsw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 04 /r","V","V","AVX2","","w,r,r","","" +"VPMADDUBSW ymm1, {k}{z}, ymmV, ymm2/m256","VPMADDUBSW ymm2/m256, ymmV, {k}{z}, ymm1","vpmaddubsw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.WIG 04 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMADDUBSW zmm1, {k}{z}, zmmV, zmm2/m512","VPMADDUBSW zmm2/m512, zmmV, {k}{z}, zmm1","vpmaddubsw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.WIG 04 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMADDWD xmm1, xmmV, xmm2/m128","VPMADDWD xmm2/m128, xmmV, xmm1","vpmaddwd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG F5 /r","V","V","AVX","","w,r,r","","" +"VPMADDWD xmm1, {k}{z}, xmmV, xmm2/m128","VPMADDWD xmm2/m128, xmmV, {k}{z}, xmm1","vpmaddwd xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG F5 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMADDWD ymm1, ymmV, ymm2/m256","VPMADDWD ymm2/m256, ymmV, ymm1","vpmaddwd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG F5 /r","V","V","AVX2","","w,r,r","","" +"VPMADDWD ymm1, {k}{z}, ymmV, ymm2/m256","VPMADDWD ymm2/m256, ymmV, {k}{z}, ymm1","vpmaddwd ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG F5 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMADDWD zmm1, {k}{z}, zmmV, zmm2/m512","VPMADDWD zmm2/m512, zmmV, {k}{z}, zmm1","vpmaddwd zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG F5 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMASKMOVD xmm1, xmmV, m128","VPMASKMOVD m128, xmmV, xmm1","vpmaskmovd m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 8C /r","V","V","AVX2","modrm_memonly","w,r,r","","" +"VPMASKMOVD ymm1, ymmV, m256","VPMASKMOVD m256, ymmV, ymm1","vpmaskmovd m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 8C /r","V","V","AVX2","modrm_memonly","w,r,r","","" +"VPMASKMOVD m128, xmmV, xmm1","VPMASKMOVD xmm1, xmmV, m128","vpmaskmovd xmm1, xmmV, m128","VEX.NDS.128.66.0F38.W0 8E /r","V","V","AVX2","modrm_memonly","w,r,r","","" +"VPMASKMOVD m256, ymmV, ymm1","VPMASKMOVD ymm1, ymmV, m256","vpmaskmovd ymm1, ymmV, m256","VEX.NDS.256.66.0F38.W0 8E /r","V","V","AVX2","modrm_memonly","w,r,r","","" +"VPMASKMOVQ xmm1, xmmV, m128","VPMASKMOVQ m128, xmmV, xmm1","vpmaskmovq m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W1 8C /r","V","V","AVX2","modrm_memonly","w,r,r","","" +"VPMASKMOVQ ymm1, ymmV, m256","VPMASKMOVQ m256, ymmV, ymm1","vpmaskmovq m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W1 8C /r","V","V","AVX2","modrm_memonly","w,r,r","","" +"VPMASKMOVQ m128, xmmV, xmm1","VPMASKMOVQ xmm1, xmmV, m128","vpmaskmovq xmm1, xmmV, m128","VEX.NDS.128.66.0F38.W1 8E /r","V","V","AVX2","modrm_memonly","w,r,r","","" +"VPMASKMOVQ m256, ymmV, ymm1","VPMASKMOVQ ymm1, ymmV, m256","vpmaskmovq ymm1, ymmV, m256","VEX.NDS.256.66.0F38.W1 8E /r","V","V","AVX2","modrm_memonly","w,r,r","","" +"VPMAXSB xmm1, xmmV, xmm2/m128","VPMAXSB xmm2/m128, xmmV, xmm1","vpmaxsb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 3C /r","V","V","AVX","","w,r,r","","" +"VPMAXSB xmm1, {k}{z}, xmmV, xmm2/m128","VPMAXSB xmm2/m128, xmmV, {k}{z}, xmm1","vpmaxsb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.WIG 3C /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMAXSB ymm1, ymmV, ymm2/m256","VPMAXSB ymm2/m256, ymmV, ymm1","vpmaxsb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 3C /r","V","V","AVX2","","w,r,r","","" +"VPMAXSB ymm1, {k}{z}, ymmV, ymm2/m256","VPMAXSB ymm2/m256, ymmV, {k}{z}, ymm1","vpmaxsb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.WIG 3C /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMAXSB zmm1, {k}{z}, zmmV, zmm2/m512","VPMAXSB zmm2/m512, zmmV, {k}{z}, zmm1","vpmaxsb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.WIG 3C /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMAXSD xmm1, xmmV, xmm2/m128","VPMAXSD xmm2/m128, xmmV, xmm1","vpmaxsd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 3D /r","V","V","AVX","","w,r,r","","" +"VPMAXSD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPMAXSD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpmaxsd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 3D /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPMAXSD ymm1, ymmV, ymm2/m256","VPMAXSD ymm2/m256, ymmV, ymm1","vpmaxsd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 3D /r","V","V","AVX2","","w,r,r","","" +"VPMAXSD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPMAXSD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpmaxsd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 3D /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPMAXSD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPMAXSD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpmaxsd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 3D /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPMAXSQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMAXSQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpmaxsq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 3D /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPMAXSQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMAXSQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpmaxsq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 3D /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPMAXSQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMAXSQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpmaxsq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 3D /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPMAXSW xmm1, xmmV, xmm2/m128","VPMAXSW xmm2/m128, xmmV, xmm1","vpmaxsw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG EE /r","V","V","AVX","","w,r,r","","" +"VPMAXSW xmm1, {k}{z}, xmmV, xmm2/m128","VPMAXSW xmm2/m128, xmmV, {k}{z}, xmm1","vpmaxsw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG EE /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMAXSW ymm1, ymmV, ymm2/m256","VPMAXSW ymm2/m256, ymmV, ymm1","vpmaxsw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG EE /r","V","V","AVX2","","w,r,r","","" +"VPMAXSW ymm1, {k}{z}, ymmV, ymm2/m256","VPMAXSW ymm2/m256, ymmV, {k}{z}, ymm1","vpmaxsw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG EE /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMAXSW zmm1, {k}{z}, zmmV, zmm2/m512","VPMAXSW zmm2/m512, zmmV, {k}{z}, zmm1","vpmaxsw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG EE /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMAXUB xmm1, xmmV, xmm2/m128","VPMAXUB xmm2/m128, xmmV, xmm1","vpmaxub xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG DE /r","V","V","AVX","","w,r,r","","" +"VPMAXUB xmm1, {k}{z}, xmmV, xmm2/m128","VPMAXUB xmm2/m128, xmmV, {k}{z}, xmm1","vpmaxub xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG DE /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMAXUB ymm1, ymmV, ymm2/m256","VPMAXUB ymm2/m256, ymmV, ymm1","vpmaxub ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG DE /r","V","V","AVX2","","w,r,r","","" +"VPMAXUB ymm1, {k}{z}, ymmV, ymm2/m256","VPMAXUB ymm2/m256, ymmV, {k}{z}, ymm1","vpmaxub ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG DE /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMAXUB zmm1, {k}{z}, zmmV, zmm2/m512","VPMAXUB zmm2/m512, zmmV, {k}{z}, zmm1","vpmaxub zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG DE /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMAXUD xmm1, xmmV, xmm2/m128","VPMAXUD xmm2/m128, xmmV, xmm1","vpmaxud xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 3F /r","V","V","AVX","","w,r,r","","" +"VPMAXUD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPMAXUD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpmaxud xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 3F /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPMAXUD ymm1, ymmV, ymm2/m256","VPMAXUD ymm2/m256, ymmV, ymm1","vpmaxud ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 3F /r","V","V","AVX2","","w,r,r","","" +"VPMAXUD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPMAXUD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpmaxud ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 3F /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPMAXUD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPMAXUD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpmaxud zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 3F /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPMAXUQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMAXUQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpmaxuq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 3F /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPMAXUQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMAXUQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpmaxuq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 3F /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPMAXUQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMAXUQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpmaxuq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 3F /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPMAXUW xmm1, xmmV, xmm2/m128","VPMAXUW xmm2/m128, xmmV, xmm1","vpmaxuw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 3E /r","V","V","AVX","","w,r,r","","" +"VPMAXUW xmm1, {k}{z}, xmmV, xmm2/m128","VPMAXUW xmm2/m128, xmmV, {k}{z}, xmm1","vpmaxuw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.WIG 3E /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMAXUW ymm1, ymmV, ymm2/m256","VPMAXUW ymm2/m256, ymmV, ymm1","vpmaxuw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 3E /r","V","V","AVX2","","w,r,r","","" +"VPMAXUW ymm1, {k}{z}, ymmV, ymm2/m256","VPMAXUW ymm2/m256, ymmV, {k}{z}, ymm1","vpmaxuw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.WIG 3E /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMAXUW zmm1, {k}{z}, zmmV, zmm2/m512","VPMAXUW zmm2/m512, zmmV, {k}{z}, zmm1","vpmaxuw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.WIG 3E /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMINSB xmm1, xmmV, xmm2/m128","VPMINSB xmm2/m128, xmmV, xmm1","vpminsb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 38 /r","V","V","AVX","","w,r,r","","" +"VPMINSB xmm1, {k}{z}, xmmV, xmm2/m128","VPMINSB xmm2/m128, xmmV, {k}{z}, xmm1","vpminsb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.WIG 38 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMINSB ymm1, ymmV, ymm2/m256","VPMINSB ymm2/m256, ymmV, ymm1","vpminsb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 38 /r","V","V","AVX2","","w,r,r","","" +"VPMINSB ymm1, {k}{z}, ymmV, ymm2/m256","VPMINSB ymm2/m256, ymmV, {k}{z}, ymm1","vpminsb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.WIG 38 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMINSB zmm1, {k}{z}, zmmV, zmm2/m512","VPMINSB zmm2/m512, zmmV, {k}{z}, zmm1","vpminsb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.WIG 38 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMINSD xmm1, xmmV, xmm2/m128","VPMINSD xmm2/m128, xmmV, xmm1","vpminsd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 39 /r","V","V","AVX","","w,r,r","","" +"VPMINSD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPMINSD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpminsd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 39 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPMINSD ymm1, ymmV, ymm2/m256","VPMINSD ymm2/m256, ymmV, ymm1","vpminsd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 39 /r","V","V","AVX2","","w,r,r","","" +"VPMINSD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPMINSD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpminsd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 39 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPMINSD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPMINSD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpminsd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 39 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPMINSQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMINSQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpminsq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 39 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPMINSQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMINSQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpminsq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 39 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPMINSQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMINSQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpminsq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 39 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPMINSW xmm1, xmmV, xmm2/m128","VPMINSW xmm2/m128, xmmV, xmm1","vpminsw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG EA /r","V","V","AVX","","w,r,r","","" +"VPMINSW xmm1, {k}{z}, xmmV, xmm2/m128","VPMINSW xmm2/m128, xmmV, {k}{z}, xmm1","vpminsw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG EA /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMINSW ymm1, ymmV, ymm2/m256","VPMINSW ymm2/m256, ymmV, ymm1","vpminsw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG EA /r","V","V","AVX2","","w,r,r","","" +"VPMINSW ymm1, {k}{z}, ymmV, ymm2/m256","VPMINSW ymm2/m256, ymmV, {k}{z}, ymm1","vpminsw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG EA /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMINSW zmm1, {k}{z}, zmmV, zmm2/m512","VPMINSW zmm2/m512, zmmV, {k}{z}, zmm1","vpminsw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG EA /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMINUB xmm1, xmmV, xmm2/m128","VPMINUB xmm2/m128, xmmV, xmm1","vpminub xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG DA /r","V","V","AVX","","w,r,r","","" +"VPMINUB xmm1, {k}{z}, xmmV, xmm2/m128","VPMINUB xmm2/m128, xmmV, {k}{z}, xmm1","vpminub xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG DA /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMINUB ymm1, ymmV, ymm2/m256","VPMINUB ymm2/m256, ymmV, ymm1","vpminub ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG DA /r","V","V","AVX2","","w,r,r","","" +"VPMINUB ymm1, {k}{z}, ymmV, ymm2/m256","VPMINUB ymm2/m256, ymmV, {k}{z}, ymm1","vpminub ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG DA /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMINUB zmm1, {k}{z}, zmmV, zmm2/m512","VPMINUB zmm2/m512, zmmV, {k}{z}, zmm1","vpminub zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG DA /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMINUD xmm1, xmmV, xmm2/m128","VPMINUD xmm2/m128, xmmV, xmm1","vpminud xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 3B /r","V","V","AVX","","w,r,r","","" +"VPMINUD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPMINUD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpminud xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 3B /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPMINUD ymm1, ymmV, ymm2/m256","VPMINUD ymm2/m256, ymmV, ymm1","vpminud ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 3B /r","V","V","AVX2","","w,r,r","","" +"VPMINUD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPMINUD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpminud ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 3B /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPMINUD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPMINUD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpminud zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 3B /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPMINUQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMINUQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpminuq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 3B /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPMINUQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMINUQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpminuq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 3B /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPMINUQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMINUQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpminuq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 3B /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPMINUW xmm1, xmmV, xmm2/m128","VPMINUW xmm2/m128, xmmV, xmm1","vpminuw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 3A /r","V","V","AVX","","w,r,r","","" +"VPMINUW xmm1, {k}{z}, xmmV, xmm2/m128","VPMINUW xmm2/m128, xmmV, {k}{z}, xmm1","vpminuw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.WIG 3A /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMINUW ymm1, ymmV, ymm2/m256","VPMINUW ymm2/m256, ymmV, ymm1","vpminuw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 3A /r","V","V","AVX2","","w,r,r","","" +"VPMINUW ymm1, {k}{z}, ymmV, ymm2/m256","VPMINUW ymm2/m256, ymmV, {k}{z}, ymm1","vpminuw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.WIG 3A /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMINUW zmm1, {k}{z}, zmmV, zmm2/m512","VPMINUW zmm2/m512, zmmV, {k}{z}, zmm1","vpminuw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.WIG 3A /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMOVB2M k1, xmm2","VPMOVB2M xmm2, k1","vpmovb2m xmm2, k1","EVEX.128.F3.0F38.W0 29 /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r","","" +"VPMOVB2M k1, ymm2","VPMOVB2M ymm2, k1","vpmovb2m ymm2, k1","EVEX.256.F3.0F38.W0 29 /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r","","" +"VPMOVB2M k1, zmm2","VPMOVB2M zmm2, k1","vpmovb2m zmm2, k1","EVEX.512.F3.0F38.W0 29 /r","V","V","AVX512BW","modrm_regonly","w,r","","" +"VPMOVD2M k1, xmm2","VPMOVD2M xmm2, k1","vpmovd2m xmm2, k1","EVEX.128.F3.0F38.W0 39 /r","V","V","AVX512DQ+AVX512VL","modrm_regonly","w,r","","" +"VPMOVD2M k1, ymm2","VPMOVD2M ymm2, k1","vpmovd2m ymm2, k1","EVEX.256.F3.0F38.W0 39 /r","V","V","AVX512DQ+AVX512VL","modrm_regonly","w,r","","" +"VPMOVD2M k1, zmm2","VPMOVD2M zmm2, k1","vpmovd2m zmm2, k1","EVEX.512.F3.0F38.W0 39 /r","V","V","AVX512DQ","modrm_regonly","w,r","","" +"VPMOVDB xmm2/m32, {k}{z}, xmm1","VPMOVDB xmm1, {k}{z}, xmm2/m32","vpmovdb xmm1, {k}{z}, xmm2/m32","EVEX.128.F3.0F38.W0 31 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVDB xmm2/m64, {k}{z}, ymm1","VPMOVDB ymm1, {k}{z}, xmm2/m64","vpmovdb ymm1, {k}{z}, xmm2/m64","EVEX.256.F3.0F38.W0 31 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVDB xmm2/m128, {k}{z}, zmm1","VPMOVDB zmm1, {k}{z}, xmm2/m128","vpmovdb zmm1, {k}{z}, xmm2/m128","EVEX.512.F3.0F38.W0 31 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVDW xmm2/m64, {k}{z}, xmm1","VPMOVDW xmm1, {k}{z}, xmm2/m64","vpmovdw xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 33 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVDW xmm2/m128, {k}{z}, ymm1","VPMOVDW ymm1, {k}{z}, xmm2/m128","vpmovdw ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 33 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVDW ymm2/m256, {k}{z}, zmm1","VPMOVDW zmm1, {k}{z}, ymm2/m256","vpmovdw zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 33 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVM2B xmm1, k2","VPMOVM2B k2, xmm1","vpmovm2b k2, xmm1","EVEX.128.F3.0F38.W0 28 /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r","","" +"VPMOVM2B ymm1, k2","VPMOVM2B k2, ymm1","vpmovm2b k2, ymm1","EVEX.256.F3.0F38.W0 28 /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r","","" +"VPMOVM2B zmm1, k2","VPMOVM2B k2, zmm1","vpmovm2b k2, zmm1","EVEX.512.F3.0F38.W0 28 /r","V","V","AVX512BW","modrm_regonly","w,r","","" +"VPMOVM2D xmm1, k2","VPMOVM2D k2, xmm1","vpmovm2d k2, xmm1","EVEX.128.F3.0F38.W0 38 /r","V","V","AVX512DQ+AVX512VL","modrm_regonly","w,r","","" +"VPMOVM2D ymm1, k2","VPMOVM2D k2, ymm1","vpmovm2d k2, ymm1","EVEX.256.F3.0F38.W0 38 /r","V","V","AVX512DQ+AVX512VL","modrm_regonly","w,r","","" +"VPMOVM2D zmm1, k2","VPMOVM2D k2, zmm1","vpmovm2d k2, zmm1","EVEX.512.F3.0F38.W0 38 /r","V","V","AVX512DQ","modrm_regonly","w,r","","" +"VPMOVM2Q xmm1, k2","VPMOVM2Q k2, xmm1","vpmovm2q k2, xmm1","EVEX.128.F3.0F38.W1 38 /r","V","V","AVX512DQ+AVX512VL","modrm_regonly","w,r","","" +"VPMOVM2Q ymm1, k2","VPMOVM2Q k2, ymm1","vpmovm2q k2, ymm1","EVEX.256.F3.0F38.W1 38 /r","V","V","AVX512DQ+AVX512VL","modrm_regonly","w,r","","" +"VPMOVM2Q zmm1, k2","VPMOVM2Q k2, zmm1","vpmovm2q k2, zmm1","EVEX.512.F3.0F38.W1 38 /r","V","V","AVX512DQ","modrm_regonly","w,r","","" +"VPMOVM2W xmm1, k2","VPMOVM2W k2, xmm1","vpmovm2w k2, xmm1","EVEX.128.F3.0F38.W1 28 /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r","","" +"VPMOVM2W ymm1, k2","VPMOVM2W k2, ymm1","vpmovm2w k2, ymm1","EVEX.256.F3.0F38.W1 28 /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r","","" +"VPMOVM2W zmm1, k2","VPMOVM2W k2, zmm1","vpmovm2w k2, zmm1","EVEX.512.F3.0F38.W1 28 /r","V","V","AVX512BW","modrm_regonly","w,r","","" +"VPMOVMSKB r32, xmm2","VPMOVMSKB xmm2, r32","vpmovmskb xmm2, r32","VEX.128.66.0F.WIG D7 /r","V","V","AVX","modrm_regonly","w,r","","" +"VPMOVMSKB r32, ymm2","VPMOVMSKB ymm2, r32","vpmovmskb ymm2, r32","VEX.256.66.0F.WIG D7 /r","V","V","AVX2","modrm_regonly","w,r","","" +"VPMOVQ2M k1, xmm2","VPMOVQ2M xmm2, k1","vpmovq2m xmm2, k1","EVEX.128.F3.0F38.W1 39 /r","V","V","AVX512DQ+AVX512VL","modrm_regonly","w,r","","" +"VPMOVQ2M k1, ymm2","VPMOVQ2M ymm2, k1","vpmovq2m ymm2, k1","EVEX.256.F3.0F38.W1 39 /r","V","V","AVX512DQ+AVX512VL","modrm_regonly","w,r","","" +"VPMOVQ2M k1, zmm2","VPMOVQ2M zmm2, k1","vpmovq2m zmm2, k1","EVEX.512.F3.0F38.W1 39 /r","V","V","AVX512DQ","modrm_regonly","w,r","","" +"VPMOVQB xmm2/m16, {k}{z}, xmm1","VPMOVQB xmm1, {k}{z}, xmm2/m16","vpmovqb xmm1, {k}{z}, xmm2/m16","EVEX.128.F3.0F38.W0 32 /r","V","V","AVX512F+AVX512VL","scale2","w,r,r","","" +"VPMOVQB xmm2/m32, {k}{z}, ymm1","VPMOVQB ymm1, {k}{z}, xmm2/m32","vpmovqb ymm1, {k}{z}, xmm2/m32","EVEX.256.F3.0F38.W0 32 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVQB xmm2/m64, {k}{z}, zmm1","VPMOVQB zmm1, {k}{z}, xmm2/m64","vpmovqb zmm1, {k}{z}, xmm2/m64","EVEX.512.F3.0F38.W0 32 /r","V","V","AVX512F","scale8","w,r,r","","" +"VPMOVQD xmm2/m64, {k}{z}, xmm1","VPMOVQD xmm1, {k}{z}, xmm2/m64","vpmovqd xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 35 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVQD xmm2/m128, {k}{z}, ymm1","VPMOVQD ymm1, {k}{z}, xmm2/m128","vpmovqd ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 35 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVQD ymm2/m256, {k}{z}, zmm1","VPMOVQD zmm1, {k}{z}, ymm2/m256","vpmovqd zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 35 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVQW xmm2/m32, {k}{z}, xmm1","VPMOVQW xmm1, {k}{z}, xmm2/m32","vpmovqw xmm1, {k}{z}, xmm2/m32","EVEX.128.F3.0F38.W0 34 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVQW xmm2/m64, {k}{z}, ymm1","VPMOVQW ymm1, {k}{z}, xmm2/m64","vpmovqw ymm1, {k}{z}, xmm2/m64","EVEX.256.F3.0F38.W0 34 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVQW xmm2/m128, {k}{z}, zmm1","VPMOVQW zmm1, {k}{z}, xmm2/m128","vpmovqw zmm1, {k}{z}, xmm2/m128","EVEX.512.F3.0F38.W0 34 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVSDB xmm2/m32, {k}{z}, xmm1","VPMOVSDB xmm1, {k}{z}, xmm2/m32","vpmovsdb xmm1, {k}{z}, xmm2/m32","EVEX.128.F3.0F38.W0 21 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVSDB xmm2/m64, {k}{z}, ymm1","VPMOVSDB ymm1, {k}{z}, xmm2/m64","vpmovsdb ymm1, {k}{z}, xmm2/m64","EVEX.256.F3.0F38.W0 21 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVSDB xmm2/m128, {k}{z}, zmm1","VPMOVSDB zmm1, {k}{z}, xmm2/m128","vpmovsdb zmm1, {k}{z}, xmm2/m128","EVEX.512.F3.0F38.W0 21 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVSDW xmm2/m64, {k}{z}, xmm1","VPMOVSDW xmm1, {k}{z}, xmm2/m64","vpmovsdw xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 23 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVSDW xmm2/m128, {k}{z}, ymm1","VPMOVSDW ymm1, {k}{z}, xmm2/m128","vpmovsdw ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 23 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVSDW ymm2/m256, {k}{z}, zmm1","VPMOVSDW zmm1, {k}{z}, ymm2/m256","vpmovsdw zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 23 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVSQB xmm2/m16, {k}{z}, xmm1","VPMOVSQB xmm1, {k}{z}, xmm2/m16","vpmovsqb xmm1, {k}{z}, xmm2/m16","EVEX.128.F3.0F38.W0 22 /r","V","V","AVX512F+AVX512VL","scale2","w,r,r","","" +"VPMOVSQB xmm2/m32, {k}{z}, ymm1","VPMOVSQB ymm1, {k}{z}, xmm2/m32","vpmovsqb ymm1, {k}{z}, xmm2/m32","EVEX.256.F3.0F38.W0 22 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVSQB xmm2/m64, {k}{z}, zmm1","VPMOVSQB zmm1, {k}{z}, xmm2/m64","vpmovsqb zmm1, {k}{z}, xmm2/m64","EVEX.512.F3.0F38.W0 22 /r","V","V","AVX512F","scale8","w,r,r","","" +"VPMOVSQD xmm2/m64, {k}{z}, xmm1","VPMOVSQD xmm1, {k}{z}, xmm2/m64","vpmovsqd xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 25 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVSQD xmm2/m128, {k}{z}, ymm1","VPMOVSQD ymm1, {k}{z}, xmm2/m128","vpmovsqd ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 25 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVSQD ymm2/m256, {k}{z}, zmm1","VPMOVSQD zmm1, {k}{z}, ymm2/m256","vpmovsqd zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 25 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVSQW xmm2/m32, {k}{z}, xmm1","VPMOVSQW xmm1, {k}{z}, xmm2/m32","vpmovsqw xmm1, {k}{z}, xmm2/m32","EVEX.128.F3.0F38.W0 24 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVSQW xmm2/m64, {k}{z}, ymm1","VPMOVSQW ymm1, {k}{z}, xmm2/m64","vpmovsqw ymm1, {k}{z}, xmm2/m64","EVEX.256.F3.0F38.W0 24 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVSQW xmm2/m128, {k}{z}, zmm1","VPMOVSQW zmm1, {k}{z}, xmm2/m128","vpmovsqw zmm1, {k}{z}, xmm2/m128","EVEX.512.F3.0F38.W0 24 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVSWB xmm2/m64, {k}{z}, xmm1","VPMOVSWB xmm1, {k}{z}, xmm2/m64","vpmovswb xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 20 /r","V","V","AVX512BW+AVX512VL","scale8","w,r,r","","" +"VPMOVSWB xmm2/m128, {k}{z}, ymm1","VPMOVSWB ymm1, {k}{z}, xmm2/m128","vpmovswb ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 20 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPMOVSWB ymm2/m256, {k}{z}, zmm1","VPMOVSWB zmm1, {k}{z}, ymm2/m256","vpmovswb zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 20 /r","V","V","AVX512BW","scale32","w,r,r","","" +"VPMOVSXBD zmm1, {k}{z}, xmm2/m128","VPMOVSXBD xmm2/m128, {k}{z}, zmm1","vpmovsxbd xmm2/m128, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 21 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVSXBD xmm1, xmm2/m32","VPMOVSXBD xmm2/m32, xmm1","vpmovsxbd xmm2/m32, xmm1","VEX.128.66.0F38.WIG 21 /r","V","V","AVX","","w,r","","" +"VPMOVSXBD xmm1, {k}{z}, xmm2/m32","VPMOVSXBD xmm2/m32, {k}{z}, xmm1","vpmovsxbd xmm2/m32, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 21 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVSXBD ymm1, xmm2/m64","VPMOVSXBD xmm2/m64, ymm1","vpmovsxbd xmm2/m64, ymm1","VEX.256.66.0F38.WIG 21 /r","V","V","AVX2","","w,r","","" +"VPMOVSXBD ymm1, {k}{z}, xmm2/m64","VPMOVSXBD xmm2/m64, {k}{z}, ymm1","vpmovsxbd xmm2/m64, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 21 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVSXBQ xmm1, xmm2/m16","VPMOVSXBQ xmm2/m16, xmm1","vpmovsxbq xmm2/m16, xmm1","VEX.128.66.0F38.WIG 22 /r","V","V","AVX","","w,r","","" +"VPMOVSXBQ xmm1, {k}{z}, xmm2/m16","VPMOVSXBQ xmm2/m16, {k}{z}, xmm1","vpmovsxbq xmm2/m16, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 22 /r","V","V","AVX512F+AVX512VL","scale2","w,r,r","","" +"VPMOVSXBQ ymm1, xmm2/m32","VPMOVSXBQ xmm2/m32, ymm1","vpmovsxbq xmm2/m32, ymm1","VEX.256.66.0F38.WIG 22 /r","V","V","AVX2","","w,r","","" +"VPMOVSXBQ ymm1, {k}{z}, xmm2/m32","VPMOVSXBQ xmm2/m32, {k}{z}, ymm1","vpmovsxbq xmm2/m32, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 22 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVSXBQ zmm1, {k}{z}, xmm2/m64","VPMOVSXBQ xmm2/m64, {k}{z}, zmm1","vpmovsxbq xmm2/m64, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 22 /r","V","V","AVX512F","scale8","w,r,r","","" +"VPMOVSXBW ymm1, xmm2/m128","VPMOVSXBW xmm2/m128, ymm1","vpmovsxbw xmm2/m128, ymm1","VEX.256.66.0F38.WIG 20 /r","V","V","AVX2","","w,r","","" +"VPMOVSXBW ymm1, {k}{z}, xmm2/m128","VPMOVSXBW xmm2/m128, {k}{z}, ymm1","vpmovsxbw xmm2/m128, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 20 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPMOVSXBW xmm1, xmm2/m64","VPMOVSXBW xmm2/m64, xmm1","vpmovsxbw xmm2/m64, xmm1","VEX.128.66.0F38.WIG 20 /r","V","V","AVX","","w,r","","" +"VPMOVSXBW xmm1, {k}{z}, xmm2/m64","VPMOVSXBW xmm2/m64, {k}{z}, xmm1","vpmovsxbw xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 20 /r","V","V","AVX512BW+AVX512VL","scale8","w,r,r","","" +"VPMOVSXBW zmm1, {k}{z}, ymm2/m256","VPMOVSXBW ymm2/m256, {k}{z}, zmm1","vpmovsxbw ymm2/m256, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 20 /r","V","V","AVX512BW","scale32","w,r,r","","" +"VPMOVSXDQ ymm1, xmm2/m128","VPMOVSXDQ xmm2/m128, ymm1","vpmovsxdq xmm2/m128, ymm1","VEX.256.66.0F38.WIG 25 /r","V","V","AVX2","","w,r","","" +"VPMOVSXDQ ymm1, {k}{z}, xmm2/m128","VPMOVSXDQ xmm2/m128, {k}{z}, ymm1","vpmovsxdq xmm2/m128, {k}{z}, ymm1","EVEX.256.66.0F38.W0 25 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVSXDQ xmm1, xmm2/m64","VPMOVSXDQ xmm2/m64, xmm1","vpmovsxdq xmm2/m64, xmm1","VEX.128.66.0F38.WIG 25 /r","V","V","AVX","","w,r","","" +"VPMOVSXDQ xmm1, {k}{z}, xmm2/m64","VPMOVSXDQ xmm2/m64, {k}{z}, xmm1","vpmovsxdq xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.W0 25 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVSXDQ zmm1, {k}{z}, ymm2/m256","VPMOVSXDQ ymm2/m256, {k}{z}, zmm1","vpmovsxdq ymm2/m256, {k}{z}, zmm1","EVEX.512.66.0F38.W0 25 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVSXWD ymm1, xmm2/m128","VPMOVSXWD xmm2/m128, ymm1","vpmovsxwd xmm2/m128, ymm1","VEX.256.66.0F38.WIG 23 /r","V","V","AVX2","","w,r","","" +"VPMOVSXWD ymm1, {k}{z}, xmm2/m128","VPMOVSXWD xmm2/m128, {k}{z}, ymm1","vpmovsxwd xmm2/m128, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 23 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVSXWD xmm1, xmm2/m64","VPMOVSXWD xmm2/m64, xmm1","vpmovsxwd xmm2/m64, xmm1","VEX.128.66.0F38.WIG 23 /r","V","V","AVX","","w,r","","" +"VPMOVSXWD xmm1, {k}{z}, xmm2/m64","VPMOVSXWD xmm2/m64, {k}{z}, xmm1","vpmovsxwd xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 23 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVSXWD zmm1, {k}{z}, ymm2/m256","VPMOVSXWD ymm2/m256, {k}{z}, zmm1","vpmovsxwd ymm2/m256, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 23 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVSXWQ zmm1, {k}{z}, xmm2/m128","VPMOVSXWQ xmm2/m128, {k}{z}, zmm1","vpmovsxwq xmm2/m128, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 24 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVSXWQ xmm1, xmm2/m32","VPMOVSXWQ xmm2/m32, xmm1","vpmovsxwq xmm2/m32, xmm1","VEX.128.66.0F38.WIG 24 /r","V","V","AVX","","w,r","","" +"VPMOVSXWQ xmm1, {k}{z}, xmm2/m32","VPMOVSXWQ xmm2/m32, {k}{z}, xmm1","vpmovsxwq xmm2/m32, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 24 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVSXWQ ymm1, xmm2/m64","VPMOVSXWQ xmm2/m64, ymm1","vpmovsxwq xmm2/m64, ymm1","VEX.256.66.0F38.WIG 24 /r","V","V","AVX2","","w,r","","" +"VPMOVSXWQ ymm1, {k}{z}, xmm2/m64","VPMOVSXWQ xmm2/m64, {k}{z}, ymm1","vpmovsxwq xmm2/m64, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 24 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVUSDB xmm2/m32, {k}{z}, xmm1","VPMOVUSDB xmm1, {k}{z}, xmm2/m32","vpmovusdb xmm1, {k}{z}, xmm2/m32","EVEX.128.F3.0F38.W0 11 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVUSDB xmm2/m64, {k}{z}, ymm1","VPMOVUSDB ymm1, {k}{z}, xmm2/m64","vpmovusdb ymm1, {k}{z}, xmm2/m64","EVEX.256.F3.0F38.W0 11 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVUSDB xmm2/m128, {k}{z}, zmm1","VPMOVUSDB zmm1, {k}{z}, xmm2/m128","vpmovusdb zmm1, {k}{z}, xmm2/m128","EVEX.512.F3.0F38.W0 11 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVUSDW xmm2/m64, {k}{z}, xmm1","VPMOVUSDW xmm1, {k}{z}, xmm2/m64","vpmovusdw xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 13 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVUSDW xmm2/m128, {k}{z}, ymm1","VPMOVUSDW ymm1, {k}{z}, xmm2/m128","vpmovusdw ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 13 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVUSDW ymm2/m256, {k}{z}, zmm1","VPMOVUSDW zmm1, {k}{z}, ymm2/m256","vpmovusdw zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 13 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVUSQB xmm2/m16, {k}{z}, xmm1","VPMOVUSQB xmm1, {k}{z}, xmm2/m16","vpmovusqb xmm1, {k}{z}, xmm2/m16","EVEX.128.F3.0F38.W0 12 /r","V","V","AVX512F+AVX512VL","scale2","w,r,r","","" +"VPMOVUSQB xmm2/m32, {k}{z}, ymm1","VPMOVUSQB ymm1, {k}{z}, xmm2/m32","vpmovusqb ymm1, {k}{z}, xmm2/m32","EVEX.256.F3.0F38.W0 12 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVUSQB xmm2/m64, {k}{z}, zmm1","VPMOVUSQB zmm1, {k}{z}, xmm2/m64","vpmovusqb zmm1, {k}{z}, xmm2/m64","EVEX.512.F3.0F38.W0 12 /r","V","V","AVX512F","scale8","w,r,r","","" +"VPMOVUSQD xmm2/m64, {k}{z}, xmm1","VPMOVUSQD xmm1, {k}{z}, xmm2/m64","vpmovusqd xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 15 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVUSQD xmm2/m128, {k}{z}, ymm1","VPMOVUSQD ymm1, {k}{z}, xmm2/m128","vpmovusqd ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 15 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVUSQD ymm2/m256, {k}{z}, zmm1","VPMOVUSQD zmm1, {k}{z}, ymm2/m256","vpmovusqd zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 15 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVUSQW xmm2/m32, {k}{z}, xmm1","VPMOVUSQW xmm1, {k}{z}, xmm2/m32","vpmovusqw xmm1, {k}{z}, xmm2/m32","EVEX.128.F3.0F38.W0 14 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVUSQW xmm2/m64, {k}{z}, ymm1","VPMOVUSQW ymm1, {k}{z}, xmm2/m64","vpmovusqw ymm1, {k}{z}, xmm2/m64","EVEX.256.F3.0F38.W0 14 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVUSQW xmm2/m128, {k}{z}, zmm1","VPMOVUSQW zmm1, {k}{z}, xmm2/m128","vpmovusqw zmm1, {k}{z}, xmm2/m128","EVEX.512.F3.0F38.W0 14 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVUSWB xmm2/m64, {k}{z}, xmm1","VPMOVUSWB xmm1, {k}{z}, xmm2/m64","vpmovuswb xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 10 /r","V","V","AVX512BW+AVX512VL","scale8","w,r,r","","" +"VPMOVUSWB xmm2/m128, {k}{z}, ymm1","VPMOVUSWB ymm1, {k}{z}, xmm2/m128","vpmovuswb ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 10 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPMOVUSWB ymm2/m256, {k}{z}, zmm1","VPMOVUSWB zmm1, {k}{z}, ymm2/m256","vpmovuswb zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 10 /r","V","V","AVX512BW","scale32","w,r,r","","" +"VPMOVW2M k1, xmm2","VPMOVW2M xmm2, k1","vpmovw2m xmm2, k1","EVEX.128.F3.0F38.W1 29 /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r","","" +"VPMOVW2M k1, ymm2","VPMOVW2M ymm2, k1","vpmovw2m ymm2, k1","EVEX.256.F3.0F38.W1 29 /r","V","V","AVX512BW+AVX512VL","modrm_regonly","w,r","","" +"VPMOVW2M k1, zmm2","VPMOVW2M zmm2, k1","vpmovw2m zmm2, k1","EVEX.512.F3.0F38.W1 29 /r","V","V","AVX512BW","modrm_regonly","w,r","","" +"VPMOVWB xmm2/m64, {k}{z}, xmm1","VPMOVWB xmm1, {k}{z}, xmm2/m64","vpmovwb xmm1, {k}{z}, xmm2/m64","EVEX.128.F3.0F38.W0 30 /r","V","V","AVX512BW+AVX512VL","scale8","w,r,r","","" +"VPMOVWB xmm2/m128, {k}{z}, ymm1","VPMOVWB ymm1, {k}{z}, xmm2/m128","vpmovwb ymm1, {k}{z}, xmm2/m128","EVEX.256.F3.0F38.W0 30 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPMOVWB ymm2/m256, {k}{z}, zmm1","VPMOVWB zmm1, {k}{z}, ymm2/m256","vpmovwb zmm1, {k}{z}, ymm2/m256","EVEX.512.F3.0F38.W0 30 /r","V","V","AVX512BW","scale32","w,r,r","","" +"VPMOVZXBD zmm1, {k}{z}, xmm2/m128","VPMOVZXBD xmm2/m128, {k}{z}, zmm1","vpmovzxbd xmm2/m128, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 31 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVZXBD xmm1, xmm2/m32","VPMOVZXBD xmm2/m32, xmm1","vpmovzxbd xmm2/m32, xmm1","VEX.128.66.0F38.WIG 31 /r","V","V","AVX","","w,r","","" +"VPMOVZXBD xmm1, {k}{z}, xmm2/m32","VPMOVZXBD xmm2/m32, {k}{z}, xmm1","vpmovzxbd xmm2/m32, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 31 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVZXBD ymm1, xmm2/m64","VPMOVZXBD xmm2/m64, ymm1","vpmovzxbd xmm2/m64, ymm1","VEX.256.66.0F38.WIG 31 /r","V","V","AVX2","","w,r","","" +"VPMOVZXBD ymm1, {k}{z}, xmm2/m64","VPMOVZXBD xmm2/m64, {k}{z}, ymm1","vpmovzxbd xmm2/m64, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 31 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVZXBQ xmm1, xmm2/m16","VPMOVZXBQ xmm2/m16, xmm1","vpmovzxbq xmm2/m16, xmm1","VEX.128.66.0F38.WIG 32 /r","V","V","AVX","","w,r","","" +"VPMOVZXBQ xmm1, {k}{z}, xmm2/m16","VPMOVZXBQ xmm2/m16, {k}{z}, xmm1","vpmovzxbq xmm2/m16, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 32 /r","V","V","AVX512F+AVX512VL","scale2","w,r,r","","" +"VPMOVZXBQ ymm1, xmm2/m32","VPMOVZXBQ xmm2/m32, ymm1","vpmovzxbq xmm2/m32, ymm1","VEX.256.66.0F38.WIG 32 /r","V","V","AVX2","","w,r","","" +"VPMOVZXBQ ymm1, {k}{z}, xmm2/m32","VPMOVZXBQ xmm2/m32, {k}{z}, ymm1","vpmovzxbq xmm2/m32, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 32 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVZXBQ zmm1, {k}{z}, xmm2/m64","VPMOVZXBQ xmm2/m64, {k}{z}, zmm1","vpmovzxbq xmm2/m64, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 32 /r","V","V","AVX512F","scale8","w,r,r","","" +"VPMOVZXBW ymm1, xmm2/m128","VPMOVZXBW xmm2/m128, ymm1","vpmovzxbw xmm2/m128, ymm1","VEX.256.66.0F38.WIG 30 /r","V","V","AVX2","","w,r","","" +"VPMOVZXBW ymm1, {k}{z}, xmm2/m128","VPMOVZXBW xmm2/m128, {k}{z}, ymm1","vpmovzxbw xmm2/m128, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 30 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPMOVZXBW xmm1, xmm2/m64","VPMOVZXBW xmm2/m64, xmm1","vpmovzxbw xmm2/m64, xmm1","VEX.128.66.0F38.WIG 30 /r","V","V","AVX","","w,r","","" +"VPMOVZXBW xmm1, {k}{z}, xmm2/m64","VPMOVZXBW xmm2/m64, {k}{z}, xmm1","vpmovzxbw xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 30 /r","V","V","AVX512BW+AVX512VL","scale8","w,r,r","","" +"VPMOVZXBW zmm1, {k}{z}, ymm2/m256","VPMOVZXBW ymm2/m256, {k}{z}, zmm1","vpmovzxbw ymm2/m256, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 30 /r","V","V","AVX512BW","scale32","w,r,r","","" +"VPMOVZXDQ ymm1, xmm2/m128","VPMOVZXDQ xmm2/m128, ymm1","vpmovzxdq xmm2/m128, ymm1","VEX.256.66.0F38.WIG 35 /r","V","V","AVX2","","w,r","","" +"VPMOVZXDQ ymm1, {k}{z}, xmm2/m128","VPMOVZXDQ xmm2/m128, {k}{z}, ymm1","vpmovzxdq xmm2/m128, {k}{z}, ymm1","EVEX.256.66.0F38.W0 35 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVZXDQ xmm1, xmm2/m64","VPMOVZXDQ xmm2/m64, xmm1","vpmovzxdq xmm2/m64, xmm1","VEX.128.66.0F38.WIG 35 /r","V","V","AVX","","w,r","","" +"VPMOVZXDQ xmm1, {k}{z}, xmm2/m64","VPMOVZXDQ xmm2/m64, {k}{z}, xmm1","vpmovzxdq xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.W0 35 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVZXDQ zmm1, {k}{z}, ymm2/m256","VPMOVZXDQ ymm2/m256, {k}{z}, zmm1","vpmovzxdq ymm2/m256, {k}{z}, zmm1","EVEX.512.66.0F38.W0 35 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVZXWD ymm1, xmm2/m128","VPMOVZXWD xmm2/m128, ymm1","vpmovzxwd xmm2/m128, ymm1","VEX.256.66.0F38.WIG 33 /r","V","V","AVX2","","w,r","","" +"VPMOVZXWD ymm1, {k}{z}, xmm2/m128","VPMOVZXWD xmm2/m128, {k}{z}, ymm1","vpmovzxwd xmm2/m128, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 33 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r","","" +"VPMOVZXWD xmm1, xmm2/m64","VPMOVZXWD xmm2/m64, xmm1","vpmovzxwd xmm2/m64, xmm1","VEX.128.66.0F38.WIG 33 /r","V","V","AVX","","w,r","","" +"VPMOVZXWD xmm1, {k}{z}, xmm2/m64","VPMOVZXWD xmm2/m64, {k}{z}, xmm1","vpmovzxwd xmm2/m64, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 33 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMOVZXWD zmm1, {k}{z}, ymm2/m256","VPMOVZXWD ymm2/m256, {k}{z}, zmm1","vpmovzxwd ymm2/m256, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 33 /r","V","V","AVX512F","scale32","w,r,r","","" +"VPMOVZXWQ zmm1, {k}{z}, xmm2/m128","VPMOVZXWQ xmm2/m128, {k}{z}, zmm1","vpmovzxwq xmm2/m128, {k}{z}, zmm1","EVEX.512.66.0F38.WIG 34 /r","V","V","AVX512F","scale16","w,r,r","","" +"VPMOVZXWQ xmm1, xmm2/m32","VPMOVZXWQ xmm2/m32, xmm1","vpmovzxwq xmm2/m32, xmm1","VEX.128.66.0F38.WIG 34 /r","V","V","AVX","","w,r","","" +"VPMOVZXWQ xmm1, {k}{z}, xmm2/m32","VPMOVZXWQ xmm2/m32, {k}{z}, xmm1","vpmovzxwq xmm2/m32, {k}{z}, xmm1","EVEX.128.66.0F38.WIG 34 /r","V","V","AVX512F+AVX512VL","scale4","w,r,r","","" +"VPMOVZXWQ ymm1, xmm2/m64","VPMOVZXWQ xmm2/m64, ymm1","vpmovzxwq xmm2/m64, ymm1","VEX.256.66.0F38.WIG 34 /r","V","V","AVX2","","w,r","","" +"VPMOVZXWQ ymm1, {k}{z}, xmm2/m64","VPMOVZXWQ xmm2/m64, {k}{z}, ymm1","vpmovzxwq xmm2/m64, {k}{z}, ymm1","EVEX.256.66.0F38.WIG 34 /r","V","V","AVX512F+AVX512VL","scale8","w,r,r","","" +"VPMULDQ xmm1, xmmV, xmm2/m128","VPMULDQ xmm2/m128, xmmV, xmm1","vpmuldq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 28 /r","V","V","AVX","","w,r,r","","" +"VPMULDQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMULDQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpmuldq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 28 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPMULDQ ymm1, ymmV, ymm2/m256","VPMULDQ ymm2/m256, ymmV, ymm1","vpmuldq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 28 /r","V","V","AVX2","","w,r,r","","" +"VPMULDQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMULDQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpmuldq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 28 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPMULDQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMULDQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpmuldq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 28 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPMULHRSW xmm1, xmmV, xmm2/m128","VPMULHRSW xmm2/m128, xmmV, xmm1","vpmulhrsw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 0B /r","V","V","AVX","","w,r,r","","" +"VPMULHRSW xmm1, {k}{z}, xmmV, xmm2/m128","VPMULHRSW xmm2/m128, xmmV, {k}{z}, xmm1","vpmulhrsw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.WIG 0B /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMULHRSW ymm1, ymmV, ymm2/m256","VPMULHRSW ymm2/m256, ymmV, ymm1","vpmulhrsw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 0B /r","V","V","AVX2","","w,r,r","","" +"VPMULHRSW ymm1, {k}{z}, ymmV, ymm2/m256","VPMULHRSW ymm2/m256, ymmV, {k}{z}, ymm1","vpmulhrsw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.WIG 0B /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMULHRSW zmm1, {k}{z}, zmmV, zmm2/m512","VPMULHRSW zmm2/m512, zmmV, {k}{z}, zmm1","vpmulhrsw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.WIG 0B /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMULHUW xmm1, xmmV, xmm2/m128","VPMULHUW xmm2/m128, xmmV, xmm1","vpmulhuw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG E4 /r","V","V","AVX","","w,r,r","","" +"VPMULHUW xmm1, {k}{z}, xmmV, xmm2/m128","VPMULHUW xmm2/m128, xmmV, {k}{z}, xmm1","vpmulhuw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG E4 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMULHUW ymm1, ymmV, ymm2/m256","VPMULHUW ymm2/m256, ymmV, ymm1","vpmulhuw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG E4 /r","V","V","AVX2","","w,r,r","","" +"VPMULHUW ymm1, {k}{z}, ymmV, ymm2/m256","VPMULHUW ymm2/m256, ymmV, {k}{z}, ymm1","vpmulhuw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG E4 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMULHUW zmm1, {k}{z}, zmmV, zmm2/m512","VPMULHUW zmm2/m512, zmmV, {k}{z}, zmm1","vpmulhuw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG E4 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMULHW xmm1, xmmV, xmm2/m128","VPMULHW xmm2/m128, xmmV, xmm1","vpmulhw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG E5 /r","V","V","AVX","","w,r,r","","" +"VPMULHW xmm1, {k}{z}, xmmV, xmm2/m128","VPMULHW xmm2/m128, xmmV, {k}{z}, xmm1","vpmulhw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG E5 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMULHW ymm1, ymmV, ymm2/m256","VPMULHW ymm2/m256, ymmV, ymm1","vpmulhw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG E5 /r","V","V","AVX2","","w,r,r","","" +"VPMULHW ymm1, {k}{z}, ymmV, ymm2/m256","VPMULHW ymm2/m256, ymmV, {k}{z}, ymm1","vpmulhw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG E5 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMULHW zmm1, {k}{z}, zmmV, zmm2/m512","VPMULHW zmm2/m512, zmmV, {k}{z}, zmm1","vpmulhw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG E5 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMULLD xmm1, xmmV, xmm2/m128","VPMULLD xmm2/m128, xmmV, xmm1","vpmulld xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 40 /r","V","V","AVX","","w,r,r","","" +"VPMULLD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPMULLD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpmulld xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 40 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPMULLD ymm1, ymmV, ymm2/m256","VPMULLD ymm2/m256, ymmV, ymm1","vpmulld ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 40 /r","V","V","AVX2","","w,r,r","","" +"VPMULLD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPMULLD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpmulld ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 40 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPMULLD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPMULLD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpmulld zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 40 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPMULLQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMULLQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpmullq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 40 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPMULLQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMULLQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpmullq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 40 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPMULLQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMULLQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpmullq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 40 /r","V","V","AVX512DQ","bscale8,scale64","w,r,r,r","","" +"VPMULLW xmm1, xmmV, xmm2/m128","VPMULLW xmm2/m128, xmmV, xmm1","vpmullw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG D5 /r","V","V","AVX","","w,r,r","","" +"VPMULLW xmm1, {k}{z}, xmmV, xmm2/m128","VPMULLW xmm2/m128, xmmV, {k}{z}, xmm1","vpmullw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG D5 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPMULLW ymm1, ymmV, ymm2/m256","VPMULLW ymm2/m256, ymmV, ymm1","vpmullw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG D5 /r","V","V","AVX2","","w,r,r","","" +"VPMULLW ymm1, {k}{z}, ymmV, ymm2/m256","VPMULLW ymm2/m256, ymmV, {k}{z}, ymm1","vpmullw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG D5 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPMULLW zmm1, {k}{z}, zmmV, zmm2/m512","VPMULLW zmm2/m512, zmmV, {k}{z}, zmm1","vpmullw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG D5 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPMULTISHIFTQB xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMULTISHIFTQB xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpmultishiftqb xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 83 /r","V","V","AVX512_VBMI+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPMULTISHIFTQB ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMULTISHIFTQB ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpmultishiftqb ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 83 /r","V","V","AVX512_VBMI+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPMULTISHIFTQB zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMULTISHIFTQB zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpmultishiftqb zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 83 /r","V","V","AVX512_VBMI","bscale8,scale64","w,r,r,r","","" +"VPMULUDQ xmm1, xmmV, xmm2/m128","VPMULUDQ xmm2/m128, xmmV, xmm1","vpmuludq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG F4 /r","V","V","AVX","","w,r,r","","" +"VPMULUDQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPMULUDQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpmuludq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 F4 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPMULUDQ ymm1, ymmV, ymm2/m256","VPMULUDQ ymm2/m256, ymmV, ymm1","vpmuludq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG F4 /r","V","V","AVX2","","w,r,r","","" +"VPMULUDQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPMULUDQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpmuludq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 F4 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPMULUDQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPMULUDQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpmuludq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 F4 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPOPCNTB xmm1, {k}{z}, xmm2/m128","VPOPCNTB xmm2/m128, {k}{z}, xmm1","vpopcntb xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.W0 54 /r","V","V","AVX512_BITALG+AVX512VL","scale16","w,r,r","","" +"VPOPCNTB ymm1, {k}{z}, ymm2/m256","VPOPCNTB ymm2/m256, {k}{z}, ymm1","vpopcntb ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.W0 54 /r","V","V","AVX512_BITALG+AVX512VL","scale32","w,r,r","","" +"VPOPCNTB zmm1, {k}{z}, zmm2/m512","VPOPCNTB zmm2/m512, {k}{z}, zmm1","vpopcntb zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.W0 54 /r","V","V","AVX512_BITALG","scale64","w,r,r","","" +"VPOPCNTD xmm1, {k}{z}, xmm2/m128/m32bcst","VPOPCNTD xmm2/m128/m32bcst, {k}{z}, xmm1","vpopcntd xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W0 55 /r","V","V","AVX512_VPOPCNTDQ+AVX512VL","bscale4,scale16","w,r,r","","" +"VPOPCNTD ymm1, {k}{z}, ymm2/m256/m32bcst","VPOPCNTD ymm2/m256/m32bcst, {k}{z}, ymm1","vpopcntd ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W0 55 /r","V","V","AVX512_VPOPCNTDQ+AVX512VL","bscale4,scale32","w,r,r","","" +"VPOPCNTD zmm1, {k}{z}, zmm2/m512/m32bcst","VPOPCNTD zmm2/m512/m32bcst, {k}{z}, zmm1","vpopcntd zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 55 /r","V","V","AVX512_VPOPCNTDQ","bscale4,scale64","w,r,r","","" +"VPOPCNTQ xmm1, {k}{z}, xmm2/m128/m64bcst","VPOPCNTQ xmm2/m128/m64bcst, {k}{z}, xmm1","vpopcntq xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W1 55 /r","V","V","AVX512_VPOPCNTDQ+AVX512VL","bscale8,scale16","w,r,r","","" +"VPOPCNTQ ymm1, {k}{z}, ymm2/m256/m64bcst","VPOPCNTQ ymm2/m256/m64bcst, {k}{z}, ymm1","vpopcntq ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W1 55 /r","V","V","AVX512_VPOPCNTDQ+AVX512VL","bscale8,scale32","w,r,r","","" +"VPOPCNTQ zmm1, {k}{z}, zmm2/m512/m64bcst","VPOPCNTQ zmm2/m512/m64bcst, {k}{z}, zmm1","vpopcntq zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 55 /r","V","V","AVX512_VPOPCNTDQ","bscale8,scale64","w,r,r","","" +"VPOPCNTW xmm1, {k}{z}, xmm2/m128","VPOPCNTW xmm2/m128, {k}{z}, xmm1","vpopcntw xmm2/m128, {k}{z}, xmm1","EVEX.128.66.0F38.W1 54 /r","V","V","AVX512_BITALG+AVX512VL","scale16","w,r,r","","" +"VPOPCNTW ymm1, {k}{z}, ymm2/m256","VPOPCNTW ymm2/m256, {k}{z}, ymm1","vpopcntw ymm2/m256, {k}{z}, ymm1","EVEX.256.66.0F38.W1 54 /r","V","V","AVX512_BITALG+AVX512VL","scale32","w,r,r","","" +"VPOPCNTW zmm1, {k}{z}, zmm2/m512","VPOPCNTW zmm2/m512, {k}{z}, zmm1","vpopcntw zmm2/m512, {k}{z}, zmm1","EVEX.512.66.0F38.W1 54 /r","V","V","AVX512_BITALG","scale64","w,r,r","","" +"VPOR xmm1, xmmV, xmm2/m128","VPOR xmm2/m128, xmmV, xmm1","vpor xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG EB /r","V","V","AVX","","w,r,r","","" +"VPOR ymm1, ymmV, ymm2/m256","VPOR ymm2/m256, ymmV, ymm1","vpor ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG EB /r","V","V","AVX2","","w,r,r","","" +"VPORD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPORD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpord xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 EB /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPORD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPORD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpord ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 EB /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPORD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPORD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpord zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 EB /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPORQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPORQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vporq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 EB /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPORQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPORQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vporq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 EB /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPORQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPORQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vporq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 EB /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPPERM xmm1, xmmV, xmmIH, xmm2/m128","VPPERM xmm2/m128, xmmIH, xmmV, xmm1","vpperm xmm2/m128, xmmIH, xmmV, xmm1","XOP.NDS.128.08.W1 A3 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPPERM xmm1, xmmV, xmm2/m128, xmmIH","VPPERM xmmIH, xmm2/m128, xmmV, xmm1","vpperm xmmIH, xmm2/m128, xmmV, xmm1","XOP.NDS.128.08.W0 A3 /r /is4","V","V","XOP","amd","w,r,r,r","","" +"VPROLD xmmV, {k}{z}, xmm2/m128/m32bcst, imm8u","VPROLD imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","vprold imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W0 72 /1 ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPROLD ymmV, {k}{z}, ymm2/m256/m32bcst, imm8u","VPROLD imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","vprold imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W0 72 /1 ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPROLD zmmV, {k}{z}, zmm2/m512/m32bcst, imm8u","VPROLD imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","vprold imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W0 72 /1 ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPROLQ xmmV, {k}{z}, xmm2/m128/m64bcst, imm8u","VPROLQ imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","vprolq imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W1 72 /1 ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPROLQ ymmV, {k}{z}, ymm2/m256/m64bcst, imm8u","VPROLQ imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","vprolq imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W1 72 /1 ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPROLQ zmmV, {k}{z}, zmm2/m512/m64bcst, imm8u","VPROLQ imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","vprolq imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W1 72 /1 ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPROLVD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPROLVD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vprolvd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 15 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPROLVD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPROLVD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vprolvd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 15 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPROLVD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPROLVD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vprolvd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 15 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPROLVQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPROLVQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vprolvq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 15 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPROLVQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPROLVQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vprolvq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 15 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPROLVQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPROLVQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vprolvq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 15 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPRORD xmmV, {k}{z}, xmm2/m128/m32bcst, imm8u","VPRORD imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","vprord imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W0 72 /0 ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPRORD ymmV, {k}{z}, ymm2/m256/m32bcst, imm8u","VPRORD imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","vprord imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W0 72 /0 ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPRORD zmmV, {k}{z}, zmm2/m512/m32bcst, imm8u","VPRORD imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","vprord imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W0 72 /0 ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPRORQ xmmV, {k}{z}, xmm2/m128/m64bcst, imm8u","VPRORQ imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","vprorq imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W1 72 /0 ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPRORQ ymmV, {k}{z}, ymm2/m256/m64bcst, imm8u","VPRORQ imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","vprorq imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W1 72 /0 ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPRORQ zmmV, {k}{z}, zmm2/m512/m64bcst, imm8u","VPRORQ imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","vprorq imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W1 72 /0 ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPRORVD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPRORVD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vprorvd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 14 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPRORVD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPRORVD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vprorvd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 14 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPRORVD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPRORVD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vprorvd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 14 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPRORVQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPRORVQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vprorvq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 14 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPRORVQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPRORVQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vprorvq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 14 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPRORVQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPRORVQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vprorvq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 14 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPROTB xmm1, xmm2/m128, imm8u","VPROTB imm8u, xmm2/m128, xmm1","vprotb imm8u, xmm2/m128, xmm1","XOP.128.08.W0 C0 /r ib","V","V","XOP","amd","w,r,r","","" +"VPROTB xmm1, xmmV, xmm2/m128","VPROTB xmm2/m128, xmmV, xmm1","vprotb xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 90 /r","V","V","XOP","amd","w,r,r","","" +"VPROTB xmm1, xmm2/m128, xmmV","VPROTB xmmV, xmm2/m128, xmm1","vprotb xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 90 /r","V","V","XOP","amd","w,r,r","","" +"VPROTD xmm1, xmm2/m128, imm8u","VPROTD imm8u, xmm2/m128, xmm1","vprotd imm8u, xmm2/m128, xmm1","XOP.128.08.W0 C2 /r ib","V","V","XOP","amd","w,r,r","","" +"VPROTD xmm1, xmmV, xmm2/m128","VPROTD xmm2/m128, xmmV, xmm1","vprotd xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 92 /r","V","V","XOP","amd","w,r,r","","" +"VPROTD xmm1, xmm2/m128, xmmV","VPROTD xmmV, xmm2/m128, xmm1","vprotd xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 92 /r","V","V","XOP","amd","w,r,r","","" +"VPROTQ xmm1, xmm2/m128, imm8u","VPROTQ imm8u, xmm2/m128, xmm1","vprotq imm8u, xmm2/m128, xmm1","XOP.128.08.W0 C3 /r ib","V","V","XOP","amd","w,r,r","","" +"VPROTQ xmm1, xmmV, xmm2/m128","VPROTQ xmm2/m128, xmmV, xmm1","vprotq xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 93 /r","V","V","XOP","amd","w,r,r","","" +"VPROTQ xmm1, xmm2/m128, xmmV","VPROTQ xmmV, xmm2/m128, xmm1","vprotq xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 93 /r","V","V","XOP","amd","w,r,r","","" +"VPROTW xmm1, xmm2/m128, imm8u","VPROTW imm8u, xmm2/m128, xmm1","vprotw imm8u, xmm2/m128, xmm1","XOP.128.08.W0 C1 /r ib","V","V","XOP","amd","w,r,r","","" +"VPROTW xmm1, xmmV, xmm2/m128","VPROTW xmm2/m128, xmmV, xmm1","vprotw xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 91 /r","V","V","XOP","amd","w,r,r","","" +"VPROTW xmm1, xmm2/m128, xmmV","VPROTW xmmV, xmm2/m128, xmm1","vprotw xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 91 /r","V","V","XOP","amd","w,r,r","","" +"VPSADBW xmm1, xmmV, xmm2/m128","VPSADBW xmm2/m128, xmmV, xmm1","vpsadbw xmm2/m128, xmmV, xmm1","EVEX.NDS.128.66.0F.WIG F6 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPSADBW xmm1, xmmV, xmm2/m128","VPSADBW xmm2/m128, xmmV, xmm1","vpsadbw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG F6 /r","V","V","AVX","","w,r,r","","" +"VPSADBW ymm1, ymmV, ymm2/m256","VPSADBW ymm2/m256, ymmV, ymm1","vpsadbw ymm2/m256, ymmV, ymm1","EVEX.NDS.256.66.0F.WIG F6 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r","","" +"VPSADBW ymm1, ymmV, ymm2/m256","VPSADBW ymm2/m256, ymmV, ymm1","vpsadbw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG F6 /r","V","V","AVX2","","w,r,r","","" +"VPSADBW zmm1, zmmV, zmm2/m512","VPSADBW zmm2/m512, zmmV, zmm1","vpsadbw zmm2/m512, zmmV, zmm1","EVEX.NDS.512.66.0F.WIG F6 /r","V","V","AVX512BW","scale64","w,r,r","","" +"VPSCATTERDD vm32x, {k1-k7}, xmm1","VPSCATTERDD xmm1, {k1-k7}, vm32x","vpscatterdd xmm1, {k1-k7}, vm32x","EVEX.128.66.0F38.W0 A0 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VPSCATTERDD vm32y, {k1-k7}, ymm1","VPSCATTERDD ymm1, {k1-k7}, vm32y","vpscatterdd ymm1, {k1-k7}, vm32y","EVEX.256.66.0F38.W0 A0 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VPSCATTERDD vm32z, {k1-k7}, zmm1","VPSCATTERDD zmm1, {k1-k7}, vm32z","vpscatterdd zmm1, {k1-k7}, vm32z","EVEX.512.66.0F38.W0 A0 /vsib","V","V","AVX512F","modrm_memonly,scale4","w,rw,r","","" +"VPSCATTERDQ vm32x, {k1-k7}, xmm1","VPSCATTERDQ xmm1, {k1-k7}, vm32x","vpscatterdq xmm1, {k1-k7}, vm32x","EVEX.128.66.0F38.W1 A0 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VPSCATTERDQ vm32x, {k1-k7}, ymm1","VPSCATTERDQ ymm1, {k1-k7}, vm32x","vpscatterdq ymm1, {k1-k7}, vm32x","EVEX.256.66.0F38.W1 A0 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VPSCATTERDQ vm32y, {k1-k7}, zmm1","VPSCATTERDQ zmm1, {k1-k7}, vm32y","vpscatterdq zmm1, {k1-k7}, vm32y","EVEX.512.66.0F38.W1 A0 /vsib","V","V","AVX512F","modrm_memonly,scale8","w,rw,r","","" +"VPSCATTERQD vm64x, {k1-k7}, xmm1","VPSCATTERQD xmm1, {k1-k7}, vm64x","vpscatterqd xmm1, {k1-k7}, vm64x","EVEX.128.66.0F38.W0 A1 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VPSCATTERQD vm64y, {k1-k7}, xmm1","VPSCATTERQD xmm1, {k1-k7}, vm64y","vpscatterqd xmm1, {k1-k7}, vm64y","EVEX.256.66.0F38.W0 A1 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VPSCATTERQD vm64z, {k1-k7}, ymm1","VPSCATTERQD ymm1, {k1-k7}, vm64z","vpscatterqd ymm1, {k1-k7}, vm64z","EVEX.512.66.0F38.W0 A1 /vsib","V","V","AVX512F","modrm_memonly,scale4","w,rw,r","","" +"VPSCATTERQQ vm64x, {k1-k7}, xmm1","VPSCATTERQQ xmm1, {k1-k7}, vm64x","vpscatterqq xmm1, {k1-k7}, vm64x","EVEX.128.66.0F38.W1 A1 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VPSCATTERQQ vm64y, {k1-k7}, ymm1","VPSCATTERQQ ymm1, {k1-k7}, vm64y","vpscatterqq ymm1, {k1-k7}, vm64y","EVEX.256.66.0F38.W1 A1 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VPSCATTERQQ vm64z, {k1-k7}, zmm1","VPSCATTERQQ zmm1, {k1-k7}, vm64z","vpscatterqq zmm1, {k1-k7}, vm64z","EVEX.512.66.0F38.W1 A1 /vsib","V","V","AVX512F","modrm_memonly,scale8","w,rw,r","","" +"VPSHAB xmm1, xmmV, xmm2/m128","VPSHAB xmm2/m128, xmmV, xmm1","vpshab xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 98 /r","V","V","XOP","amd","w,r,r","","" +"VPSHAB xmm1, xmm2/m128, xmmV","VPSHAB xmmV, xmm2/m128, xmm1","vpshab xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 98 /r","V","V","XOP","amd","w,r,r","","" +"VPSHAD xmm1, xmmV, xmm2/m128","VPSHAD xmm2/m128, xmmV, xmm1","vpshad xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 9A /r","V","V","XOP","amd","w,r,r","","" +"VPSHAD xmm1, xmm2/m128, xmmV","VPSHAD xmmV, xmm2/m128, xmm1","vpshad xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 9A /r","V","V","XOP","amd","w,r,r","","" +"VPSHAQ xmm1, xmmV, xmm2/m128","VPSHAQ xmm2/m128, xmmV, xmm1","vpshaq xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 9B /r","V","V","XOP","amd","w,r,r","","" +"VPSHAQ xmm1, xmm2/m128, xmmV","VPSHAQ xmmV, xmm2/m128, xmm1","vpshaq xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 9B /r","V","V","XOP","amd","w,r,r","","" +"VPSHAW xmm1, xmmV, xmm2/m128","VPSHAW xmm2/m128, xmmV, xmm1","vpshaw xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 99 /r","V","V","XOP","amd","w,r,r","","" +"VPSHAW xmm1, xmm2/m128, xmmV","VPSHAW xmmV, xmm2/m128, xmm1","vpshaw xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 99 /r","V","V","XOP","amd","w,r,r","","" +"VPSHLB xmm1, xmmV, xmm2/m128","VPSHLB xmm2/m128, xmmV, xmm1","vpshlb xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 94 /r","V","V","XOP","amd","w,r,r","","" +"VPSHLB xmm1, xmm2/m128, xmmV","VPSHLB xmmV, xmm2/m128, xmm1","vpshlb xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 94 /r","V","V","XOP","amd","w,r,r","","" +"VPSHLD xmm1, xmmV, xmm2/m128","VPSHLD xmm2/m128, xmmV, xmm1","vpshld xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 96 /r","V","V","XOP","amd","w,r,r","","" +"VPSHLD xmm1, xmm2/m128, xmmV","VPSHLD xmmV, xmm2/m128, xmm1","vpshld xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 96 /r","V","V","XOP","amd","w,r,r","","" +"VPSHLDD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst, imm8u","VPSHLDD imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpshldd imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W0 71 /r ib","V","V","AVX512_VBMI2+AVX512VL","bscale4,scale16","w,r,r,r,r","","" +"VPSHLDD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u","VPSHLDD imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpshldd imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 71 /r ib","V","V","AVX512_VBMI2+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VPSHLDD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u","VPSHLDD imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpshldd imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 71 /r ib","V","V","AVX512_VBMI2","bscale4,scale64","w,r,r,r,r","","" +"VPSHLDQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u","VPSHLDQ imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpshldq imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W1 71 /r ib","V","V","AVX512_VBMI2+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VPSHLDQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VPSHLDQ imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpshldq imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 71 /r ib","V","V","AVX512_VBMI2+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VPSHLDQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VPSHLDQ imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpshldq imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 71 /r ib","V","V","AVX512_VBMI2","bscale8,scale64","w,r,r,r,r","","" +"VPSHLDVD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPSHLDVD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpshldvd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 71 /r","V","V","AVX512_VBMI2+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPSHLDVD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPSHLDVD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpshldvd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 71 /r","V","V","AVX512_VBMI2+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPSHLDVD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPSHLDVD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpshldvd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 71 /r","V","V","AVX512_VBMI2","bscale4,scale64","rw,r,r,r","","" +"VPSHLDVQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPSHLDVQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpshldvq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 71 /r","V","V","AVX512_VBMI2+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VPSHLDVQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPSHLDVQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpshldvq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 71 /r","V","V","AVX512_VBMI2+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VPSHLDVQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPSHLDVQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpshldvq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 71 /r","V","V","AVX512_VBMI2","bscale8,scale64","rw,r,r,r","","" +"VPSHLDVW xmm1, {k}{z}, xmmV, xmm2/m128","VPSHLDVW xmm2/m128, xmmV, {k}{z}, xmm1","vpshldvw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 70 /r","V","V","AVX512_VBMI2+AVX512VL","scale16","rw,r,r,r","","" +"VPSHLDVW ymm1, {k}{z}, ymmV, ymm2/m256","VPSHLDVW ymm2/m256, ymmV, {k}{z}, ymm1","vpshldvw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 70 /r","V","V","AVX512_VBMI2+AVX512VL","scale32","rw,r,r,r","","" +"VPSHLDVW zmm1, {k}{z}, zmmV, zmm2/m512","VPSHLDVW zmm2/m512, zmmV, {k}{z}, zmm1","vpshldvw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 70 /r","V","V","AVX512_VBMI2","scale64","rw,r,r,r","","" +"VPSHLDW xmm1, {k}{z}, xmmV, xmm2/m128, imm8u","VPSHLDW imm8u, xmm2/m128, xmmV, {k}{z}, xmm1","vpshldw imm8u, xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W1 70 /r ib","V","V","AVX512_VBMI2+AVX512VL","scale16","w,r,r,r,r","","" +"VPSHLDW ymm1, {k}{z}, ymmV, ymm2/m256, imm8u","VPSHLDW imm8u, ymm2/m256, ymmV, {k}{z}, ymm1","vpshldw imm8u, ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 70 /r ib","V","V","AVX512_VBMI2+AVX512VL","scale32","w,r,r,r,r","","" +"VPSHLDW zmm1, {k}{z}, zmmV, zmm2/m512, imm8u","VPSHLDW imm8u, zmm2/m512, zmmV, {k}{z}, zmm1","vpshldw imm8u, zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 70 /r ib","V","V","AVX512_VBMI2","scale64","w,r,r,r,r","","" +"VPSHLQ xmm1, xmmV, xmm2/m128","VPSHLQ xmm2/m128, xmmV, xmm1","vpshlq xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 97 /r","V","V","XOP","amd","w,r,r","","" +"VPSHLQ xmm1, xmm2/m128, xmmV","VPSHLQ xmmV, xmm2/m128, xmm1","vpshlq xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 97 /r","V","V","XOP","amd","w,r,r","","" +"VPSHLW xmm1, xmmV, xmm2/m128","VPSHLW xmm2/m128, xmmV, xmm1","vpshlw xmm2/m128, xmmV, xmm1","XOP.NDS.128.09.W1 95 /r","V","V","XOP","amd","w,r,r","","" +"VPSHLW xmm1, xmm2/m128, xmmV","VPSHLW xmmV, xmm2/m128, xmm1","vpshlw xmmV, xmm2/m128, xmm1","XOP.NDS.128.09.W0 95 /r","V","V","XOP","amd","w,r,r","","" +"VPSHRDD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst, imm8u","VPSHRDD imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpshrdd imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W0 73 /r ib","V","V","AVX512_VBMI2+AVX512VL","bscale4,scale16","w,r,r,r,r","","" +"VPSHRDD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u","VPSHRDD imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpshrdd imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 73 /r ib","V","V","AVX512_VBMI2+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VPSHRDD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u","VPSHRDD imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpshrdd imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 73 /r ib","V","V","AVX512_VBMI2","bscale4,scale64","w,r,r,r,r","","" +"VPSHRDQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u","VPSHRDQ imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpshrdq imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W1 73 /r ib","V","V","AVX512_VBMI2+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VPSHRDQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VPSHRDQ imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpshrdq imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 73 /r ib","V","V","AVX512_VBMI2+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VPSHRDQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VPSHRDQ imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpshrdq imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 73 /r ib","V","V","AVX512_VBMI2","bscale8,scale64","w,r,r,r,r","","" +"VPSHRDVD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPSHRDVD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpshrdvd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W0 73 /r","V","V","AVX512_VBMI2+AVX512VL","bscale4,scale16","rw,r,r,r","","" +"VPSHRDVD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPSHRDVD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpshrdvd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W0 73 /r","V","V","AVX512_VBMI2+AVX512VL","bscale4,scale32","rw,r,r,r","","" +"VPSHRDVD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPSHRDVD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpshrdvd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W0 73 /r","V","V","AVX512_VBMI2","bscale4,scale64","rw,r,r,r","","" +"VPSHRDVQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPSHRDVQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpshrdvq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 73 /r","V","V","AVX512_VBMI2+AVX512VL","bscale8,scale16","rw,r,r,r","","" +"VPSHRDVQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPSHRDVQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpshrdvq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 73 /r","V","V","AVX512_VBMI2+AVX512VL","bscale8,scale32","rw,r,r,r","","" +"VPSHRDVQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPSHRDVQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpshrdvq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 73 /r","V","V","AVX512_VBMI2","bscale8,scale64","rw,r,r,r","","" +"VPSHRDVW xmm1, {k}{z}, xmmV, xmm2/m128","VPSHRDVW xmm2/m128, xmmV, {k}{z}, xmm1","vpshrdvw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F38.W1 72 /r","V","V","AVX512_VBMI2+AVX512VL","scale16","rw,r,r,r","","" +"VPSHRDVW ymm1, {k}{z}, ymmV, ymm2/m256","VPSHRDVW ymm2/m256, ymmV, {k}{z}, ymm1","vpshrdvw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F38.W1 72 /r","V","V","AVX512_VBMI2+AVX512VL","scale32","rw,r,r,r","","" +"VPSHRDVW zmm1, {k}{z}, zmmV, zmm2/m512","VPSHRDVW zmm2/m512, zmmV, {k}{z}, zmm1","vpshrdvw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F38.W1 72 /r","V","V","AVX512_VBMI2","scale64","rw,r,r,r","","" +"VPSHRDW xmm1, {k}{z}, xmmV, xmm2/m128, imm8u","VPSHRDW imm8u, xmm2/m128, xmmV, {k}{z}, xmm1","vpshrdw imm8u, xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W1 72 /r ib","V","V","AVX512_VBMI2+AVX512VL","scale16","w,r,r,r,r","","" +"VPSHRDW ymm1, {k}{z}, ymmV, ymm2/m256, imm8u","VPSHRDW imm8u, ymm2/m256, ymmV, {k}{z}, ymm1","vpshrdw imm8u, ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 72 /r ib","V","V","AVX512_VBMI2+AVX512VL","scale32","w,r,r,r,r","","" +"VPSHRDW zmm1, {k}{z}, zmmV, zmm2/m512, imm8u","VPSHRDW imm8u, zmm2/m512, zmmV, {k}{z}, zmm1","vpshrdw imm8u, zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 72 /r ib","V","V","AVX512_VBMI2","scale64","w,r,r,r,r","","" +"VPSHUFB xmm1, xmmV, xmm2/m128","VPSHUFB xmm2/m128, xmmV, xmm1","vpshufb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 00 /r","V","V","AVX","","w,r,r","","" +"VPSHUFB xmm1, {k}{z}, xmmV, xmm2/m128","VPSHUFB xmm2/m128, xmmV, {k}{z}, xmm1","vpshufb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.WIG 00 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSHUFB ymm1, ymmV, ymm2/m256","VPSHUFB ymm2/m256, ymmV, ymm1","vpshufb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 00 /r","V","V","AVX2","","w,r,r","","" +"VPSHUFB ymm1, {k}{z}, ymmV, ymm2/m256","VPSHUFB ymm2/m256, ymmV, {k}{z}, ymm1","vpshufb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.WIG 00 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSHUFB zmm1, {k}{z}, zmmV, zmm2/m512","VPSHUFB zmm2/m512, zmmV, {k}{z}, zmm1","vpshufb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.WIG 00 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSHUFBITQMB k1, {k}, xmmV, xmm2/m128","VPSHUFBITQMB xmm2/m128, xmmV, {k}, k1","vpshufbitqmb xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F38.W0 8F /r","V","V","AVX512_BITALG+AVX512VL","scale16","w,r,r,r","","" +"VPSHUFBITQMB k1, {k}, ymmV, ymm2/m256","VPSHUFBITQMB ymm2/m256, ymmV, {k}, k1","vpshufbitqmb ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F38.W0 8F /r","V","V","AVX512_BITALG+AVX512VL","scale32","w,r,r,r","","" +"VPSHUFBITQMB k1, {k}, zmmV, zmm2/m512","VPSHUFBITQMB zmm2/m512, zmmV, {k}, k1","vpshufbitqmb zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F38.W0 8F /r","V","V","AVX512_BITALG","scale64","w,r,r,r","","" +"VPSHUFD xmm1, xmm2/m128, imm8u","VPSHUFD imm8u, xmm2/m128, xmm1","vpshufd imm8u, xmm2/m128, xmm1","VEX.128.66.0F.WIG 70 /r ib","V","V","AVX","","w,r,r","","" +"VPSHUFD xmm1, {k}{z}, xmm2/m128/m32bcst, imm8u","VPSHUFD imm8u, xmm2/m128/m32bcst, {k}{z}, xmm1","vpshufd imm8u, xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F.W0 70 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPSHUFD ymm1, ymm2/m256, imm8u","VPSHUFD imm8u, ymm2/m256, ymm1","vpshufd imm8u, ymm2/m256, ymm1","VEX.256.66.0F.WIG 70 /r ib","V","V","AVX2","","w,r,r","","" +"VPSHUFD ymm1, {k}{z}, ymm2/m256/m32bcst, imm8u","VPSHUFD imm8u, ymm2/m256/m32bcst, {k}{z}, ymm1","vpshufd imm8u, ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F.W0 70 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPSHUFD zmm1, {k}{z}, zmm2/m512/m32bcst, imm8u","VPSHUFD imm8u, zmm2/m512/m32bcst, {k}{z}, zmm1","vpshufd imm8u, zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F.W0 70 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPSHUFHW xmm1, xmm2/m128, imm8u","VPSHUFHW imm8u, xmm2/m128, xmm1","vpshufhw imm8u, xmm2/m128, xmm1","VEX.128.F3.0F.WIG 70 /r ib","V","V","AVX","","w,r,r","","" +"VPSHUFHW xmm1, {k}{z}, xmm2/m128, imm8u","VPSHUFHW imm8u, xmm2/m128, {k}{z}, xmm1","vpshufhw imm8u, xmm2/m128, {k}{z}, xmm1","EVEX.128.F3.0F.WIG 70 /r ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSHUFHW ymm1, ymm2/m256, imm8u","VPSHUFHW imm8u, ymm2/m256, ymm1","vpshufhw imm8u, ymm2/m256, ymm1","VEX.256.F3.0F.WIG 70 /r ib","V","V","AVX2","","w,r,r","","" +"VPSHUFHW ymm1, {k}{z}, ymm2/m256, imm8u","VPSHUFHW imm8u, ymm2/m256, {k}{z}, ymm1","vpshufhw imm8u, ymm2/m256, {k}{z}, ymm1","EVEX.256.F3.0F.WIG 70 /r ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSHUFHW zmm1, {k}{z}, zmm2/m512, imm8u","VPSHUFHW imm8u, zmm2/m512, {k}{z}, zmm1","vpshufhw imm8u, zmm2/m512, {k}{z}, zmm1","EVEX.512.F3.0F.WIG 70 /r ib","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSHUFLW xmm1, xmm2/m128, imm8u","VPSHUFLW imm8u, xmm2/m128, xmm1","vpshuflw imm8u, xmm2/m128, xmm1","VEX.128.F2.0F.WIG 70 /r ib","V","V","AVX","","w,r,r","","" +"VPSHUFLW xmm1, {k}{z}, xmm2/m128, imm8u","VPSHUFLW imm8u, xmm2/m128, {k}{z}, xmm1","vpshuflw imm8u, xmm2/m128, {k}{z}, xmm1","EVEX.128.F2.0F.WIG 70 /r ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSHUFLW ymm1, ymm2/m256, imm8u","VPSHUFLW imm8u, ymm2/m256, ymm1","vpshuflw imm8u, ymm2/m256, ymm1","VEX.256.F2.0F.WIG 70 /r ib","V","V","AVX2","","w,r,r","","" +"VPSHUFLW ymm1, {k}{z}, ymm2/m256, imm8u","VPSHUFLW imm8u, ymm2/m256, {k}{z}, ymm1","vpshuflw imm8u, ymm2/m256, {k}{z}, ymm1","EVEX.256.F2.0F.WIG 70 /r ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSHUFLW zmm1, {k}{z}, zmm2/m512, imm8u","VPSHUFLW imm8u, zmm2/m512, {k}{z}, zmm1","vpshuflw imm8u, zmm2/m512, {k}{z}, zmm1","EVEX.512.F2.0F.WIG 70 /r ib","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSIGNB xmm1, xmmV, xmm2/m128","VPSIGNB xmm2/m128, xmmV, xmm1","vpsignb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 08 /r","V","V","AVX","","w,r,r","","" +"VPSIGNB ymm1, ymmV, ymm2/m256","VPSIGNB ymm2/m256, ymmV, ymm1","vpsignb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 08 /r","V","V","AVX2","","w,r,r","","" +"VPSIGND xmm1, xmmV, xmm2/m128","VPSIGND xmm2/m128, xmmV, xmm1","vpsignd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 0A /r","V","V","AVX","","w,r,r","","" +"VPSIGND ymm1, ymmV, ymm2/m256","VPSIGND ymm2/m256, ymmV, ymm1","vpsignd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 0A /r","V","V","AVX2","","w,r,r","","" +"VPSIGNW xmm1, xmmV, xmm2/m128","VPSIGNW xmm2/m128, xmmV, xmm1","vpsignw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.WIG 09 /r","V","V","AVX","","w,r,r","","" +"VPSIGNW ymm1, ymmV, ymm2/m256","VPSIGNW ymm2/m256, ymmV, ymm1","vpsignw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.WIG 09 /r","V","V","AVX2","","w,r,r","","" +"VPSLLD xmmV, xmm2, imm8u","VPSLLD imm8u, xmm2, xmmV","vpslld imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 72 /6 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSLLD xmmV, {k}{z}, xmm2/m128/m32bcst, imm8u","VPSLLD imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","vpslld imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W0 72 /6 ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPSLLD ymmV, ymm2, imm8u","VPSLLD imm8u, ymm2, ymmV","vpslld imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 72 /6 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSLLD ymmV, {k}{z}, ymm2/m256/m32bcst, imm8u","VPSLLD imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","vpslld imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W0 72 /6 ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPSLLD zmmV, {k}{z}, zmm2/m512/m32bcst, imm8u","VPSLLD imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","vpslld imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W0 72 /6 ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPSLLD xmm1, xmmV, xmm2/m128","VPSLLD xmm2/m128, xmmV, xmm1","vpslld xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG F2 /r","V","V","AVX","","w,r,r","","" +"VPSLLD xmm1, {k}{z}, xmmV, xmm2/m128","VPSLLD xmm2/m128, xmmV, {k}{z}, xmm1","vpslld xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 F2 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSLLD ymm1, ymmV, xmm2/m128","VPSLLD xmm2/m128, ymmV, ymm1","vpslld xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F.WIG F2 /r","V","V","AVX2","","w,r,r","","" +"VPSLLD ymm1, {k}{z}, ymmV, xmm2/m128","VPSLLD xmm2/m128, ymmV, {k}{z}, ymm1","vpslld xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 F2 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSLLD zmm1, {k}{z}, zmmV, xmm2/m128","VPSLLD xmm2/m128, zmmV, {k}{z}, zmm1","vpslld xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 F2 /r","V","V","AVX512F","scale16","w,r,r,r","","" +"VPSLLDQ xmmV, xmm2, imm8u","VPSLLDQ imm8u, xmm2, xmmV","vpslldq imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 73 /7 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSLLDQ xmmV, xmm2/m128, imm8u","VPSLLDQ imm8u, xmm2/m128, xmmV","vpslldq imm8u, xmm2/m128, xmmV","EVEX.NDD.128.66.0F.WIG 73 /7 ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPSLLDQ ymmV, ymm2, imm8u","VPSLLDQ imm8u, ymm2, ymmV","vpslldq imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 73 /7 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSLLDQ ymmV, ymm2/m256, imm8u","VPSLLDQ imm8u, ymm2/m256, ymmV","vpslldq imm8u, ymm2/m256, ymmV","EVEX.NDD.256.66.0F.WIG 73 /7 ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r","","" +"VPSLLDQ zmmV, zmm2/m512, imm8u","VPSLLDQ imm8u, zmm2/m512, zmmV","vpslldq imm8u, zmm2/m512, zmmV","EVEX.NDD.512.66.0F.WIG 73 /7 ib","V","V","AVX512BW","scale64","w,r,r","","" +"VPSLLQ xmmV, xmm2, imm8u","VPSLLQ imm8u, xmm2, xmmV","vpsllq imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 73 /6 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSLLQ xmmV, {k}{z}, xmm2/m128/m64bcst, imm8u","VPSLLQ imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","vpsllq imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W1 73 /6 ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPSLLQ ymmV, ymm2, imm8u","VPSLLQ imm8u, ymm2, ymmV","vpsllq imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 73 /6 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSLLQ ymmV, {k}{z}, ymm2/m256/m64bcst, imm8u","VPSLLQ imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","vpsllq imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W1 73 /6 ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPSLLQ zmmV, {k}{z}, zmm2/m512/m64bcst, imm8u","VPSLLQ imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","vpsllq imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W1 73 /6 ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPSLLQ xmm1, xmmV, xmm2/m128","VPSLLQ xmm2/m128, xmmV, xmm1","vpsllq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG F3 /r","V","V","AVX","","w,r,r","","" +"VPSLLQ xmm1, {k}{z}, xmmV, xmm2/m128","VPSLLQ xmm2/m128, xmmV, {k}{z}, xmm1","vpsllq xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 F3 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSLLQ ymm1, ymmV, xmm2/m128","VPSLLQ xmm2/m128, ymmV, ymm1","vpsllq xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F.WIG F3 /r","V","V","AVX2","","w,r,r","","" +"VPSLLQ ymm1, {k}{z}, ymmV, xmm2/m128","VPSLLQ xmm2/m128, ymmV, {k}{z}, ymm1","vpsllq xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 F3 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSLLQ zmm1, {k}{z}, zmmV, xmm2/m128","VPSLLQ xmm2/m128, zmmV, {k}{z}, zmm1","vpsllq xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 F3 /r","V","V","AVX512F","scale16","w,r,r,r","","" +"VPSLLVD xmm1, xmmV, xmm2/m128","VPSLLVD xmm2/m128, xmmV, xmm1","vpsllvd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 47 /r","V","V","AVX2","","w,r,r","","" +"VPSLLVD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPSLLVD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpsllvd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 47 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPSLLVD ymm1, ymmV, ymm2/m256","VPSLLVD ymm2/m256, ymmV, ymm1","vpsllvd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 47 /r","V","V","AVX2","","w,r,r","","" +"VPSLLVD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPSLLVD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpsllvd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 47 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPSLLVD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPSLLVD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpsllvd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 47 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPSLLVQ xmm1, xmmV, xmm2/m128","VPSLLVQ xmm2/m128, xmmV, xmm1","vpsllvq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W1 47 /r","V","V","AVX2","","w,r,r","","" +"VPSLLVQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPSLLVQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpsllvq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 47 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPSLLVQ ymm1, ymmV, ymm2/m256","VPSLLVQ ymm2/m256, ymmV, ymm1","vpsllvq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W1 47 /r","V","V","AVX2","","w,r,r","","" +"VPSLLVQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPSLLVQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpsllvq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 47 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPSLLVQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPSLLVQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpsllvq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 47 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPSLLVW xmm1, {k}{z}, xmmV, xmm2/m128","VPSLLVW xmm2/m128, xmmV, {k}{z}, xmm1","vpsllvw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 12 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSLLVW ymm1, {k}{z}, ymmV, ymm2/m256","VPSLLVW ymm2/m256, ymmV, {k}{z}, ymm1","vpsllvw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 12 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSLLVW zmm1, {k}{z}, zmmV, zmm2/m512","VPSLLVW zmm2/m512, zmmV, {k}{z}, zmm1","vpsllvw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 12 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSLLW xmmV, xmm2, imm8u","VPSLLW imm8u, xmm2, xmmV","vpsllw imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 71 /6 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSLLW xmmV, {k}{z}, xmm2/m128, imm8u","VPSLLW imm8u, xmm2/m128, {k}{z}, xmmV","vpsllw imm8u, xmm2/m128, {k}{z}, xmmV","EVEX.NDD.128.66.0F.WIG 71 /6 ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSLLW ymmV, ymm2, imm8u","VPSLLW imm8u, ymm2, ymmV","vpsllw imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 71 /6 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSLLW ymmV, {k}{z}, ymm2/m256, imm8u","VPSLLW imm8u, ymm2/m256, {k}{z}, ymmV","vpsllw imm8u, ymm2/m256, {k}{z}, ymmV","EVEX.NDD.256.66.0F.WIG 71 /6 ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSLLW zmmV, {k}{z}, zmm2/m512, imm8u","VPSLLW imm8u, zmm2/m512, {k}{z}, zmmV","vpsllw imm8u, zmm2/m512, {k}{z}, zmmV","EVEX.NDD.512.66.0F.WIG 71 /6 ib","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSLLW xmm1, xmmV, xmm2/m128","VPSLLW xmm2/m128, xmmV, xmm1","vpsllw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG F1 /r","V","V","AVX","","w,r,r","","" +"VPSLLW xmm1, {k}{z}, xmmV, xmm2/m128","VPSLLW xmm2/m128, xmmV, {k}{z}, xmm1","vpsllw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG F1 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSLLW ymm1, ymmV, xmm2/m128","VPSLLW xmm2/m128, ymmV, ymm1","vpsllw xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F.WIG F1 /r","V","V","AVX2","","w,r,r","","" +"VPSLLW ymm1, {k}{z}, ymmV, xmm2/m128","VPSLLW xmm2/m128, ymmV, {k}{z}, ymm1","vpsllw xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG F1 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSLLW zmm1, {k}{z}, zmmV, xmm2/m128","VPSLLW xmm2/m128, zmmV, {k}{z}, zmm1","vpsllw xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG F1 /r","V","V","AVX512BW","scale16","w,r,r,r","","" +"VPSRAD xmmV, xmm2, imm8u","VPSRAD imm8u, xmm2, xmmV","vpsrad imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 72 /4 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSRAD xmmV, {k}{z}, xmm2/m128/m32bcst, imm8u","VPSRAD imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","vpsrad imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W0 72 /4 ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPSRAD ymmV, ymm2, imm8u","VPSRAD imm8u, ymm2, ymmV","vpsrad imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 72 /4 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSRAD ymmV, {k}{z}, ymm2/m256/m32bcst, imm8u","VPSRAD imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","vpsrad imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W0 72 /4 ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPSRAD zmmV, {k}{z}, zmm2/m512/m32bcst, imm8u","VPSRAD imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","vpsrad imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W0 72 /4 ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPSRAD xmm1, xmmV, xmm2/m128","VPSRAD xmm2/m128, xmmV, xmm1","vpsrad xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG E2 /r","V","V","AVX","","w,r,r","","" +"VPSRAD xmm1, {k}{z}, xmmV, xmm2/m128","VPSRAD xmm2/m128, xmmV, {k}{z}, xmm1","vpsrad xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 E2 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSRAD ymm1, ymmV, xmm2/m128","VPSRAD xmm2/m128, ymmV, ymm1","vpsrad xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F.WIG E2 /r","V","V","AVX2","","w,r,r","","" +"VPSRAD ymm1, {k}{z}, ymmV, xmm2/m128","VPSRAD xmm2/m128, ymmV, {k}{z}, ymm1","vpsrad xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 E2 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSRAD zmm1, {k}{z}, zmmV, xmm2/m128","VPSRAD xmm2/m128, zmmV, {k}{z}, zmm1","vpsrad xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 E2 /r","V","V","AVX512F","scale16","w,r,r,r","","" +"VPSRAQ xmmV, {k}{z}, xmm2/m128/m64bcst, imm8u","VPSRAQ imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","vpsraq imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W1 72 /4 ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPSRAQ ymmV, {k}{z}, ymm2/m256/m64bcst, imm8u","VPSRAQ imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","vpsraq imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W1 72 /4 ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPSRAQ zmmV, {k}{z}, zmm2/m512/m64bcst, imm8u","VPSRAQ imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","vpsraq imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W1 72 /4 ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPSRAQ xmm1, {k}{z}, xmmV, xmm2/m128","VPSRAQ xmm2/m128, xmmV, {k}{z}, xmm1","vpsraq xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 E2 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSRAQ ymm1, {k}{z}, ymmV, xmm2/m128","VPSRAQ xmm2/m128, ymmV, {k}{z}, ymm1","vpsraq xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 E2 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSRAQ zmm1, {k}{z}, zmmV, xmm2/m128","VPSRAQ xmm2/m128, zmmV, {k}{z}, zmm1","vpsraq xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 E2 /r","V","V","AVX512F","scale16","w,r,r,r","","" +"VPSRAVD xmm1, xmmV, xmm2/m128","VPSRAVD xmm2/m128, xmmV, xmm1","vpsravd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 46 /r","V","V","AVX2","","w,r,r","","" +"VPSRAVD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPSRAVD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpsravd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 46 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPSRAVD ymm1, ymmV, ymm2/m256","VPSRAVD ymm2/m256, ymmV, ymm1","vpsravd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 46 /r","V","V","AVX2","","w,r,r","","" +"VPSRAVD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPSRAVD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpsravd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 46 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPSRAVD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPSRAVD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpsravd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 46 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPSRAVQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPSRAVQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpsravq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 46 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPSRAVQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPSRAVQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpsravq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 46 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPSRAVQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPSRAVQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpsravq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 46 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPSRAVW xmm1, {k}{z}, xmmV, xmm2/m128","VPSRAVW xmm2/m128, xmmV, {k}{z}, xmm1","vpsravw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 11 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSRAVW ymm1, {k}{z}, ymmV, ymm2/m256","VPSRAVW ymm2/m256, ymmV, {k}{z}, ymm1","vpsravw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 11 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSRAVW zmm1, {k}{z}, zmmV, zmm2/m512","VPSRAVW zmm2/m512, zmmV, {k}{z}, zmm1","vpsravw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 11 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSRAW xmmV, xmm2, imm8u","VPSRAW imm8u, xmm2, xmmV","vpsraw imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 71 /4 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSRAW xmmV, {k}{z}, xmm2/m128, imm8u","VPSRAW imm8u, xmm2/m128, {k}{z}, xmmV","vpsraw imm8u, xmm2/m128, {k}{z}, xmmV","EVEX.NDD.128.66.0F.WIG 71 /4 ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSRAW ymmV, ymm2, imm8u","VPSRAW imm8u, ymm2, ymmV","vpsraw imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 71 /4 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSRAW ymmV, {k}{z}, ymm2/m256, imm8u","VPSRAW imm8u, ymm2/m256, {k}{z}, ymmV","vpsraw imm8u, ymm2/m256, {k}{z}, ymmV","EVEX.NDD.256.66.0F.WIG 71 /4 ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSRAW zmmV, {k}{z}, zmm2/m512, imm8u","VPSRAW imm8u, zmm2/m512, {k}{z}, zmmV","vpsraw imm8u, zmm2/m512, {k}{z}, zmmV","EVEX.NDD.512.66.0F.WIG 71 /4 ib","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSRAW xmm1, xmmV, xmm2/m128","VPSRAW xmm2/m128, xmmV, xmm1","vpsraw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG E1 /r","V","V","AVX","","w,r,r","","" +"VPSRAW xmm1, {k}{z}, xmmV, xmm2/m128","VPSRAW xmm2/m128, xmmV, {k}{z}, xmm1","vpsraw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG E1 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSRAW ymm1, ymmV, xmm2/m128","VPSRAW xmm2/m128, ymmV, ymm1","vpsraw xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F.WIG E1 /r","V","V","AVX2","","w,r,r","","" +"VPSRAW ymm1, {k}{z}, ymmV, xmm2/m128","VPSRAW xmm2/m128, ymmV, {k}{z}, ymm1","vpsraw xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG E1 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSRAW zmm1, {k}{z}, zmmV, xmm2/m128","VPSRAW xmm2/m128, zmmV, {k}{z}, zmm1","vpsraw xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG E1 /r","V","V","AVX512BW","scale16","w,r,r,r","","" +"VPSRLD xmmV, xmm2, imm8u","VPSRLD imm8u, xmm2, xmmV","vpsrld imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 72 /2 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSRLD xmmV, {k}{z}, xmm2/m128/m32bcst, imm8u","VPSRLD imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","vpsrld imm8u, xmm2/m128/m32bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W0 72 /2 ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPSRLD ymmV, ymm2, imm8u","VPSRLD imm8u, ymm2, ymmV","vpsrld imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 72 /2 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSRLD ymmV, {k}{z}, ymm2/m256/m32bcst, imm8u","VPSRLD imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","vpsrld imm8u, ymm2/m256/m32bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W0 72 /2 ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPSRLD zmmV, {k}{z}, zmm2/m512/m32bcst, imm8u","VPSRLD imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","vpsrld imm8u, zmm2/m512/m32bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W0 72 /2 ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPSRLD xmm1, xmmV, xmm2/m128","VPSRLD xmm2/m128, xmmV, xmm1","vpsrld xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG D2 /r","V","V","AVX","","w,r,r","","" +"VPSRLD xmm1, {k}{z}, xmmV, xmm2/m128","VPSRLD xmm2/m128, xmmV, {k}{z}, xmm1","vpsrld xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 D2 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSRLD ymm1, ymmV, xmm2/m128","VPSRLD xmm2/m128, ymmV, ymm1","vpsrld xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F.WIG D2 /r","V","V","AVX2","","w,r,r","","" +"VPSRLD ymm1, {k}{z}, ymmV, xmm2/m128","VPSRLD xmm2/m128, ymmV, {k}{z}, ymm1","vpsrld xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 D2 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSRLD zmm1, {k}{z}, zmmV, xmm2/m128","VPSRLD xmm2/m128, zmmV, {k}{z}, zmm1","vpsrld xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 D2 /r","V","V","AVX512F","scale16","w,r,r,r","","" +"VPSRLDQ xmmV, xmm2, imm8u","VPSRLDQ imm8u, xmm2, xmmV","vpsrldq imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 73 /3 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSRLDQ xmmV, xmm2/m128, imm8u","VPSRLDQ imm8u, xmm2/m128, xmmV","vpsrldq imm8u, xmm2/m128, xmmV","EVEX.NDD.128.66.0F.WIG 73 /3 ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r","","" +"VPSRLDQ ymmV, ymm2, imm8u","VPSRLDQ imm8u, ymm2, ymmV","vpsrldq imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 73 /3 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSRLDQ ymmV, ymm2/m256, imm8u","VPSRLDQ imm8u, ymm2/m256, ymmV","vpsrldq imm8u, ymm2/m256, ymmV","EVEX.NDD.256.66.0F.WIG 73 /3 ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r","","" +"VPSRLDQ zmmV, zmm2/m512, imm8u","VPSRLDQ imm8u, zmm2/m512, zmmV","vpsrldq imm8u, zmm2/m512, zmmV","EVEX.NDD.512.66.0F.WIG 73 /3 ib","V","V","AVX512BW","scale64","w,r,r","","" +"VPSRLQ xmmV, xmm2, imm8u","VPSRLQ imm8u, xmm2, xmmV","vpsrlq imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 73 /2 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSRLQ xmmV, {k}{z}, xmm2/m128/m64bcst, imm8u","VPSRLQ imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","vpsrlq imm8u, xmm2/m128/m64bcst, {k}{z}, xmmV","EVEX.NDD.128.66.0F.W1 73 /2 ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPSRLQ ymmV, ymm2, imm8u","VPSRLQ imm8u, ymm2, ymmV","vpsrlq imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 73 /2 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSRLQ ymmV, {k}{z}, ymm2/m256/m64bcst, imm8u","VPSRLQ imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","vpsrlq imm8u, ymm2/m256/m64bcst, {k}{z}, ymmV","EVEX.NDD.256.66.0F.W1 73 /2 ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPSRLQ zmmV, {k}{z}, zmm2/m512/m64bcst, imm8u","VPSRLQ imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","vpsrlq imm8u, zmm2/m512/m64bcst, {k}{z}, zmmV","EVEX.NDD.512.66.0F.W1 73 /2 ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPSRLQ xmm1, xmmV, xmm2/m128","VPSRLQ xmm2/m128, xmmV, xmm1","vpsrlq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG D3 /r","V","V","AVX","","w,r,r","","" +"VPSRLQ xmm1, {k}{z}, xmmV, xmm2/m128","VPSRLQ xmm2/m128, xmmV, {k}{z}, xmm1","vpsrlq xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 D3 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSRLQ ymm1, ymmV, xmm2/m128","VPSRLQ xmm2/m128, ymmV, ymm1","vpsrlq xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F.WIG D3 /r","V","V","AVX2","","w,r,r","","" +"VPSRLQ ymm1, {k}{z}, ymmV, xmm2/m128","VPSRLQ xmm2/m128, ymmV, {k}{z}, ymm1","vpsrlq xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 D3 /r","V","V","AVX512F+AVX512VL","scale16","w,r,r,r","","" +"VPSRLQ zmm1, {k}{z}, zmmV, xmm2/m128","VPSRLQ xmm2/m128, zmmV, {k}{z}, zmm1","vpsrlq xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 D3 /r","V","V","AVX512F","scale16","w,r,r,r","","" +"VPSRLVD xmm1, xmmV, xmm2/m128","VPSRLVD xmm2/m128, xmmV, xmm1","vpsrlvd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W0 45 /r","V","V","AVX2","","w,r,r","","" +"VPSRLVD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPSRLVD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpsrlvd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 45 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPSRLVD ymm1, ymmV, ymm2/m256","VPSRLVD ymm2/m256, ymmV, ymm1","vpsrlvd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W0 45 /r","V","V","AVX2","","w,r,r","","" +"VPSRLVD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPSRLVD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpsrlvd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 45 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPSRLVD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPSRLVD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpsrlvd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 45 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPSRLVQ xmm1, xmmV, xmm2/m128","VPSRLVQ xmm2/m128, xmmV, xmm1","vpsrlvq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F38.W1 45 /r","V","V","AVX2","","w,r,r","","" +"VPSRLVQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPSRLVQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpsrlvq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 45 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPSRLVQ ymm1, ymmV, ymm2/m256","VPSRLVQ ymm2/m256, ymmV, ymm1","vpsrlvq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F38.W1 45 /r","V","V","AVX2","","w,r,r","","" +"VPSRLVQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPSRLVQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpsrlvq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 45 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPSRLVQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPSRLVQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpsrlvq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 45 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPSRLVW xmm1, {k}{z}, xmmV, xmm2/m128","VPSRLVW xmm2/m128, xmmV, {k}{z}, xmm1","vpsrlvw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 10 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSRLVW ymm1, {k}{z}, ymmV, ymm2/m256","VPSRLVW ymm2/m256, ymmV, {k}{z}, ymm1","vpsrlvw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 10 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSRLVW zmm1, {k}{z}, zmmV, zmm2/m512","VPSRLVW zmm2/m512, zmmV, {k}{z}, zmm1","vpsrlvw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 10 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSRLW xmmV, xmm2, imm8u","VPSRLW imm8u, xmm2, xmmV","vpsrlw imm8u, xmm2, xmmV","VEX.NDD.128.66.0F.WIG 71 /2 ib","V","V","AVX","modrm_regonly","w,r,r","","" +"VPSRLW xmmV, {k}{z}, xmm2/m128, imm8u","VPSRLW imm8u, xmm2/m128, {k}{z}, xmmV","vpsrlw imm8u, xmm2/m128, {k}{z}, xmmV","EVEX.NDD.128.66.0F.WIG 71 /2 ib","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSRLW ymmV, ymm2, imm8u","VPSRLW imm8u, ymm2, ymmV","vpsrlw imm8u, ymm2, ymmV","VEX.NDD.256.66.0F.WIG 71 /2 ib","V","V","AVX2","modrm_regonly","w,r,r","","" +"VPSRLW ymmV, {k}{z}, ymm2/m256, imm8u","VPSRLW imm8u, ymm2/m256, {k}{z}, ymmV","vpsrlw imm8u, ymm2/m256, {k}{z}, ymmV","EVEX.NDD.256.66.0F.WIG 71 /2 ib","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSRLW zmmV, {k}{z}, zmm2/m512, imm8u","VPSRLW imm8u, zmm2/m512, {k}{z}, zmmV","vpsrlw imm8u, zmm2/m512, {k}{z}, zmmV","EVEX.NDD.512.66.0F.WIG 71 /2 ib","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSRLW xmm1, xmmV, xmm2/m128","VPSRLW xmm2/m128, xmmV, xmm1","vpsrlw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG D1 /r","V","V","AVX","","w,r,r","","" +"VPSRLW xmm1, {k}{z}, xmmV, xmm2/m128","VPSRLW xmm2/m128, xmmV, {k}{z}, xmm1","vpsrlw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG D1 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSRLW ymm1, ymmV, xmm2/m128","VPSRLW xmm2/m128, ymmV, ymm1","vpsrlw xmm2/m128, ymmV, ymm1","VEX.NDS.256.66.0F.WIG D1 /r","V","V","AVX2","","w,r,r","","" +"VPSRLW ymm1, {k}{z}, ymmV, xmm2/m128","VPSRLW xmm2/m128, ymmV, {k}{z}, ymm1","vpsrlw xmm2/m128, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG D1 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSRLW zmm1, {k}{z}, zmmV, xmm2/m128","VPSRLW xmm2/m128, zmmV, {k}{z}, zmm1","vpsrlw xmm2/m128, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG D1 /r","V","V","AVX512BW","scale16","w,r,r,r","","" +"VPSUBB xmm1, xmmV, xmm2/m128","VPSUBB xmm2/m128, xmmV, xmm1","vpsubb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG F8 /r","V","V","AVX","","w,r,r","","" +"VPSUBB xmm1, {k}{z}, xmmV, xmm2/m128","VPSUBB xmm2/m128, xmmV, {k}{z}, xmm1","vpsubb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG F8 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSUBB ymm1, ymmV, ymm2/m256","VPSUBB ymm2/m256, ymmV, ymm1","vpsubb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG F8 /r","V","V","AVX2","","w,r,r","","" +"VPSUBB ymm1, {k}{z}, ymmV, ymm2/m256","VPSUBB ymm2/m256, ymmV, {k}{z}, ymm1","vpsubb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG F8 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSUBB zmm1, {k}{z}, zmmV, zmm2/m512","VPSUBB zmm2/m512, zmmV, {k}{z}, zmm1","vpsubb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG F8 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSUBD xmm1, xmmV, xmm2/m128","VPSUBD xmm2/m128, xmmV, xmm1","vpsubd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG FA /r","V","V","AVX","","w,r,r","","" +"VPSUBD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPSUBD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpsubd xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 FA /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPSUBD ymm1, ymmV, ymm2/m256","VPSUBD ymm2/m256, ymmV, ymm1","vpsubd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG FA /r","V","V","AVX2","","w,r,r","","" +"VPSUBD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPSUBD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpsubd ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 FA /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPSUBD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPSUBD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpsubd zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 FA /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPSUBQ xmm1, xmmV, xmm2/m128","VPSUBQ xmm2/m128, xmmV, xmm1","vpsubq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG FB /r","V","V","AVX","","w,r,r","","" +"VPSUBQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPSUBQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpsubq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 FB /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPSUBQ ymm1, ymmV, ymm2/m256","VPSUBQ ymm2/m256, ymmV, ymm1","vpsubq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG FB /r","V","V","AVX2","","w,r,r","","" +"VPSUBQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPSUBQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpsubq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 FB /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPSUBQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPSUBQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpsubq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 FB /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPSUBSB xmm1, xmmV, xmm2/m128","VPSUBSB xmm2/m128, xmmV, xmm1","vpsubsb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG E8 /r","V","V","AVX","","w,r,r","","" +"VPSUBSB xmm1, {k}{z}, xmmV, xmm2/m128","VPSUBSB xmm2/m128, xmmV, {k}{z}, xmm1","vpsubsb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG E8 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSUBSB ymm1, ymmV, ymm2/m256","VPSUBSB ymm2/m256, ymmV, ymm1","vpsubsb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG E8 /r","V","V","AVX2","","w,r,r","","" +"VPSUBSB ymm1, {k}{z}, ymmV, ymm2/m256","VPSUBSB ymm2/m256, ymmV, {k}{z}, ymm1","vpsubsb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG E8 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSUBSB zmm1, {k}{z}, zmmV, zmm2/m512","VPSUBSB zmm2/m512, zmmV, {k}{z}, zmm1","vpsubsb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG E8 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSUBSW xmm1, xmmV, xmm2/m128","VPSUBSW xmm2/m128, xmmV, xmm1","vpsubsw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG E9 /r","V","V","AVX","","w,r,r","","" +"VPSUBSW xmm1, {k}{z}, xmmV, xmm2/m128","VPSUBSW xmm2/m128, xmmV, {k}{z}, xmm1","vpsubsw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG E9 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSUBSW ymm1, ymmV, ymm2/m256","VPSUBSW ymm2/m256, ymmV, ymm1","vpsubsw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG E9 /r","V","V","AVX2","","w,r,r","","" +"VPSUBSW ymm1, {k}{z}, ymmV, ymm2/m256","VPSUBSW ymm2/m256, ymmV, {k}{z}, ymm1","vpsubsw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG E9 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSUBSW zmm1, {k}{z}, zmmV, zmm2/m512","VPSUBSW zmm2/m512, zmmV, {k}{z}, zmm1","vpsubsw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG E9 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSUBUSB xmm1, xmmV, xmm2/m128","VPSUBUSB xmm2/m128, xmmV, xmm1","vpsubusb xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG D8 /r","V","V","AVX","","w,r,r","","" +"VPSUBUSB xmm1, {k}{z}, xmmV, xmm2/m128","VPSUBUSB xmm2/m128, xmmV, {k}{z}, xmm1","vpsubusb xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG D8 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSUBUSB ymm1, ymmV, ymm2/m256","VPSUBUSB ymm2/m256, ymmV, ymm1","vpsubusb ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG D8 /r","V","V","AVX2","","w,r,r","","" +"VPSUBUSB ymm1, {k}{z}, ymmV, ymm2/m256","VPSUBUSB ymm2/m256, ymmV, {k}{z}, ymm1","vpsubusb ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG D8 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSUBUSB zmm1, {k}{z}, zmmV, zmm2/m512","VPSUBUSB zmm2/m512, zmmV, {k}{z}, zmm1","vpsubusb zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG D8 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSUBUSW xmm1, xmmV, xmm2/m128","VPSUBUSW xmm2/m128, xmmV, xmm1","vpsubusw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG D9 /r","V","V","AVX","","w,r,r","","" +"VPSUBUSW xmm1, {k}{z}, xmmV, xmm2/m128","VPSUBUSW xmm2/m128, xmmV, {k}{z}, xmm1","vpsubusw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG D9 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSUBUSW ymm1, ymmV, ymm2/m256","VPSUBUSW ymm2/m256, ymmV, ymm1","vpsubusw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG D9 /r","V","V","AVX2","","w,r,r","","" +"VPSUBUSW ymm1, {k}{z}, ymmV, ymm2/m256","VPSUBUSW ymm2/m256, ymmV, {k}{z}, ymm1","vpsubusw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG D9 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSUBUSW zmm1, {k}{z}, zmmV, zmm2/m512","VPSUBUSW zmm2/m512, zmmV, {k}{z}, zmm1","vpsubusw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG D9 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPSUBW xmm1, xmmV, xmm2/m128","VPSUBW xmm2/m128, xmmV, xmm1","vpsubw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG F9 /r","V","V","AVX","","w,r,r","","" +"VPSUBW xmm1, {k}{z}, xmmV, xmm2/m128","VPSUBW xmm2/m128, xmmV, {k}{z}, xmm1","vpsubw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG F9 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPSUBW ymm1, ymmV, ymm2/m256","VPSUBW ymm2/m256, ymmV, ymm1","vpsubw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG F9 /r","V","V","AVX2","","w,r,r","","" +"VPSUBW ymm1, {k}{z}, ymmV, ymm2/m256","VPSUBW ymm2/m256, ymmV, {k}{z}, ymm1","vpsubw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG F9 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPSUBW zmm1, {k}{z}, zmmV, zmm2/m512","VPSUBW zmm2/m512, zmmV, {k}{z}, zmm1","vpsubw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG F9 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPTERNLOGD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst, imm8u","VPTERNLOGD imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpternlogd imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F3A.W0 25 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","rw,r,r,r,r","","" +"VPTERNLOGD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u","VPTERNLOGD imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpternlogd imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F3A.W0 25 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","rw,r,r,r,r","","" +"VPTERNLOGD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u","VPTERNLOGD imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpternlogd imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F3A.W0 25 /r ib","V","V","AVX512F","bscale4,scale64","rw,r,r,r,r","","" +"VPTERNLOGQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u","VPTERNLOGQ imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpternlogq imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.DDS.128.66.0F3A.W1 25 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","rw,r,r,r,r","","" +"VPTERNLOGQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VPTERNLOGQ imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpternlogq imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.DDS.256.66.0F3A.W1 25 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","rw,r,r,r,r","","" +"VPTERNLOGQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VPTERNLOGQ imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpternlogq imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.DDS.512.66.0F3A.W1 25 /r ib","V","V","AVX512F","bscale8,scale64","rw,r,r,r,r","","" +"VPTEST xmm1, xmm2/m128","VPTEST xmm2/m128, xmm1","vptest xmm2/m128, xmm1","VEX.128.66.0F38.WIG 17 /r","V","V","AVX","","r,r","","" +"VPTEST ymm1, ymm2/m256","VPTEST ymm2/m256, ymm1","vptest ymm2/m256, ymm1","VEX.256.66.0F38.WIG 17 /r","V","V","AVX","","r,r","","" +"VPTESTMB k1, {k}, xmmV, xmm2/m128","VPTESTMB xmm2/m128, xmmV, {k}, k1","vptestmb xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F38.W0 26 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPTESTMB k1, {k}, ymmV, ymm2/m256","VPTESTMB ymm2/m256, ymmV, {k}, k1","vptestmb ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F38.W0 26 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPTESTMB k1, {k}, zmmV, zmm2/m512","VPTESTMB zmm2/m512, zmmV, {k}, k1","vptestmb zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F38.W0 26 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPTESTMD k1, {k}, xmmV, xmm2/m128/m32bcst","VPTESTMD xmm2/m128/m32bcst, xmmV, {k}, k1","vptestmd xmm2/m128/m32bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F38.W0 27 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPTESTMD k1, {k}, ymmV, ymm2/m256/m32bcst","VPTESTMD ymm2/m256/m32bcst, ymmV, {k}, k1","vptestmd ymm2/m256/m32bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F38.W0 27 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPTESTMD k1, {k}, zmmV, zmm2/m512/m32bcst","VPTESTMD zmm2/m512/m32bcst, zmmV, {k}, k1","vptestmd zmm2/m512/m32bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F38.W0 27 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPTESTMQ k1, {k}, xmmV, xmm2/m128/m64bcst","VPTESTMQ xmm2/m128/m64bcst, xmmV, {k}, k1","vptestmq xmm2/m128/m64bcst, xmmV, {k}, k1","EVEX.NDS.128.66.0F38.W1 27 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPTESTMQ k1, {k}, ymmV, ymm2/m256/m64bcst","VPTESTMQ ymm2/m256/m64bcst, ymmV, {k}, k1","vptestmq ymm2/m256/m64bcst, ymmV, {k}, k1","EVEX.NDS.256.66.0F38.W1 27 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPTESTMQ k1, {k}, zmmV, zmm2/m512/m64bcst","VPTESTMQ zmm2/m512/m64bcst, zmmV, {k}, k1","vptestmq zmm2/m512/m64bcst, zmmV, {k}, k1","EVEX.NDS.512.66.0F38.W1 27 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPTESTMW k1, {k}, xmmV, xmm2/m128","VPTESTMW xmm2/m128, xmmV, {k}, k1","vptestmw xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.66.0F38.W1 26 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPTESTMW k1, {k}, ymmV, ymm2/m256","VPTESTMW ymm2/m256, ymmV, {k}, k1","vptestmw ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.66.0F38.W1 26 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPTESTMW k1, {k}, zmmV, zmm2/m512","VPTESTMW zmm2/m512, zmmV, {k}, k1","vptestmw zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.66.0F38.W1 26 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPTESTNMB k1, {k}, xmmV, xmm2/m128","VPTESTNMB xmm2/m128, xmmV, {k}, k1","vptestnmb xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.F3.0F38.W0 26 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPTESTNMB k1, {k}, ymmV, ymm2/m256","VPTESTNMB ymm2/m256, ymmV, {k}, k1","vptestnmb ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.F3.0F38.W0 26 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPTESTNMB k1, {k}, zmmV, zmm2/m512","VPTESTNMB zmm2/m512, zmmV, {k}, k1","vptestnmb zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.F3.0F38.W0 26 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPTESTNMD k1, {k}, xmmV, xmm2/m128/m32bcst","VPTESTNMD xmm2/m128/m32bcst, xmmV, {k}, k1","vptestnmd xmm2/m128/m32bcst, xmmV, {k}, k1","EVEX.NDS.128.F3.0F38.W0 27 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPTESTNMD k1, {k}, ymmV, ymm2/m256/m32bcst","VPTESTNMD ymm2/m256/m32bcst, ymmV, {k}, k1","vptestnmd ymm2/m256/m32bcst, ymmV, {k}, k1","EVEX.NDS.256.F3.0F38.W0 27 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPTESTNMD k1, {k}, zmmV, zmm2/m512/m32bcst","VPTESTNMD zmm2/m512/m32bcst, zmmV, {k}, k1","vptestnmd zmm2/m512/m32bcst, zmmV, {k}, k1","EVEX.NDS.512.F3.0F38.W0 27 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPTESTNMQ k1, {k}, xmmV, xmm2/m128/m64bcst","VPTESTNMQ xmm2/m128/m64bcst, xmmV, {k}, k1","vptestnmq xmm2/m128/m64bcst, xmmV, {k}, k1","EVEX.NDS.128.F3.0F38.W1 27 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPTESTNMQ k1, {k}, ymmV, ymm2/m256/m64bcst","VPTESTNMQ ymm2/m256/m64bcst, ymmV, {k}, k1","vptestnmq ymm2/m256/m64bcst, ymmV, {k}, k1","EVEX.NDS.256.F3.0F38.W1 27 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPTESTNMQ k1, {k}, zmmV, zmm2/m512/m64bcst","VPTESTNMQ zmm2/m512/m64bcst, zmmV, {k}, k1","vptestnmq zmm2/m512/m64bcst, zmmV, {k}, k1","EVEX.NDS.512.F3.0F38.W1 27 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPTESTNMW k1, {k}, xmmV, xmm2/m128","VPTESTNMW xmm2/m128, xmmV, {k}, k1","vptestnmw xmm2/m128, xmmV, {k}, k1","EVEX.NDS.128.F3.0F38.W1 26 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPTESTNMW k1, {k}, ymmV, ymm2/m256","VPTESTNMW ymm2/m256, ymmV, {k}, k1","vptestnmw ymm2/m256, ymmV, {k}, k1","EVEX.NDS.256.F3.0F38.W1 26 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPTESTNMW k1, {k}, zmmV, zmm2/m512","VPTESTNMW zmm2/m512, zmmV, {k}, k1","vptestnmw zmm2/m512, zmmV, {k}, k1","EVEX.NDS.512.F3.0F38.W1 26 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPUNPCKHBW xmm1, xmmV, xmm2/m128","VPUNPCKHBW xmm2/m128, xmmV, xmm1","vpunpckhbw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 68 /r","V","V","AVX","","w,r,r","","" +"VPUNPCKHBW xmm1, {k}{z}, xmmV, xmm2/m128","VPUNPCKHBW xmm2/m128, xmmV, {k}{z}, xmm1","vpunpckhbw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG 68 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPUNPCKHBW ymm1, ymmV, ymm2/m256","VPUNPCKHBW ymm2/m256, ymmV, ymm1","vpunpckhbw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 68 /r","V","V","AVX2","","w,r,r","","" +"VPUNPCKHBW ymm1, {k}{z}, ymmV, ymm2/m256","VPUNPCKHBW ymm2/m256, ymmV, {k}{z}, ymm1","vpunpckhbw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG 68 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPUNPCKHBW zmm1, {k}{z}, zmmV, zmm2/m512","VPUNPCKHBW zmm2/m512, zmmV, {k}{z}, zmm1","vpunpckhbw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG 68 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPUNPCKHDQ xmm1, xmmV, xmm2/m128","VPUNPCKHDQ xmm2/m128, xmmV, xmm1","vpunpckhdq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 6A /r","V","V","AVX","","w,r,r","","" +"VPUNPCKHDQ xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPUNPCKHDQ xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpunpckhdq xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 6A /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPUNPCKHDQ ymm1, ymmV, ymm2/m256","VPUNPCKHDQ ymm2/m256, ymmV, ymm1","vpunpckhdq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 6A /r","V","V","AVX2","","w,r,r","","" +"VPUNPCKHDQ ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPUNPCKHDQ ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpunpckhdq ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 6A /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPUNPCKHDQ zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPUNPCKHDQ zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpunpckhdq zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 6A /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPUNPCKHQDQ xmm1, xmmV, xmm2/m128","VPUNPCKHQDQ xmm2/m128, xmmV, xmm1","vpunpckhqdq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 6D /r","V","V","AVX","","w,r,r","","" +"VPUNPCKHQDQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPUNPCKHQDQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpunpckhqdq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 6D /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPUNPCKHQDQ ymm1, ymmV, ymm2/m256","VPUNPCKHQDQ ymm2/m256, ymmV, ymm1","vpunpckhqdq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 6D /r","V","V","AVX2","","w,r,r","","" +"VPUNPCKHQDQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPUNPCKHQDQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpunpckhqdq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 6D /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPUNPCKHQDQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPUNPCKHQDQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpunpckhqdq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 6D /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPUNPCKHWD xmm1, xmmV, xmm2/m128","VPUNPCKHWD xmm2/m128, xmmV, xmm1","vpunpckhwd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 69 /r","V","V","AVX","","w,r,r","","" +"VPUNPCKHWD xmm1, {k}{z}, xmmV, xmm2/m128","VPUNPCKHWD xmm2/m128, xmmV, {k}{z}, xmm1","vpunpckhwd xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG 69 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPUNPCKHWD ymm1, ymmV, ymm2/m256","VPUNPCKHWD ymm2/m256, ymmV, ymm1","vpunpckhwd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 69 /r","V","V","AVX2","","w,r,r","","" +"VPUNPCKHWD ymm1, {k}{z}, ymmV, ymm2/m256","VPUNPCKHWD ymm2/m256, ymmV, {k}{z}, ymm1","vpunpckhwd ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG 69 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPUNPCKHWD zmm1, {k}{z}, zmmV, zmm2/m512","VPUNPCKHWD zmm2/m512, zmmV, {k}{z}, zmm1","vpunpckhwd zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG 69 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPUNPCKLBW xmm1, xmmV, xmm2/m128","VPUNPCKLBW xmm2/m128, xmmV, xmm1","vpunpcklbw xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 60 /r","V","V","AVX","","w,r,r","","" +"VPUNPCKLBW xmm1, {k}{z}, xmmV, xmm2/m128","VPUNPCKLBW xmm2/m128, xmmV, {k}{z}, xmm1","vpunpcklbw xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG 60 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPUNPCKLBW ymm1, ymmV, ymm2/m256","VPUNPCKLBW ymm2/m256, ymmV, ymm1","vpunpcklbw ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 60 /r","V","V","AVX2","","w,r,r","","" +"VPUNPCKLBW ymm1, {k}{z}, ymmV, ymm2/m256","VPUNPCKLBW ymm2/m256, ymmV, {k}{z}, ymm1","vpunpcklbw ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG 60 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPUNPCKLBW zmm1, {k}{z}, zmmV, zmm2/m512","VPUNPCKLBW zmm2/m512, zmmV, {k}{z}, zmm1","vpunpcklbw zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG 60 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPUNPCKLDQ xmm1, xmmV, xmm2/m128","VPUNPCKLDQ xmm2/m128, xmmV, xmm1","vpunpckldq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 62 /r","V","V","AVX","","w,r,r","","" +"VPUNPCKLDQ xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPUNPCKLDQ xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpunpckldq xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 62 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPUNPCKLDQ ymm1, ymmV, ymm2/m256","VPUNPCKLDQ ymm2/m256, ymmV, ymm1","vpunpckldq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 62 /r","V","V","AVX2","","w,r,r","","" +"VPUNPCKLDQ ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPUNPCKLDQ ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpunpckldq ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 62 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPUNPCKLDQ zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPUNPCKLDQ zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpunpckldq zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 62 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPUNPCKLQDQ xmm1, xmmV, xmm2/m128","VPUNPCKLQDQ xmm2/m128, xmmV, xmm1","vpunpcklqdq xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 6C /r","V","V","AVX","","w,r,r","","" +"VPUNPCKLQDQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPUNPCKLQDQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpunpcklqdq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 6C /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPUNPCKLQDQ ymm1, ymmV, ymm2/m256","VPUNPCKLQDQ ymm2/m256, ymmV, ymm1","vpunpcklqdq ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 6C /r","V","V","AVX2","","w,r,r","","" +"VPUNPCKLQDQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPUNPCKLQDQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpunpcklqdq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 6C /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPUNPCKLQDQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPUNPCKLQDQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpunpcklqdq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 6C /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VPUNPCKLWD xmm1, xmmV, xmm2/m128","VPUNPCKLWD xmm2/m128, xmmV, xmm1","vpunpcklwd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 61 /r","V","V","AVX","","w,r,r","","" +"VPUNPCKLWD xmm1, {k}{z}, xmmV, xmm2/m128","VPUNPCKLWD xmm2/m128, xmmV, {k}{z}, xmm1","vpunpcklwd xmm2/m128, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.WIG 61 /r","V","V","AVX512BW+AVX512VL","scale16","w,r,r,r","","" +"VPUNPCKLWD ymm1, ymmV, ymm2/m256","VPUNPCKLWD ymm2/m256, ymmV, ymm1","vpunpcklwd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 61 /r","V","V","AVX2","","w,r,r","","" +"VPUNPCKLWD ymm1, {k}{z}, ymmV, ymm2/m256","VPUNPCKLWD ymm2/m256, ymmV, {k}{z}, ymm1","vpunpcklwd ymm2/m256, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.WIG 61 /r","V","V","AVX512BW+AVX512VL","scale32","w,r,r,r","","" +"VPUNPCKLWD zmm1, {k}{z}, zmmV, zmm2/m512","VPUNPCKLWD zmm2/m512, zmmV, {k}{z}, zmm1","vpunpcklwd zmm2/m512, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.WIG 61 /r","V","V","AVX512BW","scale64","w,r,r,r","","" +"VPXOR xmm1, xmmV, xmm2/m128","VPXOR xmm2/m128, xmmV, xmm1","vpxor xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG EF /r","V","V","AVX","","w,r,r","","" +"VPXOR ymm1, ymmV, ymm2/m256","VPXOR ymm2/m256, ymmV, ymm1","vpxor ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG EF /r","V","V","AVX2","","w,r,r","","" +"VPXORD xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VPXORD xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vpxord xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W0 EF /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VPXORD ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VPXORD ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vpxord ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W0 EF /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VPXORD zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VPXORD zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vpxord zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W0 EF /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VPXORQ xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VPXORQ xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vpxorq xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 EF /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VPXORQ ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VPXORQ ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vpxorq ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 EF /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VPXORQ zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VPXORQ zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vpxorq zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 EF /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VRANGEPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u:4","VRANGEPD imm8u:4, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vrangepd imm8u:4, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W1 50 /r ib","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VRANGEPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u:4","VRANGEPD imm8u:4, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vrangepd imm8u:4, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 50 /r ib","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VRANGEPD zmm1{sae}, {k}{z}, zmmV, zmm2, imm8u:4","VRANGEPD imm8u:4, zmm2, zmmV, {k}{z}, zmm1{sae}","vrangepd imm8u:4, zmm2, zmmV, {k}{z}, zmm1{sae}","EVEX.NDS.512.66.0F3A.W1 50 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r,r,r","","" +"VRANGEPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u:4","VRANGEPD imm8u:4, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vrangepd imm8u:4, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 50 /r ib","V","V","AVX512DQ","bscale8,scale64","w,r,r,r,r","","" +"VRANGEPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst, imm8u:4","VRANGEPS imm8u:4, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vrangeps imm8u:4, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F3A.W0 50 /r ib","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r,r,r","","" +"VRANGEPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u:4","VRANGEPS imm8u:4, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vrangeps imm8u:4, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 50 /r ib","V","V","AVX512DQ+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VRANGEPS zmm1{sae}, {k}{z}, zmmV, zmm2, imm8u:4","VRANGEPS imm8u:4, zmm2, zmmV, {k}{z}, zmm1{sae}","vrangeps imm8u:4, zmm2, zmmV, {k}{z}, zmm1{sae}","EVEX.NDS.512.66.0F3A.W0 50 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r,r,r","","" +"VRANGEPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u:4","VRANGEPS imm8u:4, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vrangeps imm8u:4, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 50 /r ib","V","V","AVX512DQ","bscale4,scale64","w,r,r,r,r","","" +"VRANGESD xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u:4","VRANGESD imm8u:4, xmm2, xmmV, {k}{z}, xmm1{sae}","vrangesd imm8u:4, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F3A.W1 51 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r,r,r","","" +"VRANGESD xmm1, {k}{z}, xmmV, xmm2/m64, imm8u:4","VRANGESD imm8u:4, xmm2/m64, xmmV, {k}{z}, xmm1","vrangesd imm8u:4, xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F3A.W1 51 /r ib","V","V","AVX512DQ","scale8","w,r,r,r,r","","" +"VRANGESS xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u:4","VRANGESS imm8u:4, xmm2, xmmV, {k}{z}, xmm1{sae}","vrangess imm8u:4, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F3A.W0 51 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r,r,r","","" +"VRANGESS xmm1, {k}{z}, xmmV, xmm2/m32, imm8u:4","VRANGESS imm8u:4, xmm2/m32, xmmV, {k}{z}, xmm1","vrangess imm8u:4, xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F3A.W0 51 /r ib","V","V","AVX512DQ","scale4","w,r,r,r,r","","" +"VRCP14PD xmm1, {k}{z}, xmm2/m128/m64bcst","VRCP14PD xmm2/m128/m64bcst, {k}{z}, xmm1","vrcp14pd xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W1 4C /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","","" +"VRCP14PD ymm1, {k}{z}, ymm2/m256/m64bcst","VRCP14PD ymm2/m256/m64bcst, {k}{z}, ymm1","vrcp14pd ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W1 4C /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","","" +"VRCP14PD zmm1, {k}{z}, zmm2/m512/m64bcst","VRCP14PD zmm2/m512/m64bcst, {k}{z}, zmm1","vrcp14pd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 4C /r","V","V","AVX512F","bscale8,scale64","w,r,r","","" +"VRCP14PS xmm1, {k}{z}, xmm2/m128/m32bcst","VRCP14PS xmm2/m128/m32bcst, {k}{z}, xmm1","vrcp14ps xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W0 4C /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VRCP14PS ymm1, {k}{z}, ymm2/m256/m32bcst","VRCP14PS ymm2/m256/m32bcst, {k}{z}, ymm1","vrcp14ps ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W0 4C /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VRCP14PS zmm1, {k}{z}, zmm2/m512/m32bcst","VRCP14PS zmm2/m512/m32bcst, {k}{z}, zmm1","vrcp14ps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 4C /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VRCP14SD xmm1, {k}{z}, xmmV, xmm2/m64","VRCP14SD xmm2/m64, xmmV, {k}{z}, xmm1","vrcp14sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W1 4D /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VRCP14SS xmm1, {k}{z}, xmmV, xmm2/m32","VRCP14SS xmm2/m32, xmmV, {k}{z}, xmm1","vrcp14ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W0 4D /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VRCP28PD zmm1{sae}, {k}{z}, zmm2","VRCP28PD zmm2, {k}{z}, zmm1{sae}","vrcp28pd zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W1 CA /r","V","V","AVX512ER","modrm_regonly","w,r,r","","" +"VRCP28PD zmm1, {k}{z}, zmm2/m512/m64bcst","VRCP28PD zmm2/m512/m64bcst, {k}{z}, zmm1","vrcp28pd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 CA /r","V","V","AVX512ER","bscale8,scale64","w,r,r","","" +"VRCP28PS zmm1{sae}, {k}{z}, zmm2","VRCP28PS zmm2, {k}{z}, zmm1{sae}","vrcp28ps zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W0 CA /r","V","V","AVX512ER","modrm_regonly","w,r,r","","" +"VRCP28PS zmm1, {k}{z}, zmm2/m512/m32bcst","VRCP28PS zmm2/m512/m32bcst, {k}{z}, zmm1","vrcp28ps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 CA /r","V","V","AVX512ER","bscale4,scale64","w,r,r","","" +"VRCP28SD xmm1{sae}, {k}{z}, xmmV, xmm2","VRCP28SD xmm2, xmmV, {k}{z}, xmm1{sae}","vrcp28sd xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F38.W1 CB /r","V","V","AVX512ER","modrm_regonly","w,r,r,r","","" +"VRCP28SD xmm1, {k}{z}, xmmV, xmm2/m64","VRCP28SD xmm2/m64, xmmV, {k}{z}, xmm1","vrcp28sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W1 CB /r","V","V","AVX512ER","scale8","w,r,r,r","","" +"VRCP28SS xmm1{sae}, {k}{z}, xmmV, xmm2","VRCP28SS xmm2, xmmV, {k}{z}, xmm1{sae}","vrcp28ss xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F38.W0 CB /r","V","V","AVX512ER","modrm_regonly","w,r,r,r","","" +"VRCP28SS xmm1, {k}{z}, xmmV, xmm2/m32","VRCP28SS xmm2/m32, xmmV, {k}{z}, xmm1","vrcp28ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W0 CB /r","V","V","AVX512ER","scale4","w,r,r,r","","" +"VRCPPS xmm1, xmm2/m128","VRCPPS xmm2/m128, xmm1","vrcpps xmm2/m128, xmm1","VEX.128.0F.WIG 53 /r","V","V","AVX","","w,r","","" +"VRCPPS ymm1, ymm2/m256","VRCPPS ymm2/m256, ymm1","vrcpps ymm2/m256, ymm1","VEX.256.0F.WIG 53 /r","V","V","AVX","","w,r","","" +"VRCPSS xmm1, xmmV, xmm2/m32","VRCPSS xmm2/m32, xmmV, xmm1","vrcpss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 53 /r","V","V","AVX","","w,r,r","","" +"VREDUCEPD xmm1, {k}{z}, xmm2/m128/m64bcst, imm8u","VREDUCEPD imm8u, xmm2/m128/m64bcst, {k}{z}, xmm1","vreducepd imm8u, xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F3A.W1 56 /r ib","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VREDUCEPD ymm1, {k}{z}, ymm2/m256/m64bcst, imm8u","VREDUCEPD imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","vreducepd imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W1 56 /r ib","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VREDUCEPD zmm1{sae}, {k}{z}, zmm2, imm8u","VREDUCEPD imm8u, zmm2, {k}{z}, zmm1{sae}","vreducepd imm8u, zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F3A.W1 56 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r,r","","" +"VREDUCEPD zmm1, {k}{z}, zmm2/m512/m64bcst, imm8u","VREDUCEPD imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","vreducepd imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W1 56 /r ib","V","V","AVX512DQ","bscale8,scale64","w,r,r,r","","" +"VREDUCEPS xmm1, {k}{z}, xmm2/m128/m32bcst, imm8u","VREDUCEPS imm8u, xmm2/m128/m32bcst, {k}{z}, xmm1","vreduceps imm8u, xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F3A.W0 56 /r ib","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VREDUCEPS ymm1, {k}{z}, ymm2/m256/m32bcst, imm8u","VREDUCEPS imm8u, ymm2/m256/m32bcst, {k}{z}, ymm1","vreduceps imm8u, ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W0 56 /r ib","V","V","AVX512DQ+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VREDUCEPS zmm1{sae}, {k}{z}, zmm2, imm8u","VREDUCEPS imm8u, zmm2, {k}{z}, zmm1{sae}","vreduceps imm8u, zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F3A.W0 56 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r,r","","" +"VREDUCEPS zmm1, {k}{z}, zmm2/m512/m32bcst, imm8u","VREDUCEPS imm8u, zmm2/m512/m32bcst, {k}{z}, zmm1","vreduceps imm8u, zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W0 56 /r ib","V","V","AVX512DQ","bscale4,scale64","w,r,r,r","","" +"VREDUCESD xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u","VREDUCESD imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","vreducesd imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F3A.W1 57 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r,r,r","","" +"VREDUCESD xmm1, {k}{z}, xmmV, xmm2/m64, imm8u","VREDUCESD imm8u, xmm2/m64, xmmV, {k}{z}, xmm1","vreducesd imm8u, xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F3A.W1 57 /r ib","V","V","AVX512DQ","scale8","w,r,r,r,r","","" +"VREDUCESS xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u","VREDUCESS imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","vreducess imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F3A.W0 57 /r ib","V","V","AVX512DQ","modrm_regonly","w,r,r,r,r","","" +"VREDUCESS xmm1, {k}{z}, xmmV, xmm2/m32, imm8u","VREDUCESS imm8u, xmm2/m32, xmmV, {k}{z}, xmm1","vreducess imm8u, xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F3A.W0 57 /r ib","V","V","AVX512DQ","scale4","w,r,r,r,r","","" +"VRNDSCALEPD xmm1, {k}{z}, xmm2/m128/m64bcst, imm8u","VRNDSCALEPD imm8u, xmm2/m128/m64bcst, {k}{z}, xmm1","vrndscalepd imm8u, xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F3A.W1 09 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VRNDSCALEPD ymm1, {k}{z}, ymm2/m256/m64bcst, imm8u","VRNDSCALEPD imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","vrndscalepd imm8u, ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W1 09 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VRNDSCALEPD zmm1{sae}, {k}{z}, zmm2, imm8u","VRNDSCALEPD imm8u, zmm2, {k}{z}, zmm1{sae}","vrndscalepd imm8u, zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F3A.W1 09 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VRNDSCALEPD zmm1, {k}{z}, zmm2/m512/m64bcst, imm8u","VRNDSCALEPD imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","vrndscalepd imm8u, zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W1 09 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VRNDSCALEPS xmm1, {k}{z}, xmm2/m128/m32bcst, imm8u","VRNDSCALEPS imm8u, xmm2/m128/m32bcst, {k}{z}, xmm1","vrndscaleps imm8u, xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F3A.W0 08 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VRNDSCALEPS ymm1, {k}{z}, ymm2/m256/m32bcst, imm8u","VRNDSCALEPS imm8u, ymm2/m256/m32bcst, {k}{z}, ymm1","vrndscaleps imm8u, ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F3A.W0 08 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VRNDSCALEPS zmm1{sae}, {k}{z}, zmm2, imm8u","VRNDSCALEPS imm8u, zmm2, {k}{z}, zmm1{sae}","vrndscaleps imm8u, zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F3A.W0 08 /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VRNDSCALEPS zmm1, {k}{z}, zmm2/m512/m32bcst, imm8u","VRNDSCALEPS imm8u, zmm2/m512/m32bcst, {k}{z}, zmm1","vrndscaleps imm8u, zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F3A.W0 08 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VRNDSCALESD xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u","VRNDSCALESD imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","vrndscalesd imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F3A.W1 0B /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r,r","","" +"VRNDSCALESD xmm1, {k}{z}, xmmV, xmm2/m64, imm8u","VRNDSCALESD imm8u, xmm2/m64, xmmV, {k}{z}, xmm1","vrndscalesd imm8u, xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F3A.W1 0B /r ib","V","V","AVX512F","scale8","w,r,r,r,r","","" +"VRNDSCALESS xmm1{sae}, {k}{z}, xmmV, xmm2, imm8u","VRNDSCALESS imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","vrndscaless imm8u, xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F3A.W0 0A /r ib","V","V","AVX512F","modrm_regonly","w,r,r,r,r","","" +"VRNDSCALESS xmm1, {k}{z}, xmmV, xmm2/m32, imm8u","VRNDSCALESS imm8u, xmm2/m32, xmmV, {k}{z}, xmm1","vrndscaless imm8u, xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F3A.W0 0A /r ib","V","V","AVX512F","scale4","w,r,r,r,r","","" +"VROUNDPD xmm1, xmm2/m128, imm8u","VROUNDPD imm8u, xmm2/m128, xmm1","vroundpd imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.WIG 09 /r ib","V","V","AVX","","w,r,r","","" +"VROUNDPD ymm1, ymm2/m256, imm8u","VROUNDPD imm8u, ymm2/m256, ymm1","vroundpd imm8u, ymm2/m256, ymm1","VEX.256.66.0F3A.WIG 09 /r ib","V","V","AVX","","w,r,r","","" +"VROUNDPS xmm1, xmm2/m128, imm8u","VROUNDPS imm8u, xmm2/m128, xmm1","vroundps imm8u, xmm2/m128, xmm1","VEX.128.66.0F3A.WIG 08 /r ib","V","V","AVX","","w,r,r","","" +"VROUNDPS ymm1, ymm2/m256, imm8u","VROUNDPS imm8u, ymm2/m256, ymm1","vroundps imm8u, ymm2/m256, ymm1","VEX.256.66.0F3A.WIG 08 /r ib","V","V","AVX","","w,r,r","","" +"VROUNDSD xmm1, xmmV, xmm2/m64, imm8u","VROUNDSD imm8u, xmm2/m64, xmmV, xmm1","vroundsd imm8u, xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.WIG 0B /r ib","V","V","AVX","","w,r,r,r","","" +"VROUNDSS xmm1, xmmV, xmm2/m32, imm8u","VROUNDSS imm8u, xmm2/m32, xmmV, xmm1","vroundss imm8u, xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.66.0F3A.WIG 0A /r ib","V","V","AVX","","w,r,r,r","","" +"VRSQRT14PD xmm1, {k}{z}, xmm2/m128/m64bcst","VRSQRT14PD xmm2/m128/m64bcst, {k}{z}, xmm1","vrsqrt14pd xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W1 4E /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","","" +"VRSQRT14PD ymm1, {k}{z}, ymm2/m256/m64bcst","VRSQRT14PD ymm2/m256/m64bcst, {k}{z}, ymm1","vrsqrt14pd ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W1 4E /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","","" +"VRSQRT14PD zmm1, {k}{z}, zmm2/m512/m64bcst","VRSQRT14PD zmm2/m512/m64bcst, {k}{z}, zmm1","vrsqrt14pd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 4E /r","V","V","AVX512F","bscale8,scale64","w,r,r","","" +"VRSQRT14PS xmm1, {k}{z}, xmm2/m128/m32bcst","VRSQRT14PS xmm2/m128/m32bcst, {k}{z}, xmm1","vrsqrt14ps xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.66.0F38.W0 4E /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VRSQRT14PS ymm1, {k}{z}, ymm2/m256/m32bcst","VRSQRT14PS ymm2/m256/m32bcst, {k}{z}, ymm1","vrsqrt14ps ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.66.0F38.W0 4E /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VRSQRT14PS zmm1, {k}{z}, zmm2/m512/m32bcst","VRSQRT14PS zmm2/m512/m32bcst, {k}{z}, zmm1","vrsqrt14ps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 4E /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VRSQRT14SD xmm1, {k}{z}, xmmV, xmm2/m64","VRSQRT14SD xmm2/m64, xmmV, {k}{z}, xmm1","vrsqrt14sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W1 4F /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VRSQRT14SS xmm1, {k}{z}, xmmV, xmm2/m32","VRSQRT14SS xmm2/m32, xmmV, {k}{z}, xmm1","vrsqrt14ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W0 4F /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VRSQRT28PD zmm1{sae}, {k}{z}, zmm2","VRSQRT28PD zmm2, {k}{z}, zmm1{sae}","vrsqrt28pd zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W1 CC /r","V","V","AVX512ER","modrm_regonly","w,r,r","","" +"VRSQRT28PD zmm1, {k}{z}, zmm2/m512/m64bcst","VRSQRT28PD zmm2/m512/m64bcst, {k}{z}, zmm1","vrsqrt28pd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W1 CC /r","V","V","AVX512ER","bscale8,scale64","w,r,r","","" +"VRSQRT28PS zmm1{sae}, {k}{z}, zmm2","VRSQRT28PS zmm2, {k}{z}, zmm1{sae}","vrsqrt28ps zmm2, {k}{z}, zmm1{sae}","EVEX.512.66.0F38.W0 CC /r","V","V","AVX512ER","modrm_regonly","w,r,r","","" +"VRSQRT28PS zmm1, {k}{z}, zmm2/m512/m32bcst","VRSQRT28PS zmm2/m512/m32bcst, {k}{z}, zmm1","vrsqrt28ps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.66.0F38.W0 CC /r","V","V","AVX512ER","bscale4,scale64","w,r,r","","" +"VRSQRT28SD xmm1{sae}, {k}{z}, xmmV, xmm2","VRSQRT28SD xmm2, xmmV, {k}{z}, xmm1{sae}","vrsqrt28sd xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F38.W1 CD /r","V","V","AVX512ER","modrm_regonly","w,r,r,r","","" +"VRSQRT28SD xmm1, {k}{z}, xmmV, xmm2/m64","VRSQRT28SD xmm2/m64, xmmV, {k}{z}, xmm1","vrsqrt28sd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W1 CD /r","V","V","AVX512ER","scale8","w,r,r,r","","" +"VRSQRT28SS xmm1{sae}, {k}{z}, xmmV, xmm2","VRSQRT28SS xmm2, xmmV, {k}{z}, xmm1{sae}","vrsqrt28ss xmm2, xmmV, {k}{z}, xmm1{sae}","EVEX.NDS.128.66.0F38.W0 CD /r","V","V","AVX512ER","modrm_regonly","w,r,r,r","","" +"VRSQRT28SS xmm1, {k}{z}, xmmV, xmm2/m32","VRSQRT28SS xmm2/m32, xmmV, {k}{z}, xmm1","vrsqrt28ss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W0 CD /r","V","V","AVX512ER","scale4","w,r,r,r","","" +"VRSQRTPS xmm1, xmm2/m128","VRSQRTPS xmm2/m128, xmm1","vrsqrtps xmm2/m128, xmm1","VEX.128.0F.WIG 52 /r","V","V","AVX","","w,r","","" +"VRSQRTPS ymm1, ymm2/m256","VRSQRTPS ymm2/m256, ymm1","vrsqrtps ymm2/m256, ymm1","VEX.256.0F.WIG 52 /r","V","V","AVX","","w,r","","" +"VRSQRTSS xmm1, xmmV, xmm2/m32","VRSQRTSS xmm2/m32, xmmV, xmm1","vrsqrtss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 52 /r","V","V","AVX","","w,r,r","","" +"VSCALEFPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VSCALEFPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vscalefpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W1 2C /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VSCALEFPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VSCALEFPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vscalefpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W1 2C /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VSCALEFPD zmm1{er}, {k}{z}, zmmV, zmm2","VSCALEFPD zmm2, zmmV, {k}{z}, zmm1{er}","vscalefpd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.66.0F38.W1 2C /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSCALEFPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VSCALEFPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vscalefpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W1 2C /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VSCALEFPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VSCALEFPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vscalefps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F38.W0 2C /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VSCALEFPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VSCALEFPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vscalefps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F38.W0 2C /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VSCALEFPS zmm1{er}, {k}{z}, zmmV, zmm2","VSCALEFPS zmm2, zmmV, {k}{z}, zmm1{er}","vscalefps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.66.0F38.W0 2C /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSCALEFPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VSCALEFPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vscalefps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F38.W0 2C /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VSCALEFSD xmm1{er}, {k}{z}, xmmV, xmm2","VSCALEFSD xmm2, xmmV, {k}{z}, xmm1{er}","vscalefsd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.66.0F38.W1 2D /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSCALEFSD xmm1, {k}{z}, xmmV, xmm2/m64","VSCALEFSD xmm2/m64, xmmV, {k}{z}, xmm1","vscalefsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W1 2D /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VSCALEFSS xmm1{er}, {k}{z}, xmmV, xmm2","VSCALEFSS xmm2, xmmV, {k}{z}, xmm1{er}","vscalefss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.66.0F38.W0 2D /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSCALEFSS xmm1, {k}{z}, xmmV, xmm2/m32","VSCALEFSS xmm2/m32, xmmV, {k}{z}, xmm1","vscalefss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.66.0F38.W0 2D /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VSCATTERDPD vm32x, {k1-k7}, xmm1","VSCATTERDPD xmm1, {k1-k7}, vm32x","vscatterdpd xmm1, {k1-k7}, vm32x","EVEX.128.66.0F38.W1 A2 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VSCATTERDPD vm32x, {k1-k7}, ymm1","VSCATTERDPD ymm1, {k1-k7}, vm32x","vscatterdpd ymm1, {k1-k7}, vm32x","EVEX.256.66.0F38.W1 A2 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VSCATTERDPD vm32y, {k1-k7}, zmm1","VSCATTERDPD zmm1, {k1-k7}, vm32y","vscatterdpd zmm1, {k1-k7}, vm32y","EVEX.512.66.0F38.W1 A2 /vsib","V","V","AVX512F","modrm_memonly,scale8","w,rw,r","","" +"VSCATTERDPS vm32x, {k1-k7}, xmm1","VSCATTERDPS xmm1, {k1-k7}, vm32x","vscatterdps xmm1, {k1-k7}, vm32x","EVEX.128.66.0F38.W0 A2 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VSCATTERDPS vm32y, {k1-k7}, ymm1","VSCATTERDPS ymm1, {k1-k7}, vm32y","vscatterdps ymm1, {k1-k7}, vm32y","EVEX.256.66.0F38.W0 A2 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VSCATTERDPS vm32z, {k1-k7}, zmm1","VSCATTERDPS zmm1, {k1-k7}, vm32z","vscatterdps zmm1, {k1-k7}, vm32z","EVEX.512.66.0F38.W0 A2 /vsib","V","V","AVX512F","modrm_memonly,scale4","w,rw,r","","" +"VSCATTERPF0DPD vm32y, {k1-k7}","VSCATTERPF0DPD {k1-k7}, vm32y","vscatterpf0dpd {k1-k7}, vm32y","EVEX.512.66.0F38.W1 C6 /5","V","V","AVX512PF","modrm_memonly,scale8","r,rw","","" +"VSCATTERPF0DPS vm32z, {k1-k7}","VSCATTERPF0DPS {k1-k7}, vm32z","vscatterpf0dps {k1-k7}, vm32z","EVEX.512.66.0F38.W0 C6 /5","V","V","AVX512PF","modrm_memonly,scale4","r,rw","","" +"VSCATTERPF0QPD vm64z, {k1-k7}","VSCATTERPF0QPD {k1-k7}, vm64z","vscatterpf0qpd {k1-k7}, vm64z","EVEX.512.66.0F38.W1 C7 /5","V","V","AVX512PF","modrm_memonly,scale8","r,rw","","" +"VSCATTERPF0QPS vm64z, {k1-k7}","VSCATTERPF0QPS {k1-k7}, vm64z","vscatterpf0qps {k1-k7}, vm64z","EVEX.512.66.0F38.W0 C7 /5","V","V","AVX512PF","modrm_memonly,scale4","r,rw","","" +"VSCATTERPF1DPD vm32y, {k1-k7}","VSCATTERPF1DPD {k1-k7}, vm32y","vscatterpf1dpd {k1-k7}, vm32y","EVEX.512.66.0F38.W1 C6 /6","V","V","AVX512PF","modrm_memonly,scale8","r,rw","","" +"VSCATTERPF1DPS vm32z, {k1-k7}","VSCATTERPF1DPS {k1-k7}, vm32z","vscatterpf1dps {k1-k7}, vm32z","EVEX.512.66.0F38.W0 C6 /6","V","V","AVX512PF","modrm_memonly,scale4","r,rw","","" +"VSCATTERPF1QPD vm64z, {k1-k7}","VSCATTERPF1QPD {k1-k7}, vm64z","vscatterpf1qpd {k1-k7}, vm64z","EVEX.512.66.0F38.W1 C7 /6","V","V","AVX512PF","modrm_memonly,scale8","r,rw","","" +"VSCATTERPF1QPS vm64z, {k1-k7}","VSCATTERPF1QPS {k1-k7}, vm64z","vscatterpf1qps {k1-k7}, vm64z","EVEX.512.66.0F38.W0 C7 /6","V","V","AVX512PF","modrm_memonly,scale4","r,rw","","" +"VSCATTERQPD vm64x, {k1-k7}, xmm1","VSCATTERQPD xmm1, {k1-k7}, vm64x","vscatterqpd xmm1, {k1-k7}, vm64x","EVEX.128.66.0F38.W1 A3 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VSCATTERQPD vm64y, {k1-k7}, ymm1","VSCATTERQPD ymm1, {k1-k7}, vm64y","vscatterqpd ymm1, {k1-k7}, vm64y","EVEX.256.66.0F38.W1 A3 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale8","w,rw,r","","" +"VSCATTERQPD vm64z, {k1-k7}, zmm1","VSCATTERQPD zmm1, {k1-k7}, vm64z","vscatterqpd zmm1, {k1-k7}, vm64z","EVEX.512.66.0F38.W1 A3 /vsib","V","V","AVX512F","modrm_memonly,scale8","w,rw,r","","" +"VSCATTERQPS vm64x, {k1-k7}, xmm1","VSCATTERQPS xmm1, {k1-k7}, vm64x","vscatterqps xmm1, {k1-k7}, vm64x","EVEX.128.66.0F38.W0 A3 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VSCATTERQPS vm64y, {k1-k7}, xmm1","VSCATTERQPS xmm1, {k1-k7}, vm64y","vscatterqps xmm1, {k1-k7}, vm64y","EVEX.256.66.0F38.W0 A3 /vsib","V","V","AVX512F+AVX512VL","modrm_memonly,scale4","w,rw,r","","" +"VSCATTERQPS vm64z, {k1-k7}, ymm1","VSCATTERQPS ymm1, {k1-k7}, vm64z","vscatterqps ymm1, {k1-k7}, vm64z","EVEX.512.66.0F38.W0 A3 /vsib","V","V","AVX512F","modrm_memonly,scale4","w,rw,r","","" +"VSHUFF32X4 ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u","VSHUFF32X4 imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vshuff32x4 imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 23 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VSHUFF32X4 zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u","VSHUFF32X4 imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vshuff32x4 imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 23 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r,r","","" +"VSHUFF64X2 ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VSHUFF64X2 imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vshuff64x2 imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 23 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VSHUFF64X2 zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VSHUFF64X2 imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vshuff64x2 imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 23 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VSHUFI32X4 ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u","VSHUFI32X4 imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vshufi32x4 imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W0 43 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VSHUFI32X4 zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u","VSHUFI32X4 imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vshufi32x4 imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W0 43 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r,r","","" +"VSHUFI64X2 ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VSHUFI64X2 imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vshufi64x2 imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F3A.W1 43 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VSHUFI64X2 zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VSHUFI64X2 imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vshufi64x2 imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F3A.W1 43 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VSHUFPD xmm1, xmmV, xmm2/m128, imm8u","VSHUFPD imm8u, xmm2/m128, xmmV, xmm1","vshufpd imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG C6 /r ib","V","V","AVX","","w,r,r,r","","" +"VSHUFPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst, imm8u","VSHUFPD imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vshufpd imm8u, xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 C6 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r,r","","" +"VSHUFPD ymm1, ymmV, ymm2/m256, imm8u","VSHUFPD imm8u, ymm2/m256, ymmV, ymm1","vshufpd imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG C6 /r ib","V","V","AVX","","w,r,r,r","","" +"VSHUFPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst, imm8u","VSHUFPD imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vshufpd imm8u, ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 C6 /r ib","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r,r","","" +"VSHUFPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst, imm8u","VSHUFPD imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vshufpd imm8u, zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 C6 /r ib","V","V","AVX512F","bscale8,scale64","w,r,r,r,r","","" +"VSHUFPS xmm1, xmmV, xmm2/m128, imm8u","VSHUFPS imm8u, xmm2/m128, xmmV, xmm1","vshufps imm8u, xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG C6 /r ib","V","V","AVX","","w,r,r,r","","" +"VSHUFPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst, imm8u","VSHUFPS imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vshufps imm8u, xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 C6 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r,r","","" +"VSHUFPS ymm1, ymmV, ymm2/m256, imm8u","VSHUFPS imm8u, ymm2/m256, ymmV, ymm1","vshufps imm8u, ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG C6 /r ib","V","V","AVX","","w,r,r,r","","" +"VSHUFPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst, imm8u","VSHUFPS imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vshufps imm8u, ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 C6 /r ib","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r,r","","" +"VSHUFPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst, imm8u","VSHUFPS imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vshufps imm8u, zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 C6 /r ib","V","V","AVX512F","bscale4,scale64","w,r,r,r,r","","" +"VSQRTPD xmm1, xmm2/m128","VSQRTPD xmm2/m128, xmm1","vsqrtpd xmm2/m128, xmm1","VEX.128.66.0F.WIG 51 /r","V","V","AVX","","w,r","","" +"VSQRTPD xmm1, {k}{z}, xmm2/m128/m64bcst","VSQRTPD xmm2/m128/m64bcst, {k}{z}, xmm1","vsqrtpd xmm2/m128/m64bcst, {k}{z}, xmm1","EVEX.128.66.0F.W1 51 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r","","" +"VSQRTPD ymm1, ymm2/m256","VSQRTPD ymm2/m256, ymm1","vsqrtpd ymm2/m256, ymm1","VEX.256.66.0F.WIG 51 /r","V","V","AVX","","w,r","","" +"VSQRTPD ymm1, {k}{z}, ymm2/m256/m64bcst","VSQRTPD ymm2/m256/m64bcst, {k}{z}, ymm1","vsqrtpd ymm2/m256/m64bcst, {k}{z}, ymm1","EVEX.256.66.0F.W1 51 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r","","" +"VSQRTPD zmm1{er}, {k}{z}, zmm2","VSQRTPD zmm2, {k}{z}, zmm1{er}","vsqrtpd zmm2, {k}{z}, zmm1{er}","EVEX.512.66.0F.W1 51 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VSQRTPD zmm1, {k}{z}, zmm2/m512/m64bcst","VSQRTPD zmm2/m512/m64bcst, {k}{z}, zmm1","vsqrtpd zmm2/m512/m64bcst, {k}{z}, zmm1","EVEX.512.66.0F.W1 51 /r","V","V","AVX512F","bscale8,scale64","w,r,r","","" +"VSQRTPS xmm1, xmm2/m128","VSQRTPS xmm2/m128, xmm1","vsqrtps xmm2/m128, xmm1","VEX.128.0F.WIG 51 /r","V","V","AVX","","w,r","","" +"VSQRTPS xmm1, {k}{z}, xmm2/m128/m32bcst","VSQRTPS xmm2/m128/m32bcst, {k}{z}, xmm1","vsqrtps xmm2/m128/m32bcst, {k}{z}, xmm1","EVEX.128.0F.W0 51 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r","","" +"VSQRTPS ymm1, ymm2/m256","VSQRTPS ymm2/m256, ymm1","vsqrtps ymm2/m256, ymm1","VEX.256.0F.WIG 51 /r","V","V","AVX","","w,r","","" +"VSQRTPS ymm1, {k}{z}, ymm2/m256/m32bcst","VSQRTPS ymm2/m256/m32bcst, {k}{z}, ymm1","vsqrtps ymm2/m256/m32bcst, {k}{z}, ymm1","EVEX.256.0F.W0 51 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r","","" +"VSQRTPS zmm1{er}, {k}{z}, zmm2","VSQRTPS zmm2, {k}{z}, zmm1{er}","vsqrtps zmm2, {k}{z}, zmm1{er}","EVEX.512.0F.W0 51 /r","V","V","AVX512F","modrm_regonly","w,r,r","","" +"VSQRTPS zmm1, {k}{z}, zmm2/m512/m32bcst","VSQRTPS zmm2/m512/m32bcst, {k}{z}, zmm1","vsqrtps zmm2/m512/m32bcst, {k}{z}, zmm1","EVEX.512.0F.W0 51 /r","V","V","AVX512F","bscale4,scale64","w,r,r","","" +"VSQRTSD xmm1{er}, {k}{z}, xmmV, xmm2","VSQRTSD xmm2, xmmV, {k}{z}, xmm1{er}","vsqrtsd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F2.0F.W1 51 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSQRTSD xmm1, xmmV, xmm2/m64","VSQRTSD xmm2/m64, xmmV, xmm1","vsqrtsd xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 51 /r","V","V","AVX","","w,r,r","","" +"VSQRTSD xmm1, {k}{z}, xmmV, xmm2/m64","VSQRTSD xmm2/m64, xmmV, {k}{z}, xmm1","vsqrtsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 51 /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VSQRTSS xmm1{er}, {k}{z}, xmmV, xmm2","VSQRTSS xmm2, xmmV, {k}{z}, xmm1{er}","vsqrtss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F3.0F.W0 51 /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSQRTSS xmm1, xmmV, xmm2/m32","VSQRTSS xmm2/m32, xmmV, xmm1","vsqrtss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 51 /r","V","V","AVX","","w,r,r","","" +"VSQRTSS xmm1, {k}{z}, xmmV, xmm2/m32","VSQRTSS xmm2/m32, xmmV, {k}{z}, xmm1","vsqrtss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 51 /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VSTMXCSR m32","VSTMXCSR m32","vstmxcsr m32","VEX.128.0F.WIG AE /3","V","V","AVX","modrm_memonly","w","","" +"VSUBPD xmm1, xmmV, xmm2/m128","VSUBPD xmm2/m128, xmmV, xmm1","vsubpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 5C /r","V","V","AVX","","w,r,r","","" +"VSUBPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VSUBPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vsubpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 5C /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VSUBPD ymm1, ymmV, ymm2/m256","VSUBPD ymm2/m256, ymmV, ymm1","vsubpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 5C /r","V","V","AVX","","w,r,r","","" +"VSUBPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VSUBPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vsubpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 5C /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VSUBPD zmm1{er}, {k}{z}, zmmV, zmm2","VSUBPD zmm2, zmmV, {k}{z}, zmm1{er}","vsubpd zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.66.0F.W1 5C /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSUBPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VSUBPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vsubpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 5C /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VSUBPS xmm1, xmmV, xmm2/m128","VSUBPS xmm2/m128, xmmV, xmm1","vsubps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 5C /r","V","V","AVX","","w,r,r","","" +"VSUBPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VSUBPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vsubps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 5C /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VSUBPS ymm1, ymmV, ymm2/m256","VSUBPS ymm2/m256, ymmV, ymm1","vsubps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 5C /r","V","V","AVX","","w,r,r","","" +"VSUBPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VSUBPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vsubps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 5C /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VSUBPS zmm1{er}, {k}{z}, zmmV, zmm2","VSUBPS zmm2, zmmV, {k}{z}, zmm1{er}","vsubps zmm2, zmmV, {k}{z}, zmm1{er}","EVEX.NDS.512.0F.W0 5C /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSUBPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VSUBPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vsubps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 5C /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VSUBSD xmm1{er}, {k}{z}, xmmV, xmm2","VSUBSD xmm2, xmmV, {k}{z}, xmm1{er}","vsubsd xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F2.0F.W1 5C /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSUBSD xmm1, xmmV, xmm2/m64","VSUBSD xmm2/m64, xmmV, xmm1","vsubsd xmm2/m64, xmmV, xmm1","VEX.NDS.LIG.F2.0F.WIG 5C /r","V","V","AVX","","w,r,r","","" +"VSUBSD xmm1, {k}{z}, xmmV, xmm2/m64","VSUBSD xmm2/m64, xmmV, {k}{z}, xmm1","vsubsd xmm2/m64, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F2.0F.W1 5C /r","V","V","AVX512F","scale8","w,r,r,r","","" +"VSUBSS xmm1{er}, {k}{z}, xmmV, xmm2","VSUBSS xmm2, xmmV, {k}{z}, xmm1{er}","vsubss xmm2, xmmV, {k}{z}, xmm1{er}","EVEX.NDS.128.F3.0F.W0 5C /r","V","V","AVX512F","modrm_regonly","w,r,r,r","","" +"VSUBSS xmm1, xmmV, xmm2/m32","VSUBSS xmm2/m32, xmmV, xmm1","vsubss xmm2/m32, xmmV, xmm1","VEX.NDS.LIG.F3.0F.WIG 5C /r","V","V","AVX","","w,r,r","","" +"VSUBSS xmm1, {k}{z}, xmmV, xmm2/m32","VSUBSS xmm2/m32, xmmV, {k}{z}, xmm1","vsubss xmm2/m32, xmmV, {k}{z}, xmm1","EVEX.NDS.LIG.F3.0F.W0 5C /r","V","V","AVX512F","scale4","w,r,r,r","","" +"VTESTPD xmm1, xmm2/m128","VTESTPD xmm2/m128, xmm1","vtestpd xmm2/m128, xmm1","VEX.128.66.0F38.W0 0F /r","V","V","AVX","","r,r","","" +"VTESTPD ymm1, ymm2/m256","VTESTPD ymm2/m256, ymm1","vtestpd ymm2/m256, ymm1","VEX.256.66.0F38.W0 0F /r","V","V","AVX","","r,r","","" +"VTESTPS xmm1, xmm2/m128","VTESTPS xmm2/m128, xmm1","vtestps xmm2/m128, xmm1","VEX.128.66.0F38.W0 0E /r","V","V","AVX","","r,r","","" +"VTESTPS ymm1, ymm2/m256","VTESTPS ymm2/m256, ymm1","vtestps ymm2/m256, ymm1","VEX.256.66.0F38.W0 0E /r","V","V","AVX","","r,r","","" +"VUCOMISD xmm1{sae}, xmm2","VUCOMISD xmm2, xmm1{sae}","vucomisd xmm2, xmm1{sae}","EVEX.128.66.0F.W1 2E /r","V","V","AVX512F","modrm_regonly","r,r","","" +"VUCOMISD xmm1, xmm2/m64","VUCOMISD xmm2/m64, xmm1","vucomisd xmm2/m64, xmm1","EVEX.LIG.66.0F.W1 2E /r","V","V","AVX512F","scale8","r,r","","" +"VUCOMISD xmm1, xmm2/m64","VUCOMISD xmm2/m64, xmm1","vucomisd xmm2/m64, xmm1","VEX.LIG.66.0F.WIG 2E /r","V","V","AVX","","r,r","","" +"VUCOMISS xmm1{sae}, xmm2","VUCOMISS xmm2, xmm1{sae}","vucomiss xmm2, xmm1{sae}","EVEX.128.0F.W0 2E /r","V","V","AVX512F","modrm_regonly","r,r","","" +"VUCOMISS xmm1, xmm2/m32","VUCOMISS xmm2/m32, xmm1","vucomiss xmm2/m32, xmm1","EVEX.LIG.0F.W0 2E /r","V","V","AVX512F","scale4","r,r","","" +"VUCOMISS xmm1, xmm2/m32","VUCOMISS xmm2/m32, xmm1","vucomiss xmm2/m32, xmm1","VEX.LIG.0F.WIG 2E /r","V","V","AVX","","r,r","","" +"VUNPCKHPD xmm1, xmmV, xmm2/m128","VUNPCKHPD xmm2/m128, xmmV, xmm1","vunpckhpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 15 /r","V","V","AVX","","w,r,r","","" +"VUNPCKHPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VUNPCKHPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vunpckhpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 15 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VUNPCKHPD ymm1, ymmV, ymm2/m256","VUNPCKHPD ymm2/m256, ymmV, ymm1","vunpckhpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 15 /r","V","V","AVX","","w,r,r","","" +"VUNPCKHPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VUNPCKHPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vunpckhpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 15 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VUNPCKHPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VUNPCKHPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vunpckhpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 15 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VUNPCKHPS xmm1, xmmV, xmm2/m128","VUNPCKHPS xmm2/m128, xmmV, xmm1","vunpckhps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 15 /r","V","V","AVX","","w,r,r","","" +"VUNPCKHPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VUNPCKHPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vunpckhps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 15 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VUNPCKHPS ymm1, ymmV, ymm2/m256","VUNPCKHPS ymm2/m256, ymmV, ymm1","vunpckhps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 15 /r","V","V","AVX","","w,r,r","","" +"VUNPCKHPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VUNPCKHPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vunpckhps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 15 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VUNPCKHPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VUNPCKHPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vunpckhps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 15 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VUNPCKLPD xmm1, xmmV, xmm2/m128","VUNPCKLPD xmm2/m128, xmmV, xmm1","vunpcklpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 14 /r","V","V","AVX","","w,r,r","","" +"VUNPCKLPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VUNPCKLPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vunpcklpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 14 /r","V","V","AVX512F+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VUNPCKLPD ymm1, ymmV, ymm2/m256","VUNPCKLPD ymm2/m256, ymmV, ymm1","vunpcklpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 14 /r","V","V","AVX","","w,r,r","","" +"VUNPCKLPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VUNPCKLPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vunpcklpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 14 /r","V","V","AVX512F+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VUNPCKLPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VUNPCKLPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vunpcklpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 14 /r","V","V","AVX512F","bscale8,scale64","w,r,r,r","","" +"VUNPCKLPS xmm1, xmmV, xmm2/m128","VUNPCKLPS xmm2/m128, xmmV, xmm1","vunpcklps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 14 /r","V","V","AVX","","w,r,r","","" +"VUNPCKLPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VUNPCKLPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vunpcklps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 14 /r","V","V","AVX512F+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VUNPCKLPS ymm1, ymmV, ymm2/m256","VUNPCKLPS ymm2/m256, ymmV, ymm1","vunpcklps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 14 /r","V","V","AVX","","w,r,r","","" +"VUNPCKLPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VUNPCKLPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vunpcklps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 14 /r","V","V","AVX512F+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VUNPCKLPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VUNPCKLPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vunpcklps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 14 /r","V","V","AVX512F","bscale4,scale64","w,r,r,r","","" +"VXORPD xmm1, xmmV, xmm2/m128","VXORPD xmm2/m128, xmmV, xmm1","vxorpd xmm2/m128, xmmV, xmm1","VEX.NDS.128.66.0F.WIG 57 /r","V","V","AVX","","w,r,r","","" +"VXORPD xmm1, {k}{z}, xmmV, xmm2/m128/m64bcst","VXORPD xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","vxorpd xmm2/m128/m64bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.66.0F.W1 57 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale16","w,r,r,r","","" +"VXORPD ymm1, ymmV, ymm2/m256","VXORPD ymm2/m256, ymmV, ymm1","vxorpd ymm2/m256, ymmV, ymm1","VEX.NDS.256.66.0F.WIG 57 /r","V","V","AVX","","w,r,r","","" +"VXORPD ymm1, {k}{z}, ymmV, ymm2/m256/m64bcst","VXORPD ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","vxorpd ymm2/m256/m64bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.66.0F.W1 57 /r","V","V","AVX512DQ+AVX512VL","bscale8,scale32","w,r,r,r","","" +"VXORPD zmm1, {k}{z}, zmmV, zmm2/m512/m64bcst","VXORPD zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","vxorpd zmm2/m512/m64bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.66.0F.W1 57 /r","V","V","AVX512DQ","bscale8,scale64","w,r,r,r","","" +"VXORPS xmm1, xmmV, xmm2/m128","VXORPS xmm2/m128, xmmV, xmm1","vxorps xmm2/m128, xmmV, xmm1","VEX.NDS.128.0F.WIG 57 /r","V","V","AVX","","w,r,r","","" +"VXORPS xmm1, {k}{z}, xmmV, xmm2/m128/m32bcst","VXORPS xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","vxorps xmm2/m128/m32bcst, xmmV, {k}{z}, xmm1","EVEX.NDS.128.0F.W0 57 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale16","w,r,r,r","","" +"VXORPS ymm1, ymmV, ymm2/m256","VXORPS ymm2/m256, ymmV, ymm1","vxorps ymm2/m256, ymmV, ymm1","VEX.NDS.256.0F.WIG 57 /r","V","V","AVX","","w,r,r","","" +"VXORPS ymm1, {k}{z}, ymmV, ymm2/m256/m32bcst","VXORPS ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","vxorps ymm2/m256/m32bcst, ymmV, {k}{z}, ymm1","EVEX.NDS.256.0F.W0 57 /r","V","V","AVX512DQ+AVX512VL","bscale4,scale32","w,r,r,r","","" +"VXORPS zmm1, {k}{z}, zmmV, zmm2/m512/m32bcst","VXORPS zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","vxorps zmm2/m512/m32bcst, zmmV, {k}{z}, zmm1","EVEX.NDS.512.0F.W0 57 /r","V","V","AVX512DQ","bscale4,scale64","w,r,r,r","","" +"VZEROALL","VZEROALL","vzeroall","VEX.256.0F.WIG 77","V","V","AVX","","","","" +"VZEROUPPER","VZEROUPPER","vzeroupper","VEX.128.0F.WIG 77","V","V","AVX","","","","" +"WAIT","WAIT","wait","9B","V","V","","pseudo","","","" +"WBINVD","WBINVD","wbinvd","0F 09","V","V","486","","","","" +"WRFSBASE rmr32","WRFSBASE rmr32","wrfsbase rmr32","F3 0F AE /2","N.S.","V","FSGSBASE","modrm_regonly,operand16,operand32","r","Y","32" +"WRFSBASE rmr64","WRFSBASE rmr64","wrfsbase rmr64","F3 REX.W 0F AE /2","N.S.","V","FSGSBASE","modrm_regonly","r","Y","64" +"WRGSBASE rmr32","WRGSBASE rmr32","wrgsbase rmr32","F3 0F AE /3","N.S.","V","FSGSBASE","modrm_regonly,operand16,operand32","r","Y","32" +"WRGSBASE rmr64","WRGSBASE rmr64","wrgsbase rmr64","F3 REX.W 0F AE /3","N.S.","V","FSGSBASE","modrm_regonly","r","Y","64" +"WRMSR","WRMSR","wrmsr","0F 30","V","V","Pentium","","","","" +"WRPKRU","WRPKRU","wrpkru","0F 01 EF","V","V","PKU","","","","" +"WRSSD m32, r32","WRSSD r32, m32","wrssd r32, m32","0F 38 F6 /r","V","V","CET","modrm_memonly,operand16,operand32","w,r","","" +"WRSSQ m64, r64","WRSSQ r64, m64","wrssq r64, m64","REX.W 0F 38 F6 /r","N.S.","V","CET","modrm_memonly","w,r","","" +"WRUSSD m32, r32","WRUSSD r32, m32","wrussd r32, m32","66 0F 38 F5 /r","V","V","CET","modrm_memonly,operand16,operand32","w,r","","" +"WRUSSQ m64, r64","WRUSSQ r64, m64","wrussq r64, m64","66 REX.W 0F 38 F5 /r","N.S.","V","CET","modrm_memonly","w,r","","" +"XABORT imm8u","XABORT imm8u","xabort imm8u","C6 F8 ib","V","V","RTM","modrm_regonly","r","","" +"XACQUIRE","XACQUIRE","xacquire","F2","V","V","HLE","pseudo","","","" +"XADD r/m8, r8","XADDB r8, r/m8","xaddb r8, r/m8","0F C0 /r","V","V","486","","rw,rw","Y","8" +"XADD r/m8, r8","XADDB r8, r/m8","xaddb r8, r/m8","REX 0F C0 /r","N.E.","V","","pseudo64","rw,w","Y","8" +"XADD r/m32, r32","XADDL r32, r/m32","xaddl r32, r/m32","0F C1 /r","V","V","486","operand32","rw,rw","Y","32" +"XADD r/m64, r64","XADDQ r64, r/m64","xaddq r64, r/m64","REX.W 0F C1 /r","N.S.","V","486","","rw,rw","Y","64" +"XADD r/m16, r16","XADDW r16, r/m16","xaddw r16, r/m16","0F C1 /r","V","V","486","operand16","rw,rw","Y","16" +"XBEGIN rel16","XBEGIN rel16","xbegin rel16","C7 F8 cw","V","V","RTM","modrm_regonly,operand16","r","","" +"XBEGIN rel32","XBEGIN rel32","xbegin rel32","C7 F8 cd","V","V","RTM","modrm_regonly,operand32,operand64","r","","" +"XCHG r8, r/m8","XCHGB r/m8, r8","xchgb r/m8, r8","86 /r","V","V","","pseudo","w,r","Y","8" +"XCHG r8, r/m8","XCHGB r/m8, r8","xchgb r/m8, r8","REX 86 /r","N.E.","V","","pseudo","w,r","Y","8" +"XCHG r/m8, r8","XCHGB r8, r/m8","xchgb r8, r/m8","86 /r","V","V","","","rw,rw","Y","8" +"XCHG r/m8, r8","XCHGB r8, r/m8","xchgb r8, r/m8","REX 86 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"XCHG r32op, EAX","XCHGL EAX, r32op","xchgl EAX, r32op","90+rd","V","V","","operand32","rw,rw","Y","32" +"XCHG r32, r/m32","XCHGL r/m32, r32","xchgl r/m32, r32","87 /r","V","V","","operand32,pseudo","w,r","Y","32" +"XCHG r/m32, r32","XCHGL r32, r/m32","xchgl r32, r/m32","87 /r","V","V","","operand32","rw,rw","Y","32" +"XCHG EAX, r32op","XCHGL r32op, EAX","xchgl r32op, EAX","90+rd","V","V","","operand32,pseudo","rw,rw","Y","32" +"XCHG r64op, RAX","XCHGQ RAX, r64op","xchgq RAX, r64op","REX.W 90+ro","N.S.","V","","","rw,rw","Y","64" +"XCHG r64, r/m64","XCHGQ r/m64, r64","xchgq r/m64, r64","REX.W 87 /r","N.E.","V","","pseudo","w,r","Y","64" +"XCHG r/m64, r64","XCHGQ r64, r/m64","xchgq r64, r/m64","REX.W 87 /r","N.S.","V","","","rw,rw","Y","64" +"XCHG RAX, r64op","XCHGQ r64op, RAX","xchgq r64op, RAX","REX.W 90+rd","N.E.","V","","pseudo","rw,rw","Y","64" +"XCHG r16op, AX","XCHGW AX, r16op","xchgw AX, r16op","90+rw","V","V","","operand16","rw,rw","Y","16" +"XCHG r16, r/m16","XCHGW r/m16, r16","xchgw r/m16, r16","87 /r","V","V","","operand16,pseudo","w,r","Y","16" +"XCHG r/m16, r16","XCHGW r16, r/m16","xchgw r16, r/m16","87 /r","V","V","","operand16","rw,rw","Y","16" +"XCHG AX, r16op","XCHGW r16op, AX","xchgw r16op, AX","90+rw","V","V","","operand16,pseudo","rw,rw","Y","16" +"XEND","XEND","xend","0F 01 D5","V","V","RTM","","","","" +"XGETBV","XGETBV","xgetbv","0F 01 D0","V","V","XSAVE","","","","" +"XLATB","XLAT","xlat","D7","V","V","","","","","" +"XLATB","XLAT","xlat","REX.W D7","N.E.","V","","pseudo","","","" +"XOR r/m8, imm8","XORB imm8, r/m8","xorb imm8, r/m8","REX 80 /6 ib","N.E.","V","","pseudo64","rw,r","Y","8" +"XOR AL, imm8u","XORB imm8u, AL","xorb imm8u, AL","34 ib","V","V","","","rw,r","Y","8" +"XOR r/m8, imm8u","XORB imm8u, r/m8","xorb imm8u, r/m8","80 /6 ib","V","V","","","rw,r","Y","8" +"XOR r/m8, imm8u","XORB imm8u, r/m8","xorb imm8u, r/m8","82 /6 ib","V","N.S.","","","rw,r","Y","8" +"XOR r8, r/m8","XORB r/m8, r8","xorb r/m8, r8","32 /r","V","V","","","rw,r","Y","8" +"XOR r8, r/m8","XORB r/m8, r8","xorb r/m8, r8","REX 32 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"XOR r/m8, r8","XORB r8, r/m8","xorb r8, r/m8","30 /r","V","V","","","rw,r","Y","8" +"XOR r/m8, r8","XORB r8, r/m8","xorb r8, r/m8","REX 30 /r","N.E.","V","","pseudo64","rw,r","Y","8" +"XOR EAX, imm32","XORL imm32, EAX","xorl imm32, EAX","35 id","V","V","","operand32","rw,r","Y","32" +"XOR r/m32, imm32","XORL imm32, r/m32","xorl imm32, r/m32","81 /6 id","V","V","","operand32","rw,r","Y","32" +"XOR r/m32, imm8","XORL imm8, r/m32","xorl imm8, r/m32","83 /6 ib","V","V","","operand32","rw,r","Y","32" +"XOR r32, r/m32","XORL r/m32, r32","xorl r/m32, r32","33 /r","V","V","","operand32","rw,r","Y","32" +"XOR r/m32, r32","XORL r32, r/m32","xorl r32, r/m32","31 /r","V","V","","operand32","rw,r","Y","32" +"XORPD xmm1, xmm2/m128","XORPD xmm2/m128, xmm1","xorpd xmm2/m128, xmm1","66 0F 57 /r","V","V","SSE2","","rw,r","","" +"XORPS xmm1, xmm2/m128","XORPS xmm2/m128, xmm1","xorps xmm2/m128, xmm1","0F 57 /r","V","V","SSE","","rw,r","","" +"XOR RAX, imm32","XORQ imm32, RAX","xorq imm32, RAX","REX.W 35 id","N.S.","V","","","rw,r","Y","64" +"XOR r/m64, imm32","XORQ imm32, r/m64","xorq imm32, r/m64","REX.W 81 /6 id","N.S.","V","","","rw,r","Y","64" +"XOR r/m64, imm8","XORQ imm8, r/m64","xorq imm8, r/m64","REX.W 83 /6 ib","N.S.","V","","","rw,r","Y","64" +"XOR r64, r/m64","XORQ r/m64, r64","xorq r/m64, r64","REX.W 33 /r","N.S.","V","","","rw,r","Y","64" +"XOR r/m64, r64","XORQ r64, r/m64","xorq r64, r/m64","REX.W 31 /r","N.S.","V","","","rw,r","Y","64" +"XOR AX, imm16","XORW imm16, AX","xorw imm16, AX","35 iw","V","V","","operand16","rw,r","Y","16" +"XOR r/m16, imm16","XORW imm16, r/m16","xorw imm16, r/m16","81 /6 iw","V","V","","operand16","rw,r","Y","16" +"XOR r/m16, imm8","XORW imm8, r/m16","xorw imm8, r/m16","83 /6 ib","V","V","","operand16","rw,r","Y","16" +"XOR r16, r/m16","XORW r/m16, r16","xorw r/m16, r16","33 /r","V","V","","operand16","rw,r","Y","16" +"XOR r/m16, r16","XORW r16, r/m16","xorw r16, r/m16","31 /r","V","V","","operand16","rw,r","Y","16" +"XRELEASE","XRELEASE","xrelease","F3","V","V","HLE","pseudo","","","" +"XRSTOR mem","XRSTOR mem","xrstor mem","0F AE /5","V","V","XSAVE","modrm_memonly,operand16,operand32","r","","" +"XRSTOR64 mem","XRSTOR64 mem","xrstor64 mem","REX.W 0F AE /5","N.S.","V","XSAVE","modrm_memonly","r","","" +"XRSTORS mem","XRSTORS mem","xrstors mem","0F C7 /3","V","V","XSAVES","modrm_memonly,operand16,operand32","r","","" +"XRSTORS64 mem","XRSTORS64 mem","xrstors64 mem","REX.W 0F C7 /3","N.S.","V","XSAVES","modrm_memonly","r","","" +"XSAVE mem","XSAVE mem","xsave mem","0F AE /4","V","V","XSAVE","modrm_memonly,operand16,operand32","w","","" +"XSAVE64 mem","XSAVE64 mem","xsave64 mem","REX.W 0F AE /4","N.S.","V","XSAVE","modrm_memonly","w","","" +"XSAVEC mem","XSAVEC mem","xsavec mem","0F C7 /4","V","V","XSAVEC","modrm_memonly,operand16,operand32","w","","" +"XSAVEC64 mem","XSAVEC64 mem","xsavec64 mem","REX.W 0F C7 /4","N.S.","V","XSAVEC","modrm_memonly","w","","" +"XSAVEOPT mem","XSAVEOPT mem","xsaveopt mem","0F AE /6","V","V","XSAVEOPT","modrm_memonly,operand16,operand32","w","","" +"XSAVEOPT64 mem","XSAVEOPT64 mem","xsaveopt64 mem","REX.W 0F AE /6","N.S.","V","XSAVEOPT","modrm_memonly","w","","" +"XSAVES mem","XSAVES mem","xsaves mem","0F C7 /5","V","V","XSAVES","modrm_memonly,operand16,operand32","w","","" +"XSAVES64 mem","XSAVES64 mem","xsaves64 mem","REX.W 0F C7 /5","N.S.","V","XSAVES","modrm_memonly","w","","" +"XSETBV","XSETBV","xsetbv","0F 01 D1","V","V","XSAVE","","","","" +"XTEST","XTEST","xtest","0F 01 D6","V","V","HLE or RTM","","","","" diff --git a/tests/tcg/loongarch64/Makefile.target b/tests/tcg/loongarch64/Makefile.target index 0115de78ef..00030a1026 100644 --- a/tests/tcg/loongarch64/Makefile.target +++ b/tests/tcg/loongarch64/Makefile.target @@ -15,5 +15,6 @@ LOONGARCH64_TESTS += test_div LOONGARCH64_TESTS += test_fclass LOONGARCH64_TESTS += test_fpcom LOONGARCH64_TESTS += test_pcadd +LOONGARCH64_TESTS += test_fcsr TESTS += $(LOONGARCH64_TESTS) diff --git a/tests/tcg/loongarch64/test_fcsr.c b/tests/tcg/loongarch64/test_fcsr.c new file mode 100644 index 0000000000..ad3609eb99 --- /dev/null +++ b/tests/tcg/loongarch64/test_fcsr.c @@ -0,0 +1,15 @@ +#include + +int main() +{ + unsigned fcsr; + + asm("movgr2fcsr $r0,$r0\n\t" + "movgr2fr.d $f0,$r0\n\t" + "fdiv.d $f0,$f0,$f0\n\t" + "movfcsr2gr %0,$r0" + : "=r"(fcsr) : : "f0"); + + assert(fcsr & (16 << 16)); /* Invalid */ + return 0; +} diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 6bba523729..78104f9bbb 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -26,7 +26,7 @@ float_%: float_%.c libs/float_helpers.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< $(MULTIARCH_SRC)/libs/float_helpers.c -o $@ $(LDFLAGS) run-float_%: float_% - $(call run-test,$<, $(QEMU) $(QEMU_OPTS) $<,"$< on $(TARGET_NAME)") + $(call run-test,$<, $(QEMU) $(QEMU_OPTS) $<) $(call conditional-diff-out,$<,$(SRC_PATH)/tests/tcg/$(TARGET_NAME)/$<.ref) @@ -42,13 +42,11 @@ signals: LDFLAGS+=-lrt -lpthread # default case (host page size) run-test-mmap: test-mmap - $(call run-test, test-mmap, $(QEMU) $<, \ - "$< (default) on $(TARGET_NAME)") + $(call run-test, test-mmap, $(QEMU) $<, $< (default)) # additional page sizes (defined by each architecture adding to EXTRA_RUNS) run-test-mmap-%: test-mmap - $(call run-test, test-mmap-$*, $(QEMU) -p $* $<,\ - "$< ($* byte pages) on $(TARGET_NAME)") + $(call run-test, test-mmap-$*, $(QEMU) -p $* $<, $< ($* byte pages)) ifneq ($(HAVE_GDB_BIN),) GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py @@ -58,21 +56,21 @@ run-gdbstub-sha1: sha1 --gdb $(HAVE_GDB_BIN) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/sha1.py, \ - "basic gdbstub support") + basic gdbstub support) run-gdbstub-qxfer-auxv-read: sha1 $(call run-test, $@, $(GDB_SCRIPT) \ --gdb $(HAVE_GDB_BIN) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \ - "basic gdbstub qXfer:auxv:read support") + basic gdbstub qXfer:auxv:read support) run-gdbstub-thread-breakpoint: testthread $(call run-test, $@, $(GDB_SCRIPT) \ --gdb $(HAVE_GDB_BIN) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/test-thread-breakpoint.py, \ - "hitting a breakpoint on non-main thread") + hitting a breakpoint on non-main thread) else run-gdbstub-%: @@ -94,13 +92,13 @@ VPATH += $(MULTIARCH_SRC)/arm-compat-semi semihosting: CFLAGS+=-I$(SRC_PATH)/tests/tcg/$(TARGET_NAME) run-semihosting: semihosting - $(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)") + $(call run-test,$<,$(QEMU) $< 2> $<.err) run-plugin-semihosting-with-%: $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \ $(call strip-plugin,$<) 2> $<.err, \ - "$< on $(TARGET_NAME) with $*") + $< with $*) semiconsole: CFLAGS+=-I$(SRC_PATH)/tests/tcg/$(TARGET_NAME) diff --git a/tests/tcg/multiarch/linux/linux-madvise.c b/tests/tcg/multiarch/linux/linux-madvise.c new file mode 100644 index 0000000000..29d0997e68 --- /dev/null +++ b/tests/tcg/multiarch/linux/linux-madvise.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +static void test_anonymous(void) +{ + int pagesize = getpagesize(); + char *page; + int ret; + + page = mmap(NULL, pagesize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(page != MAP_FAILED); + + /* Check that mprotect() does not interfere with MADV_DONTNEED. */ + ret = mprotect(page, pagesize, PROT_READ | PROT_WRITE); + assert(ret == 0); + + /* Check that MADV_DONTNEED clears the page. */ + *page = 42; + ret = madvise(page, pagesize, MADV_DONTNEED); + assert(ret == 0); + assert(*page == 0); + + ret = munmap(page, pagesize); + assert(ret == 0); +} + +static void test_file(void) +{ + char tempname[] = "/tmp/.cmadviseXXXXXX"; + int pagesize = getpagesize(); + ssize_t written; + char c = 42; + char *page; + int ret; + int fd; + + fd = mkstemp(tempname); + assert(fd != -1); + ret = unlink(tempname); + assert(ret == 0); + written = write(fd, &c, sizeof(c)); + assert(written == sizeof(c)); + page = mmap(NULL, pagesize, PROT_READ, MAP_PRIVATE, fd, 0); + assert(page != MAP_FAILED); + + /* Check that mprotect() does not interfere with MADV_DONTNEED. */ + ret = mprotect(page, pagesize, PROT_READ | PROT_WRITE); + assert(ret == 0); + + /* Check that MADV_DONTNEED resets the page. */ + *page = 0; + ret = madvise(page, pagesize, MADV_DONTNEED); + assert(ret == 0); + assert(*page == c); + + ret = munmap(page, pagesize); + assert(ret == 0); + ret = close(fd); + assert(ret == 0); +} + +int main(void) +{ + test_anonymous(); + test_file(); + + return EXIT_SUCCESS; +} diff --git a/tests/tcg/multiarch/linux/linux-test.c b/tests/tcg/multiarch/linux/linux-test.c index 019d8175ca..5a2a4f2258 100644 --- a/tests/tcg/multiarch/linux/linux-test.c +++ b/tests/tcg/multiarch/linux/linux-test.c @@ -263,7 +263,7 @@ static int server_socket(void) sockaddr.sin_port = htons(0); /* choose random ephemeral port) */ sockaddr.sin_addr.s_addr = 0; chk_error(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))); - chk_error(listen(fd, 0)); + chk_error(listen(fd, 1)); return fd; } diff --git a/tests/tcg/multiarch/noexec.c.inc b/tests/tcg/multiarch/noexec.c.inc new file mode 100644 index 0000000000..2ef539b721 --- /dev/null +++ b/tests/tcg/multiarch/noexec.c.inc @@ -0,0 +1,139 @@ +/* + * Common code for arch-specific MMU_INST_FETCH fault testing. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Forward declarations. */ + +static void *arch_mcontext_pc(const mcontext_t *ctx); +static int arch_mcontext_arg(const mcontext_t *ctx); +static void arch_flush(void *p, int len); + +/* Testing infrastructure. */ + +struct noexec_test { + const char *name; + const char *test_code; + int test_len; + int page_ofs; + int entry_ofs; + int expected_si_ofs; + int expected_pc_ofs; + int expected_arg; +}; + +static void *page_base; +static int page_size; +static const struct noexec_test *current_noexec_test; + +static void handle_err(const char *syscall) +{ + printf("[ FAILED ] %s: %s\n", syscall, strerror(errno)); + exit(EXIT_FAILURE); +} + +static void handle_segv(int sig, siginfo_t *info, void *ucontext) +{ + const struct noexec_test *test = current_noexec_test; + const mcontext_t *mc = &((ucontext_t *)ucontext)->uc_mcontext; + void *expected_si; + void *expected_pc; + void *pc; + int arg; + + if (test == NULL) { + printf("[ FAILED ] unexpected SEGV\n"); + exit(EXIT_FAILURE); + } + current_noexec_test = NULL; + + expected_si = page_base + test->expected_si_ofs; + if (info->si_addr != expected_si) { + printf("[ FAILED ] wrong si_addr (%p != %p)\n", + info->si_addr, expected_si); + exit(EXIT_FAILURE); + } + + pc = arch_mcontext_pc(mc); + expected_pc = page_base + test->expected_pc_ofs; + if (pc != expected_pc) { + printf("[ FAILED ] wrong pc (%p != %p)\n", pc, expected_pc); + exit(EXIT_FAILURE); + } + + arg = arch_mcontext_arg(mc); + if (arg != test->expected_arg) { + printf("[ FAILED ] wrong arg (%d != %d)\n", arg, test->expected_arg); + exit(EXIT_FAILURE); + } + + if (mprotect(page_base, page_size, + PROT_READ | PROT_WRITE | PROT_EXEC) < 0) { + handle_err("mprotect"); + } +} + +static void test_noexec_1(const struct noexec_test *test) +{ + void *start = page_base + test->page_ofs; + void (*fn)(int arg) = page_base + test->entry_ofs; + + memcpy(start, test->test_code, test->test_len); + arch_flush(start, test->test_len); + + /* Trigger TB creation in order to test invalidation. */ + fn(0); + + if (mprotect(page_base, page_size, PROT_NONE) < 0) { + handle_err("mprotect"); + } + + /* Trigger SEGV and check that handle_segv() ran. */ + current_noexec_test = test; + fn(0); + assert(current_noexec_test == NULL); +} + +static int test_noexec(struct noexec_test *tests, size_t n_tests) +{ + struct sigaction act; + size_t i; + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = handle_segv; + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGSEGV, &act, NULL) < 0) { + handle_err("sigaction"); + } + + page_size = getpagesize(); + page_base = mmap(NULL, 2 * page_size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (page_base == MAP_FAILED) { + handle_err("mmap"); + } + page_base += page_size; + + for (i = 0; i < n_tests; i++) { + struct noexec_test *test = &tests[i]; + + printf("[ RUN ] %s\n", test->name); + test_noexec_1(test); + printf("[ OK ]\n"); + } + + printf("[ PASSED ]\n"); + return EXIT_SUCCESS; +} diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target index 625ed792c6..368b64d531 100644 --- a/tests/tcg/multiarch/system/Makefile.softmmu-target +++ b/tests/tcg/multiarch/system/Makefile.softmmu-target @@ -25,7 +25,7 @@ run-gdbstub-memory: memory --qargs \ "-monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/memory.py, \ - "softmmu gdbstub support") + softmmu gdbstub support) else run-gdbstub-%: diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target index 331fae628e..f081f1c683 100644 --- a/tests/tcg/ppc64/Makefile.target +++ b/tests/tcg/ppc64/Makefile.target @@ -3,7 +3,13 @@ # ppc64 specific tweaks VPATH += $(SRC_PATH)/tests/tcg/ppc64 -VPATH += $(SRC_PATH)/tests/tcg/ppc64le + +config-cc.mak: Makefile + $(quiet-@)( \ + $(call cc-option,-mpower8-vector, CROSS_CC_HAS_POWER8_VECTOR); \ + $(call cc-option,-mpower10, CROSS_CC_HAS_POWER10)) 3> config-cc.mak + +-include config-cc.mak ifneq ($(CROSS_CC_HAS_POWER8_VECTOR),) PPC64_TESTS=bcdsub non_signalling_xscv diff --git a/tests/tcg/ppc64le/bcdsub.c b/tests/tcg/ppc64/bcdsub.c similarity index 100% rename from tests/tcg/ppc64le/bcdsub.c rename to tests/tcg/ppc64/bcdsub.c diff --git a/tests/tcg/ppc64le/byte_reverse.c b/tests/tcg/ppc64/byte_reverse.c similarity index 100% rename from tests/tcg/ppc64le/byte_reverse.c rename to tests/tcg/ppc64/byte_reverse.c diff --git a/tests/tcg/ppc64le/mffsce.c b/tests/tcg/ppc64/mffsce.c similarity index 100% rename from tests/tcg/ppc64le/mffsce.c rename to tests/tcg/ppc64/mffsce.c diff --git a/tests/tcg/ppc64le/mtfsf.c b/tests/tcg/ppc64/mtfsf.c similarity index 100% rename from tests/tcg/ppc64le/mtfsf.c rename to tests/tcg/ppc64/mtfsf.c diff --git a/tests/tcg/ppc64le/non_signalling_xscv.c b/tests/tcg/ppc64/non_signalling_xscv.c similarity index 100% rename from tests/tcg/ppc64le/non_signalling_xscv.c rename to tests/tcg/ppc64/non_signalling_xscv.c diff --git a/tests/tcg/ppc64le/signal_save_restore_xer.c b/tests/tcg/ppc64/signal_save_restore_xer.c similarity index 100% rename from tests/tcg/ppc64le/signal_save_restore_xer.c rename to tests/tcg/ppc64/signal_save_restore_xer.c diff --git a/tests/tcg/ppc64le/xxspltw.c b/tests/tcg/ppc64/xxspltw.c similarity index 100% rename from tests/tcg/ppc64le/xxspltw.c rename to tests/tcg/ppc64/xxspltw.c diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target index 6ca3003f02..daad5118a5 100644 --- a/tests/tcg/ppc64le/Makefile.target +++ b/tests/tcg/ppc64le/Makefile.target @@ -4,28 +4,4 @@ VPATH += $(SRC_PATH)/tests/tcg/ppc64le -ifneq ($(CROSS_CC_HAS_POWER8_VECTOR),) -PPC64LE_TESTS=bcdsub non_signalling_xscv -endif -$(PPC64LE_TESTS): CFLAGS += -mpower8-vector - -ifneq ($(CROSS_CC_HAS_POWER10),) -PPC64LE_TESTS += byte_reverse sha512-vector -endif -byte_reverse: CFLAGS += -mcpu=power10 -run-byte_reverse: QEMU_OPTS+=-cpu POWER10 -run-plugin-byte_reverse-with-%: QEMU_OPTS+=-cpu POWER10 - -sha512-vector: CFLAGS +=-mcpu=power10 -O3 -sha512-vector: sha512.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) - -run-sha512-vector: QEMU_OPTS+=-cpu POWER10 -run-plugin-sha512-vector-with-%: QEMU_OPTS+=-cpu POWER10 - -PPC64LE_TESTS += mtfsf -PPC64LE_TESTS += mffsce -PPC64LE_TESTS += signal_save_restore_xer -PPC64LE_TESTS += xxspltw - -TESTS += $(PPC64LE_TESTS) +include $(SRC_PATH)/tests/tcg/ppc64/Makefile.target diff --git a/tests/tcg/riscv64/Makefile.target b/tests/tcg/riscv64/Makefile.target index d41bf6d60d..b5b89dfb0e 100644 --- a/tests/tcg/riscv64/Makefile.target +++ b/tests/tcg/riscv64/Makefile.target @@ -3,3 +3,4 @@ VPATH += $(SRC_PATH)/tests/tcg/riscv64 TESTS += test-div +TESTS += noexec diff --git a/tests/tcg/riscv64/noexec.c b/tests/tcg/riscv64/noexec.c new file mode 100644 index 0000000000..86f64b28db --- /dev/null +++ b/tests/tcg/riscv64/noexec.c @@ -0,0 +1,79 @@ +#include "../multiarch/noexec.c.inc" + +static void *arch_mcontext_pc(const mcontext_t *ctx) +{ + return (void *)ctx->__gregs[REG_PC]; +} + +static int arch_mcontext_arg(const mcontext_t *ctx) +{ + return ctx->__gregs[REG_A0]; +} + +static void arch_flush(void *p, int len) +{ + __builtin___clear_cache(p, p + len); +} + +extern char noexec_1[]; +extern char noexec_2[]; +extern char noexec_end[]; + +asm(".option push\n" + ".option norvc\n" + "noexec_1:\n" + " li a0,1\n" /* a0 is 0 on entry, set 1. */ + "noexec_2:\n" + " li a0,2\n" /* a0 is 0/1; set 2. */ + " ret\n" + "noexec_end:\n" + ".option pop"); + +int main(void) +{ + struct noexec_test noexec_tests[] = { + { + .name = "fallthrough", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2, + .entry_ofs = noexec_1 - noexec_2, + .expected_si_ofs = 0, + .expected_pc_ofs = 0, + .expected_arg = 1, + }, + { + .name = "jump", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2, + .entry_ofs = 0, + .expected_si_ofs = 0, + .expected_pc_ofs = 0, + .expected_arg = 0, + }, + { + .name = "fallthrough [cross]", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2 - 2, + .entry_ofs = noexec_1 - noexec_2 - 2, + .expected_si_ofs = 0, + .expected_pc_ofs = -2, + .expected_arg = 1, + }, + { + .name = "jump [cross]", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2 - 2, + .entry_ofs = -2, + .expected_si_ofs = 0, + .expected_pc_ofs = -2, + .expected_arg = 0, + }, + }; + + return test_noexec(noexec_tests, + sizeof(noexec_tests) / sizeof(noexec_tests[0])); +} diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target new file mode 100644 index 0000000000..a34fa68473 --- /dev/null +++ b/tests/tcg/s390x/Makefile.softmmu-target @@ -0,0 +1,9 @@ +S390X_SRC=$(SRC_PATH)/tests/tcg/s390x +VPATH+=$(S390X_SRC) +QEMU_OPTS=-action panic=exit-failure -kernel + +%: %.S + $(CC) -march=z13 -m64 -nostartfiles -static -Wl,-Ttext=0 \ + -Wl,--build-id=none $< -o $@ + +TESTS += unaligned-lowcore diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index 1a7a4a2f59..c830313e67 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -16,6 +16,7 @@ TESTS+=shift TESTS+=trap TESTS+=signals-s390x TESTS+=branch-relative-long +TESTS+=noexec Z14_TESTS=vfminmax vfminmax: LDFLAGS+=-lm @@ -40,7 +41,7 @@ run-gdbstub-signals-s390x: signals-s390x --gdb $(HAVE_GDB_BIN) \ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ --bin $< --test $(S390X_SRC)/gdbstub/test-signals-s390x.py, \ - "mixing signals and debugging on s390x") + mixing signals and debugging) EXTRA_RUNS += run-gdbstub-signals-s390x endif diff --git a/tests/tcg/s390x/noexec.c b/tests/tcg/s390x/noexec.c new file mode 100644 index 0000000000..15d007d07f --- /dev/null +++ b/tests/tcg/s390x/noexec.c @@ -0,0 +1,106 @@ +#include "../multiarch/noexec.c.inc" + +static void *arch_mcontext_pc(const mcontext_t *ctx) +{ + return (void *)ctx->psw.addr; +} + +static int arch_mcontext_arg(const mcontext_t *ctx) +{ + return ctx->gregs[2]; +} + +static void arch_flush(void *p, int len) +{ +} + +extern char noexec_1[]; +extern char noexec_2[]; +extern char noexec_end[]; + +asm("noexec_1:\n" + " lgfi %r2,1\n" /* %r2 is 0 on entry, set 1. */ + "noexec_2:\n" + " lgfi %r2,2\n" /* %r2 is 0/1; set 2. */ + " br %r14\n" /* return */ + "noexec_end:"); + +extern char exrl_1[]; +extern char exrl_2[]; +extern char exrl_end[]; + +asm("exrl_1:\n" + " exrl %r0, exrl_2\n" + " br %r14\n" + "exrl_2:\n" + " lgfi %r2,2\n" + "exrl_end:"); + +int main(void) +{ + struct noexec_test noexec_tests[] = { + { + .name = "fallthrough", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2, + .entry_ofs = noexec_1 - noexec_2, + .expected_si_ofs = 0, + .expected_pc_ofs = 0, + .expected_arg = 1, + }, + { + .name = "jump", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2, + .entry_ofs = 0, + .expected_si_ofs = 0, + .expected_pc_ofs = 0, + .expected_arg = 0, + }, + { + .name = "exrl", + .test_code = exrl_1, + .test_len = exrl_end - exrl_1, + .page_ofs = exrl_1 - exrl_2, + .entry_ofs = exrl_1 - exrl_2, + .expected_si_ofs = 0, + .expected_pc_ofs = exrl_1 - exrl_2, + .expected_arg = 0, + }, + { + .name = "fallthrough [cross]", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2 - 2, + .entry_ofs = noexec_1 - noexec_2 - 2, + .expected_si_ofs = 0, + .expected_pc_ofs = -2, + .expected_arg = 1, + }, + { + .name = "jump [cross]", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2 - 2, + .entry_ofs = -2, + .expected_si_ofs = 0, + .expected_pc_ofs = -2, + .expected_arg = 0, + }, + { + .name = "exrl [cross]", + .test_code = exrl_1, + .test_len = exrl_end - exrl_1, + .page_ofs = exrl_1 - exrl_2 - 2, + .entry_ofs = exrl_1 - exrl_2 - 2, + .expected_si_ofs = 0, + .expected_pc_ofs = exrl_1 - exrl_2 - 2, + .expected_arg = 0, + }, + }; + + return test_noexec(noexec_tests, + sizeof(noexec_tests) / sizeof(noexec_tests[0])); +} diff --git a/tests/tcg/s390x/unaligned-lowcore.S b/tests/tcg/s390x/unaligned-lowcore.S new file mode 100644 index 0000000000..f5da2ae64c --- /dev/null +++ b/tests/tcg/s390x/unaligned-lowcore.S @@ -0,0 +1,19 @@ + .org 0x1D0 /* program new PSW */ + .quad 0x2000000000000,0 /* disabled wait */ + .org 0x200 /* lowcore padding */ + + .globl _start +_start: + lctlg %c0,%c0,_c0 + vst %v0,_unaligned + lpswe quiesce_psw + + .align 8 +quiesce_psw: + .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */ +_c0: + .quad 0x10060000 /* lowcore protection, AFP, VX */ + + .byte 0 +_unaligned: + .octa 0 diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target index 2afa3298bf..7207fee94c 100644 --- a/tests/tcg/x86_64/Makefile.softmmu-target +++ b/tests/tcg/x86_64/Makefile.softmmu-target @@ -40,8 +40,7 @@ run-plugin-%-with-libinsn.so: -chardev file$(COMMA)path=$@.out$(COMMA)id=output \ -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ -d plugin -D $*-with-libinsn.so.pout \ - $(QEMU_OPTS) $*, \ - "$* on $(TARGET_NAME)") + $(QEMU_OPTS) $*) # Running QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target index b71a6bcd5e..6895db1c43 100644 --- a/tests/tcg/x86_64/Makefile.target +++ b/tests/tcg/x86_64/Makefile.target @@ -10,15 +10,18 @@ include $(SRC_PATH)/tests/tcg/i386/Makefile.target ifeq ($(filter %-linux-user, $(TARGET)),$(TARGET)) X86_64_TESTS += vsyscall +X86_64_TESTS += noexec TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64 else TESTS=$(MULTIARCH_TESTS) endif -QEMU_OPTS += -cpu max + +run-test-i386-ssse3: QEMU_OPTS += -cpu max +run-plugin-test-i386-ssse3-%: QEMU_OPTS += -cpu max test-x86_64: LDFLAGS+=-lm -lc test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) -vsyscall: $(SRC_PATH)/tests/tcg/x86_64/vsyscall.c +%: $(SRC_PATH)/tests/tcg/x86_64/%.c $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) diff --git a/tests/tcg/x86_64/noexec.c b/tests/tcg/x86_64/noexec.c new file mode 100644 index 0000000000..9b124901be --- /dev/null +++ b/tests/tcg/x86_64/noexec.c @@ -0,0 +1,75 @@ +#include "../multiarch/noexec.c.inc" + +static void *arch_mcontext_pc(const mcontext_t *ctx) +{ + return (void *)ctx->gregs[REG_RIP]; +} + +int arch_mcontext_arg(const mcontext_t *ctx) +{ + return ctx->gregs[REG_RDI]; +} + +static void arch_flush(void *p, int len) +{ +} + +extern char noexec_1[]; +extern char noexec_2[]; +extern char noexec_end[]; + +asm("noexec_1:\n" + " movq $1,%rdi\n" /* %rdi is 0 on entry, set 1. */ + "noexec_2:\n" + " movq $2,%rdi\n" /* %rdi is 0/1; set 2. */ + " ret\n" + "noexec_end:"); + +int main(void) +{ + struct noexec_test noexec_tests[] = { + { + .name = "fallthrough", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2, + .entry_ofs = noexec_1 - noexec_2, + .expected_si_ofs = 0, + .expected_pc_ofs = 0, + .expected_arg = 1, + }, + { + .name = "jump", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2, + .entry_ofs = 0, + .expected_si_ofs = 0, + .expected_pc_ofs = 0, + .expected_arg = 0, + }, + { + .name = "fallthrough [cross]", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2 - 2, + .entry_ofs = noexec_1 - noexec_2 - 2, + .expected_si_ofs = 0, + .expected_pc_ofs = -2, + .expected_arg = 1, + }, + { + .name = "jump [cross]", + .test_code = noexec_1, + .test_len = noexec_end - noexec_1, + .page_ofs = noexec_1 - noexec_2 - 2, + .entry_ofs = -2, + .expected_si_ofs = 0, + .expected_pc_ofs = -2, + .expected_arg = 0, + }, + }; + + return test_noexec(noexec_tests, + sizeof(noexec_tests) / sizeof(noexec_tests[0])); +} diff --git a/tests/unit/check-block-qdict.c b/tests/unit/check-block-qdict.c index 5a25825093..751c58e737 100644 --- a/tests/unit/check-block-qdict.c +++ b/tests/unit/check-block-qdict.c @@ -504,7 +504,7 @@ static void qdict_crumple_test_empty(void) src = qdict_new(); dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); - + g_assert(dst); g_assert_cmpint(qdict_size(dst), ==, 0); qobject_unref(src); diff --git a/tests/unit/socket-helpers.c b/tests/unit/socket-helpers.c index 5af4de513b..eecadf3a3c 100644 --- a/tests/unit/socket-helpers.c +++ b/tests/unit/socket-helpers.c @@ -154,3 +154,19 @@ int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6) return 0; } + +void socket_check_afunix_support(bool *has_afunix) +{ + int fd; + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + closesocket(fd); + +#ifdef _WIN32 + *has_afunix = (fd != (int)INVALID_SOCKET); +#else + *has_afunix = (fd >= 0); +#endif + + return; +} diff --git a/tests/unit/socket-helpers.h b/tests/unit/socket-helpers.h index 512a004811..ed8477ceb3 100644 --- a/tests/unit/socket-helpers.h +++ b/tests/unit/socket-helpers.h @@ -32,4 +32,13 @@ */ int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6); +/* + * @has_afunix: set to true on return if unix socket support is available + * + * Check whether unix domain socket support is available for use. + * On success, @has_afunix will be set to indicate whether AF_UNIX protocol + * is available. + */ +void socket_check_afunix_support(bool *has_afunix); + #endif diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c index 36be84ae55..4924ceb562 100644 --- a/tests/unit/test-bdrv-drain.c +++ b/tests/unit/test-bdrv-drain.c @@ -930,9 +930,9 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, tjob->prepare_ret = -EIO; break; } + aio_context_release(ctx); job_start(&job->job); - aio_context_release(ctx); if (use_iothread) { /* job_co_entry() is run in the I/O thread, wait for the actual job @@ -943,63 +943,85 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, } } - g_assert_cmpint(job->job.pause_count, ==, 0); - g_assert_false(job->job.paused); - g_assert_true(tjob->running); - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + WITH_JOB_LOCK_GUARD() { + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); + g_assert_true(tjob->running); + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + } do_drain_begin_unlocked(drain_type, drain_bs); - if (drain_type == BDRV_DRAIN_ALL) { - /* bdrv_drain_all() drains both src and target */ - g_assert_cmpint(job->job.pause_count, ==, 2); - } else { - g_assert_cmpint(job->job.pause_count, ==, 1); + WITH_JOB_LOCK_GUARD() { + if (drain_type == BDRV_DRAIN_ALL) { + /* bdrv_drain_all() drains both src and target */ + g_assert_cmpint(job->job.pause_count, ==, 2); + } else { + g_assert_cmpint(job->job.pause_count, ==, 1); + } + g_assert_true(job->job.paused); + g_assert_false(job->job.busy); /* The job is paused */ } - g_assert_true(job->job.paused); - g_assert_false(job->job.busy); /* The job is paused */ do_drain_end_unlocked(drain_type, drain_bs); if (use_iothread) { - /* paused is reset in the I/O thread, wait for it */ + /* + * Here we are waiting for the paused status to change, + * so don't bother protecting the read every time. + * + * paused is reset in the I/O thread, wait for it + */ while (job->job.paused) { aio_poll(qemu_get_aio_context(), false); } } - g_assert_cmpint(job->job.pause_count, ==, 0); - g_assert_false(job->job.paused); - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + WITH_JOB_LOCK_GUARD() { + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + } do_drain_begin_unlocked(drain_type, target); - if (drain_type == BDRV_DRAIN_ALL) { - /* bdrv_drain_all() drains both src and target */ - g_assert_cmpint(job->job.pause_count, ==, 2); - } else { - g_assert_cmpint(job->job.pause_count, ==, 1); + WITH_JOB_LOCK_GUARD() { + if (drain_type == BDRV_DRAIN_ALL) { + /* bdrv_drain_all() drains both src and target */ + g_assert_cmpint(job->job.pause_count, ==, 2); + } else { + g_assert_cmpint(job->job.pause_count, ==, 1); + } + g_assert_true(job->job.paused); + g_assert_false(job->job.busy); /* The job is paused */ } - g_assert_true(job->job.paused); - g_assert_false(job->job.busy); /* The job is paused */ do_drain_end_unlocked(drain_type, target); if (use_iothread) { - /* paused is reset in the I/O thread, wait for it */ + /* + * Here we are waiting for the paused status to change, + * so don't bother protecting the read every time. + * + * paused is reset in the I/O thread, wait for it + */ while (job->job.paused) { aio_poll(qemu_get_aio_context(), false); } } - g_assert_cmpint(job->job.pause_count, ==, 0); - g_assert_false(job->job.paused); - g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + WITH_JOB_LOCK_GUARD() { + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + } - aio_context_acquire(ctx); - ret = job_complete_sync(&job->job, &error_abort); + WITH_JOB_LOCK_GUARD() { + ret = job_complete_sync_locked(&job->job, &error_abort); + } g_assert_cmpint(ret, ==, (result == TEST_JOB_SUCCESS ? 0 : -EIO)); + aio_context_acquire(ctx); if (use_iothread) { blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort); assert(blk_get_aio_context(blk_target) == qemu_get_aio_context()); diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index 8b55eccc89..def0709b2b 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -582,8 +582,10 @@ static void test_attach_blockjob(void) aio_poll(qemu_get_aio_context(), false); } + WITH_JOB_LOCK_GUARD() { + job_complete_sync_locked(&tjob->common.job, &error_abort); + } aio_context_acquire(ctx); - job_complete_sync(&tjob->common.job, &error_abort); blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort); aio_context_release(ctx); @@ -757,7 +759,9 @@ static void test_propagate_mirror(void) BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, &error_abort); - job = job_get("job0"); + WITH_JOB_LOCK_GUARD() { + job = job_get_locked("job0"); + } filter = bdrv_find_node("filter_node"); /* Change the AioContext of src */ diff --git a/tests/unit/test-blockjob-txn.c b/tests/unit/test-blockjob-txn.c index c69028b450..d3b0bb24be 100644 --- a/tests/unit/test-blockjob-txn.c +++ b/tests/unit/test-blockjob-txn.c @@ -116,8 +116,10 @@ static void test_single_job(int expected) job = test_block_job_start(1, true, expected, &result, txn); job_start(&job->job); - if (expected == -ECANCELED) { - job_cancel(&job->job, false); + WITH_JOB_LOCK_GUARD() { + if (expected == -ECANCELED) { + job_cancel_locked(&job->job, false); + } } while (result == -EINPROGRESS) { @@ -160,13 +162,15 @@ static void test_pair_jobs(int expected1, int expected2) /* Release our reference now to trigger as many nice * use-after-free bugs as possible. */ - job_txn_unref(txn); + WITH_JOB_LOCK_GUARD() { + job_txn_unref_locked(txn); - if (expected1 == -ECANCELED) { - job_cancel(&job1->job, false); - } - if (expected2 == -ECANCELED) { - job_cancel(&job2->job, false); + if (expected1 == -ECANCELED) { + job_cancel_locked(&job1->job, false); + } + if (expected2 == -ECANCELED) { + job_cancel_locked(&job2->job, false); + } } while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) { @@ -219,7 +223,9 @@ static void test_pair_jobs_fail_cancel_race(void) job_start(&job1->job); job_start(&job2->job); - job_cancel(&job1->job, false); + WITH_JOB_LOCK_GUARD() { + job_cancel_locked(&job1->job, false); + } /* Now make job2 finish before the main loop kicks jobs. This simulates * the race between a pending kick and another job completing. diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c index 4c9e1bf1e5..c0426bd10c 100644 --- a/tests/unit/test-blockjob.c +++ b/tests/unit/test-blockjob.c @@ -211,8 +211,11 @@ static CancelJob *create_common(Job **pjob) bjob = mk_job(blk, "Steve", &test_cancel_driver, true, JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); job = &bjob->job; - job_ref(job); - assert(job->status == JOB_STATUS_CREATED); + WITH_JOB_LOCK_GUARD() { + job_ref_locked(job); + assert(job->status == JOB_STATUS_CREATED); + } + s = container_of(bjob, CancelJob, common); s->blk = blk; @@ -225,21 +228,22 @@ static void cancel_common(CancelJob *s) BlockJob *job = &s->common; BlockBackend *blk = s->blk; JobStatus sts = job->job.status; - AioContext *ctx; - - ctx = job->job.aio_context; - aio_context_acquire(ctx); + AioContext *ctx = job->job.aio_context; job_cancel_sync(&job->job, true); - if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { - Job *dummy = &job->job; - job_dismiss(&dummy, &error_abort); + WITH_JOB_LOCK_GUARD() { + if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { + Job *dummy = &job->job; + job_dismiss_locked(&dummy, &error_abort); + } + assert(job->job.status == JOB_STATUS_NULL); + job_unref_locked(&job->job); } - assert(job->job.status == JOB_STATUS_NULL); - job_unref(&job->job); - destroy_blk(blk); + aio_context_acquire(ctx); + destroy_blk(blk); aio_context_release(ctx); + } static void test_cancel_created(void) @@ -251,6 +255,13 @@ static void test_cancel_created(void) cancel_common(s); } +static void assert_job_status_is(Job *job, int status) +{ + WITH_JOB_LOCK_GUARD() { + assert(job->status == status); + } +} + static void test_cancel_running(void) { Job *job; @@ -259,7 +270,7 @@ static void test_cancel_running(void) s = create_common(&job); job_start(job); - assert(job->status == JOB_STATUS_RUNNING); + assert_job_status_is(job, JOB_STATUS_RUNNING); cancel_common(s); } @@ -272,11 +283,12 @@ static void test_cancel_paused(void) s = create_common(&job); job_start(job); - assert(job->status == JOB_STATUS_RUNNING); - - job_user_pause(job, &error_abort); + WITH_JOB_LOCK_GUARD() { + assert(job->status == JOB_STATUS_RUNNING); + job_user_pause_locked(job, &error_abort); + } job_enter(job); - assert(job->status == JOB_STATUS_PAUSED); + assert_job_status_is(job, JOB_STATUS_PAUSED); cancel_common(s); } @@ -289,11 +301,11 @@ static void test_cancel_ready(void) s = create_common(&job); job_start(job); - assert(job->status == JOB_STATUS_RUNNING); + assert_job_status_is(job, JOB_STATUS_RUNNING); s->should_converge = true; job_enter(job); - assert(job->status == JOB_STATUS_READY); + assert_job_status_is(job, JOB_STATUS_READY); cancel_common(s); } @@ -306,15 +318,16 @@ static void test_cancel_standby(void) s = create_common(&job); job_start(job); - assert(job->status == JOB_STATUS_RUNNING); + assert_job_status_is(job, JOB_STATUS_RUNNING); s->should_converge = true; job_enter(job); - assert(job->status == JOB_STATUS_READY); - - job_user_pause(job, &error_abort); + WITH_JOB_LOCK_GUARD() { + assert(job->status == JOB_STATUS_READY); + job_user_pause_locked(job, &error_abort); + } job_enter(job); - assert(job->status == JOB_STATUS_STANDBY); + assert_job_status_is(job, JOB_STATUS_STANDBY); cancel_common(s); } @@ -327,20 +340,21 @@ static void test_cancel_pending(void) s = create_common(&job); job_start(job); - assert(job->status == JOB_STATUS_RUNNING); + assert_job_status_is(job, JOB_STATUS_RUNNING); s->should_converge = true; job_enter(job); - assert(job->status == JOB_STATUS_READY); - - job_complete(job, &error_abort); + WITH_JOB_LOCK_GUARD() { + assert(job->status == JOB_STATUS_READY); + job_complete_locked(job, &error_abort); + } job_enter(job); while (!job->deferred_to_main_loop) { aio_poll(qemu_get_aio_context(), true); } - assert(job->status == JOB_STATUS_READY); + assert_job_status_is(job, JOB_STATUS_READY); aio_poll(qemu_get_aio_context(), true); - assert(job->status == JOB_STATUS_PENDING); + assert_job_status_is(job, JOB_STATUS_PENDING); cancel_common(s); } @@ -353,25 +367,26 @@ static void test_cancel_concluded(void) s = create_common(&job); job_start(job); - assert(job->status == JOB_STATUS_RUNNING); + assert_job_status_is(job, JOB_STATUS_RUNNING); s->should_converge = true; job_enter(job); - assert(job->status == JOB_STATUS_READY); - - job_complete(job, &error_abort); + WITH_JOB_LOCK_GUARD() { + assert(job->status == JOB_STATUS_READY); + job_complete_locked(job, &error_abort); + } job_enter(job); while (!job->deferred_to_main_loop) { aio_poll(qemu_get_aio_context(), true); } - assert(job->status == JOB_STATUS_READY); + assert_job_status_is(job, JOB_STATUS_READY); aio_poll(qemu_get_aio_context(), true); - assert(job->status == JOB_STATUS_PENDING); + assert_job_status_is(job, JOB_STATUS_PENDING); - aio_context_acquire(job->aio_context); - job_finalize(job, &error_abort); - aio_context_release(job->aio_context); - assert(job->status == JOB_STATUS_CONCLUDED); + WITH_JOB_LOCK_GUARD() { + job_finalize_locked(job, &error_abort); + assert(job->status == JOB_STATUS_CONCLUDED); + } cancel_common(s); } @@ -417,7 +432,7 @@ static const BlockJobDriver test_yielding_driver = { }; /* - * Test that job_complete() works even on jobs that are in a paused + * Test that job_complete_locked() works even on jobs that are in a paused * state (i.e., STANDBY). * * To do this, run YieldingJob in an IO thread, get it into the READY @@ -425,7 +440,7 @@ static const BlockJobDriver test_yielding_driver = { * acquire the context so the job will not be entered and will thus * remain on STANDBY. * - * job_complete() should still work without error. + * job_complete_locked() should still work without error. * * Note that on the QMP interface, it is impossible to lock an IO * thread before a drained section ends. In practice, the @@ -459,37 +474,44 @@ static void test_complete_in_standby(void) bjob = mk_job(blk, "job", &test_yielding_driver, true, JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); job = &bjob->job; - assert(job->status == JOB_STATUS_CREATED); + assert_job_status_is(job, JOB_STATUS_CREATED); /* Wait for the job to become READY */ job_start(job); - aio_context_acquire(ctx); - AIO_WAIT_WHILE(ctx, job->status != JOB_STATUS_READY); - aio_context_release(ctx); + /* + * Here we are waiting for the status to change, so don't bother + * protecting the read every time. + */ + AIO_WAIT_WHILE_UNLOCKED(ctx, job->status != JOB_STATUS_READY); /* Begin the drained section, pausing the job */ bdrv_drain_all_begin(); - assert(job->status == JOB_STATUS_STANDBY); + assert_job_status_is(job, JOB_STATUS_STANDBY); + /* Lock the IO thread to prevent the job from being run */ aio_context_acquire(ctx); /* This will schedule the job to resume it */ bdrv_drain_all_end(); + aio_context_release(ctx); - /* But the job cannot run, so it will remain on standby */ - assert(job->status == JOB_STATUS_STANDBY); + WITH_JOB_LOCK_GUARD() { + /* But the job cannot run, so it will remain on standby */ + assert(job->status == JOB_STATUS_STANDBY); - /* Even though the job is on standby, this should work */ - job_complete(job, &error_abort); + /* Even though the job is on standby, this should work */ + job_complete_locked(job, &error_abort); - /* The test is done now, clean up. */ - job_finish_sync(job, NULL, &error_abort); - assert(job->status == JOB_STATUS_PENDING); + /* The test is done now, clean up. */ + job_finish_sync_locked(job, NULL, &error_abort); + assert(job->status == JOB_STATUS_PENDING); - job_finalize(job, &error_abort); - assert(job->status == JOB_STATUS_CONCLUDED); + job_finalize_locked(job, &error_abort); + assert(job->status == JOB_STATUS_CONCLUDED); - job_dismiss(&job, &error_abort); + job_dismiss_locked(&job, &error_abort); + } + aio_context_acquire(ctx); destroy_blk(blk); aio_context_release(ctx); iothread_join(iothread); diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c index aa77a3bcb3..e16b80c245 100644 --- a/tests/unit/test-coroutine.c +++ b/tests/unit/test-coroutine.c @@ -610,7 +610,7 @@ static void perf_baseline(void) g_test_message("Function call %u iterations: %f s", maxcycles, duration); } -static __attribute__((noinline)) void perf_cost_func(void *opaque) +static __attribute__((noinline)) void coroutine_fn perf_cost_func(void *opaque) { qemu_coroutine_yield(); } diff --git a/tests/unit/test-crypto-tlscredsx509.c b/tests/unit/test-crypto-tlscredsx509.c index aab4149b56..3c25d75ca1 100644 --- a/tests/unit/test-crypto-tlscredsx509.c +++ b/tests/unit/test-crypto-tlscredsx509.c @@ -75,7 +75,7 @@ static void test_tls_creds(const void *opaque) QCryptoTLSCreds *creds; #define CERT_DIR "tests/test-crypto-tlscredsx509-certs/" - mkdir(CERT_DIR, 0700); + g_mkdir_with_parents(CERT_DIR, 0700); unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); if (data->isServer) { @@ -141,7 +141,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); g_setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1); - mkdir(WORKDIR, 0700); + g_mkdir_with_parents(WORKDIR, 0700); test_tls_init(KEYFILE); diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c index f222959d36..615a1344b4 100644 --- a/tests/unit/test-crypto-tlssession.c +++ b/tests/unit/test-crypto-tlssession.c @@ -249,8 +249,8 @@ static void test_crypto_tls_session_x509(const void *opaque) #define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/" #define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/" - mkdir(CLIENT_CERT_DIR, 0700); - mkdir(SERVER_CERT_DIR, 0700); + g_mkdir_with_parents(CLIENT_CERT_DIR, 0700); + g_mkdir_with_parents(SERVER_CERT_DIR, 0700); unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT); @@ -398,7 +398,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); g_setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1); - mkdir(WORKDIR, 0700); + g_mkdir_with_parents(WORKDIR, 0700); test_tls_init(KEYFILE); test_tls_psk_init(PSKFILE); diff --git a/tests/unit/test-image-locking.c b/tests/unit/test-image-locking.c index ba057bd66c..a47299c247 100644 --- a/tests/unit/test-image-locking.c +++ b/tests/unit/test-image-locking.c @@ -76,10 +76,10 @@ static void check_locked_bytes(int fd, uint64_t perm_locks, static void test_image_locking_basic(void) { BlockBackend *blk1, *blk2, *blk3; - char img_path[] = "/tmp/qtest.XXXXXX"; + g_autofree char *img_path = NULL; uint64_t perm, shared_perm; - int fd = mkstemp(img_path); + int fd = g_file_open_tmp("qtest.XXXXXX", &img_path, NULL); assert(fd >= 0); perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; @@ -117,10 +117,10 @@ static void test_image_locking_basic(void) static void test_set_perm_abort(void) { BlockBackend *blk1, *blk2; - char img_path[] = "/tmp/qtest.XXXXXX"; + g_autofree char *img_path = NULL; uint64_t perm, shared_perm; int r; - int fd = mkstemp(img_path); + int fd = g_file_open_tmp("qtest.XXXXXX", &img_path, NULL); assert(fd >= 0); perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; diff --git a/tests/unit/test-io-channel-command.c b/tests/unit/test-io-channel-command.c index 99056e07c0..aa09c559cd 100644 --- a/tests/unit/test-io-channel-command.c +++ b/tests/unit/test-io-channel-command.c @@ -41,7 +41,8 @@ static void test_io_channel_command_fifo(bool async) unlink(TEST_FIFO); if (access("/bin/socat", X_OK) < 0) { - return; /* Pretend success if socat is not present */ + g_test_skip("socat is missing"); + return; } if (mkfifo(TEST_FIFO, 0600) < 0) { abort(); diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c index 6713886d02..b36a5d972a 100644 --- a/tests/unit/test-io-channel-socket.c +++ b/tests/unit/test-io-channel-socket.c @@ -179,10 +179,12 @@ static void test_io_channel(bool async, test_io_channel_setup_async(listen_addr, connect_addr, &srv, &src, &dst); +#ifndef _WIN32 g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); +#endif g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); @@ -206,10 +208,12 @@ static void test_io_channel(bool async, test_io_channel_setup_async(listen_addr, connect_addr, &srv, &src, &dst); +#ifndef _WIN32 g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); +#endif g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); @@ -236,10 +240,12 @@ static void test_io_channel(bool async, test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst); +#ifndef _WIN32 g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); +#endif g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); @@ -263,10 +269,12 @@ static void test_io_channel(bool async, test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst); +#ifndef _WIN32 g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); +#endif g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); @@ -367,7 +375,6 @@ static void test_io_channel_ipv6_async(void) } -#ifndef _WIN32 static void test_io_channel_unix(bool async) { SocketAddress *listen_addr = g_new0(SocketAddress, 1); @@ -398,6 +405,7 @@ static void test_io_channel_unix_async(void) return test_io_channel_unix(true); } +#ifndef _WIN32 static void test_io_channel_unix_fd_pass(void) { SocketAddress *listen_addr = g_new0(SocketAddress, 1); @@ -491,6 +499,7 @@ static void test_io_channel_unix_fd_pass(void) } g_free(fdrecv); } +#endif /* _WIN32 */ static void test_io_channel_unix_listen_cleanup(void) { @@ -522,9 +531,6 @@ static void test_io_channel_unix_listen_cleanup(void) unlink(TEST_SOCKET); } -#endif /* _WIN32 */ - - static void test_io_channel_ipv4_fd(void) { QIOChannel *ioc; @@ -555,7 +561,7 @@ static void test_io_channel_ipv4_fd(void) int main(int argc, char **argv) { - bool has_ipv4, has_ipv6; + bool has_ipv4, has_ipv6, has_afunix; module_call_init(MODULE_INIT_QOM); qemu_init_main_loop(&error_abort); @@ -588,16 +594,19 @@ int main(int argc, char **argv) test_io_channel_ipv6_async); } + socket_check_afunix_support(&has_afunix); + if (has_afunix) { + g_test_add_func("/io/channel/socket/unix-sync", + test_io_channel_unix_sync); + g_test_add_func("/io/channel/socket/unix-async", + test_io_channel_unix_async); #ifndef _WIN32 - g_test_add_func("/io/channel/socket/unix-sync", - test_io_channel_unix_sync); - g_test_add_func("/io/channel/socket/unix-async", - test_io_channel_unix_async); - g_test_add_func("/io/channel/socket/unix-fd-pass", - test_io_channel_unix_fd_pass); - g_test_add_func("/io/channel/socket/unix-listen-cleanup", - test_io_channel_unix_listen_cleanup); -#endif /* _WIN32 */ + g_test_add_func("/io/channel/socket/unix-fd-pass", + test_io_channel_unix_fd_pass); +#endif + g_test_add_func("/io/channel/socket/unix-listen-cleanup", + test_io_channel_unix_listen_cleanup); + } end: return g_test_run(); diff --git a/tests/unit/test-io-channel-tls.c b/tests/unit/test-io-channel-tls.c index f6fb988c01..cc39247556 100644 --- a/tests/unit/test-io-channel-tls.c +++ b/tests/unit/test-io-channel-tls.c @@ -125,8 +125,8 @@ static void test_io_channel_tls(const void *opaque) #define CLIENT_CERT_DIR "tests/test-io-channel-tls-client/" #define SERVER_CERT_DIR "tests/test-io-channel-tls-server/" - mkdir(CLIENT_CERT_DIR, 0700); - mkdir(SERVER_CERT_DIR, 0700); + g_mkdir_with_parents(CLIENT_CERT_DIR, 0700); + g_mkdir_with_parents(SERVER_CERT_DIR, 0700); unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT); @@ -273,7 +273,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); g_setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1); - mkdir(WORKDIR, 0700); + g_mkdir_with_parents(WORKDIR, 0700); test_tls_init(KEYFILE); diff --git a/tests/unit/test-qga.c b/tests/unit/test-qga.c index 530317044b..b4e0a14573 100644 --- a/tests/unit/test-qga.c +++ b/tests/unit/test-qga.c @@ -32,6 +32,7 @@ static int connect_qga(char *path) g_usleep(G_USEC_PER_SEC); } if (i++ == 10) { + close(s); return -1; } } while (ret == -1); @@ -59,8 +60,8 @@ fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp) fixture->loop = g_main_loop_new(NULL, FALSE); - fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX"); - g_assert_nonnull(mkdtemp(fixture->test_dir)); + fixture->test_dir = g_strdup_printf("%s/qgatest.XXXXXX", g_get_tmp_dir()); + g_assert_nonnull(g_mkdtemp(fixture->test_dir)); path = g_build_filename(fixture->test_dir, "sock", NULL); cwd = g_get_current_dir(); @@ -629,7 +630,7 @@ static void test_qga_get_time(gconstpointer fix) g_assert_cmpint(time, >, 0); } -static void test_qga_blacklist(gconstpointer data) +static void test_qga_blockedrpcs(gconstpointer data) { TestFixture fix; QDict *ret, *error; @@ -637,7 +638,7 @@ static void test_qga_blacklist(gconstpointer data) fixture_setup(&fix, "-b guest-ping,guest-get-time", NULL); - /* check blacklist */ + /* check blocked RPCs */ ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}"); g_assert_nonnull(ret); error = qdict_get_qdict(ret, "error"); @@ -729,7 +730,7 @@ static void test_qga_config(gconstpointer data) g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error)); g_assert_no_error(error); - strv = g_key_file_get_string_list(kf, "general", "blacklist", &n, &error); + strv = g_key_file_get_string_list(kf, "general", "block-rpcs", &n, &error); g_assert_cmpint(n, ==, 2); g_assert_true(g_strv_contains((const char * const *)strv, "guest-ping")); @@ -968,7 +969,7 @@ int main(int argc, char **argv) g_test_add_data_func("/qga/fsfreeze-status", &fix, test_qga_fsfreeze_status); - g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist); + g_test_add_data_func("/qga/blockedrpcs", NULL, test_qga_blockedrpcs); g_test_add_data_func("/qga/config", NULL, test_qga_config); g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec); g_test_add_data_func("/qga/guest-exec-invalid", &fix, diff --git a/tests/unit/test-qobject-input-visitor.c b/tests/unit/test-qobject-input-visitor.c index 14329dabcf..5f614afdbf 100644 --- a/tests/unit/test-qobject-input-visitor.c +++ b/tests/unit/test-qobject-input-visitor.c @@ -447,9 +447,8 @@ static void test_visitor_in_list(TestInputVisitorData *data, g_assert(head != NULL); for (i = 0, item = head; item; item = item->next, i++) { - char string[12]; + g_autofree char *string = g_strdup_printf("string%d", i); - snprintf(string, sizeof(string), "string%d", i); g_assert_cmpstr(item->value->string, ==, string); g_assert_cmpint(item->value->integer, ==, 42 + i); } diff --git a/tests/unit/test-visitor-serialization.c b/tests/unit/test-visitor-serialization.c index 907263d030..667e8fed82 100644 --- a/tests/unit/test-visitor-serialization.c +++ b/tests/unit/test-visitor-serialization.c @@ -427,131 +427,117 @@ static void test_primitive_lists(gconstpointer opaque) ops->deserialize((void **)&pl_copy_ptr, serialize_data, visit_primitive_list, &error_abort); - i = 0; + + switch (pl_copy.type) { + case PTYPE_STRING: + cur_head = pl_copy.value.strings; + break; + case PTYPE_INTEGER: + cur_head = pl_copy.value.integers; + break; + case PTYPE_S8: + cur_head = pl_copy.value.s8_integers; + break; + case PTYPE_S16: + cur_head = pl_copy.value.s16_integers; + break; + case PTYPE_S32: + cur_head = pl_copy.value.s32_integers; + break; + case PTYPE_S64: + cur_head = pl_copy.value.s64_integers; + break; + case PTYPE_U8: + cur_head = pl_copy.value.u8_integers; + break; + case PTYPE_U16: + cur_head = pl_copy.value.u16_integers; + break; + case PTYPE_U32: + cur_head = pl_copy.value.u32_integers; + break; + case PTYPE_U64: + cur_head = pl_copy.value.u64_integers; + break; + case PTYPE_NUMBER: + cur_head = pl_copy.value.numbers; + break; + case PTYPE_BOOLEAN: + cur_head = pl_copy.value.booleans; + break; + default: + g_assert_not_reached(); + } /* compare our deserialized list of primitives to the original */ - do { + i = 0; + while (cur_head) { switch (pl_copy.type) { case PTYPE_STRING: { - strList *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.strings; - } + strList *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpstr(pt->value.string, ==, ptr->value); break; } case PTYPE_INTEGER: { - intList *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.integers; - } + intList *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.integer, ==, ptr->value); break; } case PTYPE_S8: { - int8List *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.s8_integers; - } + int8List *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.s8, ==, ptr->value); break; } case PTYPE_S16: { - int16List *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.s16_integers; - } + int16List *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.s16, ==, ptr->value); break; } case PTYPE_S32: { - int32List *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.s32_integers; - } + int32List *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.s32, ==, ptr->value); break; } case PTYPE_S64: { - int64List *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.s64_integers; - } + int64List *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.s64, ==, ptr->value); break; } case PTYPE_U8: { - uint8List *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.u8_integers; - } + uint8List *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.u8, ==, ptr->value); break; } case PTYPE_U16: { - uint16List *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.u16_integers; - } + uint16List *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.u16, ==, ptr->value); break; } case PTYPE_U32: { - uint32List *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.u32_integers; - } + uint32List *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.u32, ==, ptr->value); break; } case PTYPE_U64: { - uint64List *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.u64_integers; - } + uint64List *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(pt->value.u64, ==, ptr->value); break; } case PTYPE_NUMBER: { - numberList *ptr; GString *double_expected = g_string_new(""); GString *double_actual = g_string_new(""); - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.numbers; - } + numberList *ptr = cur_head; + cur_head = ptr->next; /* we serialize with %f for our reference visitors, so rather than * fuzzy floating math to test "equality", just compare the * formatted values @@ -564,13 +550,8 @@ static void test_primitive_lists(gconstpointer opaque) break; } case PTYPE_BOOLEAN: { - boolList *ptr; - if (cur_head) { - ptr = cur_head; - cur_head = ptr->next; - } else { - cur_head = ptr = pl_copy.value.booleans; - } + boolList *ptr = cur_head; + cur_head = ptr->next; g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value); break; } @@ -578,9 +559,9 @@ static void test_primitive_lists(gconstpointer opaque) g_assert_not_reached(); } i++; - } while (cur_head); + } - g_assert_cmpint(i, ==, 33); + g_assert_cmpint(i, ==, 32); ops->cleanup(serialize_data); dealloc_helper(&pl, visit_primitive_list, &error_abort); diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c index 72077b5780..541bb4f63e 100644 --- a/tests/unit/test-vmstate.c +++ b/tests/unit/test-vmstate.c @@ -87,17 +87,16 @@ static void save_buffer(const uint8_t *buf, size_t buf_size) static void compare_vmstate(const uint8_t *wire, size_t size) { QEMUFile *f = open_test_file(false); - uint8_t result[size]; + g_autofree uint8_t *result = g_malloc(size); /* read back as binary */ - g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==, - sizeof(result)); + g_assert_cmpint(qemu_get_buffer(f, result, size), ==, size); g_assert(!qemu_file_get_error(f)); /* Compare that what is on the file is the same that what we expected to be there */ - SUCCESS(memcmp(result, wire, sizeof(result))); + SUCCESS(memcmp(result, wire, size)); /* Must reach EOF */ qemu_get_byte(f); diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c index 9b1dab2f28..fecdf915e7 100644 --- a/tests/vhost-user-bridge.c +++ b/tests/vhost-user-bridge.c @@ -631,7 +631,6 @@ static void *notifier_thread(void *arg) static void vubr_host_notifier_setup(VubrDev *dev) { - char template[] = "/tmp/vubr-XXXXXX"; pthread_t thread; size_t length; void *addr; @@ -639,7 +638,7 @@ vubr_host_notifier_setup(VubrDev *dev) length = qemu_real_host_page_size() * VHOST_USER_BRIDGE_MAX_QUEUES; - fd = mkstemp(template); + fd = g_file_open_tmp("vubr-XXXXXX", NULL, NULL); if (fd < 0) { vubr_die("mkstemp()"); } diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index 8d2a164552..2cc2203d09 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -15,7 +15,7 @@ endif EFI_AARCH64 = $(wildcard $(BUILD_DIR)/pc-bios/edk2-aarch64-code.fd) -X86_IMAGES := freebsd netbsd openbsd fedora haiku.x86_64 +X86_IMAGES := freebsd netbsd openbsd haiku.x86_64 ifneq ($(GENISOIMAGE),) X86_IMAGES += centos ifneq ($(EFI_AARCH64),) @@ -45,7 +45,6 @@ vm-help vm-test: @echo " vm-build-freebsd - Build QEMU in FreeBSD VM" @echo " vm-build-netbsd - Build QEMU in NetBSD VM" @echo " vm-build-openbsd - Build QEMU in OpenBSD VM" - @echo " vm-build-fedora - Build QEMU in Fedora VM" ifneq ($(GENISOIMAGE),) @echo " vm-build-centos - Build QEMU in CentOS VM, with Docker" ifneq ($(EFI_AARCH64),) diff --git a/tests/vm/fedora b/tests/vm/fedora deleted file mode 100755 index 12eca919a0..0000000000 --- a/tests/vm/fedora +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python3 -# -# Fedora VM image -# -# Copyright 2019 Red Hat Inc. -# -# Authors: -# Gerd Hoffmann -# -# This code is licensed under the GPL version 2 or later. See -# the COPYING file in the top-level directory. -# - -import os -import re -import sys -import time -import socket -import subprocess -import basevm - -class FedoraVM(basevm.BaseVM): - name = "fedora" - arch = "x86_64" - - base = "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/30/" - link = base + "Server/x86_64/iso/Fedora-Server-netinst-x86_64-30-1.2.iso" - repo = base + "Server/x86_64/os/" - full = base + "Everything/x86_64/os/" - csum = "5e4eac4566d8c572bfb3bcf54b7d6c82006ec3c6c882a2c9235c6d3494d7b100" - size = "20G" - pkgs = [ - # tools - 'git-core', - 'gcc', 'binutils', 'make', 'ninja-build', - - # perl - 'perl', - - # libs: usb - '"pkgconfig(libusb-1.0)"', - '"pkgconfig(libusbredirparser-0.5)"', - - # libs: crypto - '"pkgconfig(gnutls)"', - - # libs: ui - '"pkgconfig(sdl2)"', - '"pkgconfig(gtk+-3.0)"', - '"pkgconfig(ncursesw)"', - - # libs: audio - '"pkgconfig(libpulse)"', - '"pkgconfig(alsa)"', - - # libs: migration - '"pkgconfig(libzstd)"', -] - - BUILD_SCRIPT = """ - set -e; - rm -rf /home/qemu/qemu-test.* - cd $(mktemp -d /home/qemu/qemu-test.XXXXXX); - mkdir src build; cd src; - tar -xf /dev/vdb; - cd ../build - ../src/configure --python=python3 {configure_opts}; - gmake --output-sync -j{jobs} {target} {verbose}; - """ - - def build_image(self, img): - self.print_step("Downloading install iso") - cimg = self._download_with_cache(self.link, sha256sum=self.csum) - img_tmp = img + ".tmp" - iso = img + ".install.iso" - - self.print_step("Preparing iso and disk image") - subprocess.check_call(["cp", "-f", cimg, iso]) - self.exec_qemu_img("create", "-f", "qcow2", img_tmp, self.size) - self.print_step("Booting installer") - self.boot(img_tmp, extra_args = [ - "-machine", "graphics=off", - "-device", "VGA", - "-cdrom", iso - ]) - self.console_init(300) - self.console_wait("installation process.") - time.sleep(0.3) - self.console_send("\t") - time.sleep(0.3) - self.console_send(" console=ttyS0") - proxy = os.environ.get("http_proxy") - if not proxy is None: - self.console_send(" proxy=%s" % proxy) - self.console_send(" inst.proxy=%s" % proxy) - self.console_send(" inst.repo=%s" % self.repo) - self.console_send("\n") - - self.console_wait_send("2) Use text mode", "2\n") - - self.console_wait_send("5) [!] Installation Dest", "5\n") - self.console_wait_send("1) [x]", "c\n") - self.console_wait_send("2) [ ] Use All Space", "2\n") - self.console_wait_send("2) [x] Use All Space", "c\n") - self.console_wait_send("1) [ ] Standard Part", "1\n") - self.console_wait_send("1) [x] Standard Part", "c\n") - - self.console_wait_send("7) [!] Root password", "7\n") - self.console_wait("Password:") - self.console_send("%s\n" % self._config["root_pass"]) - self.console_wait("Password (confirm):") - self.console_send("%s\n" % self._config["root_pass"]) - - self.console_wait_send("8) [ ] User creation", "8\n") - self.console_wait_send("1) [ ] Create user", "1\n") - self.console_wait_send("3) User name", "3\n") - self.console_wait_send("ENTER:", "%s\n" % self._config["guest_user"]) - self.console_wait_send("4) [ ] Use password", "4\n") - self.console_wait_send("5) Password", "5\n") - self.console_wait("Password:") - self.console_send("%s\n" % self._config["guest_pass"]) - self.console_wait("Password (confirm):") - self.console_send("%s\n" % self._config["guest_pass"]) - self.console_wait_send("7) Groups", "c\n") - - while True: - good = self.console_wait("3) [x] Installation", - "3) [!] Installation") - self.console_send("r\n") - if good: - break - time.sleep(10) - - while True: - good = self.console_wait("4) [x] Software", - "4) [!] Software") - self.console_send("r\n") - if good: - break - time.sleep(10) - self.console_send("r\n" % self._config["guest_pass"]) - - self.console_wait_send("'b' to begin install", "b\n") - - self.print_step("Installation started now, this will take a while") - - self.console_wait_send("Installation complete", "\n") - self.print_step("Installation finished, rebooting") - - # setup qemu user - prompt = " ~]$" - self.console_ssh_init(prompt, self._config["guest_user"], - self._config["guest_pass"]) - self.console_wait_send(prompt, "exit\n") - - # setup root user - prompt = " ~]#" - self.console_ssh_init(prompt, "root", self._config["root_pass"]) - self.console_sshd_config(prompt) - - # setup virtio-blk #1 (tarfile) - self.console_wait(prompt) - self.console_send("echo 'KERNEL==\"vdb\" MODE=\"666\"' >> %s\n" % - "/etc/udev/rules.d/99-qemu.rules") - - self.print_step("Configuration finished, rebooting") - self.console_wait_send(prompt, "reboot\n") - self.console_wait("login:") - self.wait_ssh() - - self.print_step("Installing packages") - self.ssh_root_check("rm -vf /etc/yum.repos.d/fedora*.repo\n") - self.ssh_root_check("echo '[fedora]' >> /etc/yum.repos.d/qemu.repo\n") - self.ssh_root_check("echo 'baseurl=%s' >> /etc/yum.repos.d/qemu.repo\n" % self.full) - self.ssh_root_check("echo 'gpgcheck=0' >> /etc/yum.repos.d/qemu.repo\n") - self.ssh_root_check("dnf install -y %s\n" % " ".join(self.pkgs)) - - # shutdown - self.ssh_root(self.poweroff) - self.console_wait("sleep state S5") - self.wait() - - if os.path.exists(img): - os.remove(img) - os.rename(img_tmp, img) - os.remove(iso) - self.print_step("All done") - -if __name__ == "__main__": - sys.exit(basevm.main(FedoraVM)) diff --git a/tests/vm/freebsd b/tests/vm/freebsd index cd1fabde52..3643fe325d 100755 --- a/tests/vm/freebsd +++ b/tests/vm/freebsd @@ -63,6 +63,9 @@ class FreeBSDVM(basevm.BaseVM): # libs: migration "zstd", + + # libs: networking + "libslirp", ] BUILD_SCRIPT = """ diff --git a/tests/vm/haiku.x86_64 b/tests/vm/haiku.x86_64 index 936f7d2ae2..29668bc272 100755 --- a/tests/vm/haiku.x86_64 +++ b/tests/vm/haiku.x86_64 @@ -71,6 +71,7 @@ class HaikuVM(basevm.BaseVM): "devel:libpixman_1", "devel:libpng16", "devel:libsdl2_2.0", + "devel:libslirp", "devel:libsnappy", "devel:libssh2", "devel:libtasn1", @@ -89,7 +90,7 @@ class HaikuVM(basevm.BaseVM): mkdir -p /usr/bin ln -s /boot/system/bin/env /usr/bin/env cd ../build - ../src/configure --disable-slirp {configure_opts}; + ../src/configure {configure_opts}; make --output-sync -j{jobs} {target} {verbose}; """ diff --git a/tests/vm/netbsd b/tests/vm/netbsd index aa883ec23c..aa54338dfa 100755 --- a/tests/vm/netbsd +++ b/tests/vm/netbsd @@ -22,8 +22,8 @@ class NetBSDVM(basevm.BaseVM): name = "netbsd" arch = "x86_64" - link = "https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.2/images/NetBSD-9.2-amd64.iso" - csum = "5ee0ea101f73386b9b424f5d1041e371db3c42fdd6f4e4518dc79c4a08f31d43091ebe93425c9f0dcaaed2b51131836fe6774f33f89030b58d64709b35fda72f" + link = "https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/images/NetBSD-9.3-amd64.iso" + csum = "2bfce544f762a579f61478e7106c436fc48731ff25cf6f79b392ba5752e6f5ec130364286f7471716290a5f033637cf56aacee7fedb91095face59adf36300c3" size = "20G" pkgs = [ # tools @@ -54,6 +54,9 @@ class NetBSDVM(basevm.BaseVM): # libs: migration "zstd", + + # libs: networking + "libslirp", ] BUILD_SCRIPT = """ diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c index 752928741d..2f08471627 100644 --- a/tools/virtiofsd/fuse_lowlevel.c +++ b/tools/virtiofsd/fuse_lowlevel.c @@ -2025,7 +2025,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor); if (arg->major == 7 && arg->minor >= 6) { - fuse_log(FUSE_LOG_DEBUG, "flags=0x%016llx\n", flags); + fuse_log(FUSE_LOG_DEBUG, "flags=0x%016" PRIx64 "\n", flags); fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n", arg->max_readahead); } se->conn.proto_major = arg->major; @@ -2174,7 +2174,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, if (se->conn.want & (~se->conn.capable)) { fuse_log(FUSE_LOG_ERR, "fuse: error: filesystem requested capabilities " - "0x%llx that are not supported by kernel, aborting.\n", + "0x%" PRIx64 " that are not supported by kernel, aborting.\n", se->conn.want & (~se->conn.capable)); fuse_reply_err(req, EPROTO); se->error = -EPROTO; diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c index a52eacf82e..9368e292e4 100644 --- a/tools/virtiofsd/fuse_virtio.c +++ b/tools/virtiofsd/fuse_virtio.c @@ -379,7 +379,7 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, copy_iov(iov, count, in_sg, in_num, iov_len); /* - * Build a copy of the the in_sg iov so we can skip bits in it, + * Build a copy of the in_sg iov so we can skip bits in it, * including changing the offsets */ in_sg_cpy = g_new(struct iovec, in_num); diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 7a73dfcce9..20f0f41f99 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -767,19 +767,10 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn) fuse_log(FUSE_LOG_DEBUG, "lo_init: enabling killpriv_v2\n"); conn->want |= FUSE_CAP_HANDLE_KILLPRIV_V2; lo->killpriv_v2 = 1; - } else if (lo->user_killpriv_v2 == -1 && - conn->capable & FUSE_CAP_HANDLE_KILLPRIV_V2) { - /* - * User did not specify a value for killpriv_v2. By default enable it - * if connection offers this capability - */ - fuse_log(FUSE_LOG_DEBUG, "lo_init: enabling killpriv_v2\n"); - conn->want |= FUSE_CAP_HANDLE_KILLPRIV_V2; - lo->killpriv_v2 = 1; } else { /* - * Either user specified to disable killpriv_v2, or connection does - * not offer this capability. Disable killpriv_v2 in both the cases + * Either user specified to disable killpriv_v2, or did not + * specify anything. Disable killpriv_v2 in both the cases. */ fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling killpriv_v2\n"); conn->want &= ~FUSE_CAP_HANDLE_KILLPRIV_V2; @@ -4194,6 +4185,7 @@ static void setup_nofile_rlimit(unsigned long rlimit_nofile) static void log_func(enum fuse_log_level level, const char *fmt, va_list ap) { g_autofree char *localfmt = NULL; + char buf[64]; if (current_log_level < level) { return; @@ -4206,9 +4198,11 @@ static void log_func(enum fuse_log_level level, const char *fmt, va_list ap) fmt); } else { g_autoptr(GDateTime) now = g_date_time_new_now_utc(); - g_autofree char *nowstr = g_date_time_format(now, "%Y-%m-%d %H:%M:%S.%f%z"); + g_autofree char *nowstr = g_date_time_format(now, + "%Y-%m-%d %H:%M:%S.%%06d%z"); + snprintf(buf, 64, nowstr, g_date_time_get_microsecond(now)); localfmt = g_strdup_printf("[%s] [ID: %08ld] %s", - nowstr, syscall(__NR_gettid), fmt); + buf, syscall(__NR_gettid), fmt); } fmt = localfmt; } diff --git a/trace-events b/trace-events index bc71006675..035f3d570d 100644 --- a/trace-events +++ b/trace-events @@ -46,34 +46,6 @@ ram_block_discard_range(const char *rbname, void *hva, size_t length, bool need_ memory_notdirty_write_access(uint64_t vaddr, uint64_t ram_addr, unsigned size) "0x%" PRIx64 " ram_addr 0x%" PRIx64 " size %u" memory_notdirty_set_dirty(uint64_t vaddr) "0x%" PRIx64 -# gdbstub.c -gdbstub_op_start(const char *device) "Starting gdbstub using device %s" -gdbstub_op_exiting(uint8_t code) "notifying exit with code=0x%02x" -gdbstub_op_continue(void) "Continuing all CPUs" -gdbstub_op_continue_cpu(int cpu_index) "Continuing CPU %d" -gdbstub_op_stepping(int cpu_index) "Stepping CPU %d" -gdbstub_op_extra_info(const char *info) "Thread extra info: %s" -gdbstub_hit_watchpoint(const char *type, int cpu_gdb_index, uint64_t vaddr) "Watchpoint hit, type=\"%s\" cpu=%d, vaddr=0x%" PRIx64 "" -gdbstub_hit_internal_error(void) "RUN_STATE_INTERNAL_ERROR" -gdbstub_hit_break(void) "RUN_STATE_DEBUG" -gdbstub_hit_paused(void) "RUN_STATE_PAUSED" -gdbstub_hit_shutdown(void) "RUN_STATE_SHUTDOWN" -gdbstub_hit_io_error(void) "RUN_STATE_IO_ERROR" -gdbstub_hit_watchdog(void) "RUN_STATE_WATCHDOG" -gdbstub_hit_unknown(int state) "Unknown run state=0x%x" -gdbstub_io_reply(const char *message) "Sent: %s" -gdbstub_io_binaryreply(size_t ofs, const char *line) "0x%04zx: %s" -gdbstub_io_command(const char *command) "Received: %s" -gdbstub_io_got_ack(void) "Got ACK" -gdbstub_io_got_unexpected(uint8_t ch) "Got 0x%02x when expecting ACK/NACK" -gdbstub_err_got_nack(void) "Got NACK, retransmitting" -gdbstub_err_garbage(uint8_t ch) "received garbage between packets: 0x%02x" -gdbstub_err_overrun(void) "command buffer overrun, dropping command" -gdbstub_err_invalid_repeat(uint8_t ch) "got invalid RLE count: 0x%02x" -gdbstub_err_invalid_rle(void) "got invalid RLE sequence" -gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x%02x" -gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x" - # job.c job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)" diff --git a/trace/control-target.c b/trace/control-target.c index 8418673c18..232c97a4a1 100644 --- a/trace/control-target.c +++ b/trace/control-target.c @@ -65,7 +65,7 @@ static void trace_event_synchronize_vcpu_state_dynamic( { bitmap_copy(vcpu->trace_dstate, vcpu->trace_dstate_delayed, CPU_TRACE_DSTATE_MAX_EVENTS); - cpu_tb_jmp_cache_clear(vcpu); + tcg_flush_jmp_cache(vcpu); } void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, diff --git a/ui/clipboard.c b/ui/clipboard.c index 9079ef829b..3d14bffaf8 100644 --- a/ui/clipboard.c +++ b/ui/clipboard.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" #include "ui/clipboard.h" +#include "trace.h" static NotifierList clipboard_notifiers = NOTIFIER_LIST_INITIALIZER(clipboard_notifiers); @@ -43,17 +44,23 @@ void qemu_clipboard_peer_release(QemuClipboardPeer *peer, bool qemu_clipboard_check_serial(QemuClipboardInfo *info, bool client) { + bool ok; + if (!info->has_serial || !cbinfo[info->selection] || !cbinfo[info->selection]->has_serial) { + trace_clipboard_check_serial(-1, -1, true); return true; } if (client) { - return cbinfo[info->selection]->serial >= info->serial; + ok = info->serial >= cbinfo[info->selection]->serial; } else { - return cbinfo[info->selection]->serial > info->serial; + ok = info->serial > cbinfo[info->selection]->serial; } + + trace_clipboard_check_serial(cbinfo[info->selection]->serial, info->serial, ok); + return ok; } void qemu_clipboard_update(QemuClipboardInfo *info) @@ -132,7 +139,14 @@ void qemu_clipboard_request(QemuClipboardInfo *info, void qemu_clipboard_reset_serial(void) { QemuClipboardNotify notify = { .type = QEMU_CLIPBOARD_RESET_SERIAL }; + int i; + for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) { + QemuClipboardInfo *info = qemu_clipboard_info(i); + if (info) { + info->serial = 0; + } + } notifier_list_notify(&clipboard_notifiers, ¬ify); } diff --git a/ui/cocoa.m b/ui/cocoa.m index 5a8bd5dd84..660d3e0935 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -100,13 +100,9 @@ static int cursor_hide = 1; static int left_command_key_enabled = 1; static bool swap_opt_cmd; -static int gArgc; -static char **gArgv; static bool stretch_video; static NSTextField *pauseLabel; -static QemuSemaphore display_init_sem; -static QemuSemaphore app_started_sem; static bool allow_events; static NSInteger cbchangecount = -1; @@ -597,7 +593,7 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven /* * Don't try to tell QEMU about UI information in the application * startup phase -- we haven't yet registered dcl with the QEMU UI - * layer, and also trying to take the iothread lock would deadlock. + * layer. * When cocoa_display_init() does register the dcl, the UI layer * will call cocoa_switch(), which will call updateUIInfo, so * we don't lose any information here. @@ -790,16 +786,6 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven - (bool) handleEvent:(NSEvent *)event { - if(!allow_events) { - /* - * Just let OSX have all events that arrive before - * applicationDidFinishLaunching. - * This avoids a deadlock on the iothread lock, which cocoa_display_init() - * will not drop until after the app_started_sem is posted. (In theory - * there should not be any such events, but OSX Catalina now emits some.) - */ - return false; - } return bool_with_iothread_lock(^{ return [self handleEventLocked:event]; }); @@ -1287,8 +1273,6 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven { COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n"); allow_events = true; - /* Tell cocoa_display_init to proceed */ - qemu_sem_post(&app_started_sem); } - (void)applicationWillTerminate:(NSNotification *)aNotification @@ -1919,92 +1903,45 @@ static void cocoa_clipboard_request(QemuClipboardInfo *info, /* * The startup process for the OSX/Cocoa UI is complicated, because * OSX insists that the UI runs on the initial main thread, and so we - * need to start a second thread which runs the vl.c qemu_main(): - * - * Initial thread: 2nd thread: + * need to start a second thread which runs the qemu_default_main(): * in main(): - * create qemu-main thread - * wait on display_init semaphore - * call qemu_main() - * ... - * in cocoa_display_init(): - * post the display_init semaphore - * wait on app_started semaphore - * create application, menus, etc - * enter OSX run loop - * in applicationDidFinishLaunching: - * post app_started semaphore - * tell main thread to fullscreen if needed - * [...] - * run qemu main-loop - * - * We do this in two stages so that we don't do the creation of the - * GUI application menus and so on for command line options like --help - * where we want to just print text to stdout and exit immediately. + * in cocoa_display_init(): + * assign cocoa_main to qemu_main + * create application, menus, etc + * in cocoa_main(): + * create qemu-main thread + * enter OSX run loop */ static void *call_qemu_main(void *opaque) { int status; - COCOA_DEBUG("Second thread: calling qemu_main()\n"); - status = qemu_main(gArgc, gArgv, *_NSGetEnviron()); - COCOA_DEBUG("Second thread: qemu_main() returned, exiting\n"); + COCOA_DEBUG("Second thread: calling qemu_default_main()\n"); + qemu_mutex_lock_iothread(); + status = qemu_default_main(); + qemu_mutex_unlock_iothread(); + COCOA_DEBUG("Second thread: qemu_default_main() returned, exiting\n"); [cbowner release]; exit(status); } -int main (int argc, char **argv) { +static int cocoa_main() +{ QemuThread thread; - COCOA_DEBUG("Entered main()\n"); - gArgc = argc; - gArgv = argv; - - qemu_sem_init(&display_init_sem, 0); - qemu_sem_init(&app_started_sem, 0); + COCOA_DEBUG("Entered %s()\n", __func__); + qemu_mutex_unlock_iothread(); qemu_thread_create(&thread, "qemu_main", call_qemu_main, NULL, QEMU_THREAD_DETACHED); - COCOA_DEBUG("Main thread: waiting for display_init_sem\n"); - qemu_sem_wait(&display_init_sem); - COCOA_DEBUG("Main thread: initializing app\n"); - - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - - // Pull this console process up to being a fully-fledged graphical - // app with a menubar and Dock icon - ProcessSerialNumber psn = { 0, kCurrentProcess }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - - [QemuApplication sharedApplication]; - - create_initial_menus(); - - /* - * Create the menu entries which depend on QEMU state (for consoles - * and removeable devices). These make calls back into QEMU functions, - * which is OK because at this point we know that the second thread - * holds the iothread lock and is synchronously waiting for us to - * finish. - */ - add_console_menu_entries(); - addRemovableDevicesMenuItems(); - - // Create an Application controller - QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init]; - [NSApp setDelegate:appController]; - // Start the main event loop COCOA_DEBUG("Main thread: entering OSX run loop\n"); [NSApp run]; - COCOA_DEBUG("Main thread: left OSX run loop, exiting\n"); + COCOA_DEBUG("Main thread: left OSX run loop, which should never happen\n"); - [appController release]; - [pool release]; - - return 0; + abort(); } @@ -2083,25 +2020,42 @@ static void cocoa_refresh(DisplayChangeListener *dcl) static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n"); - /* Tell main thread to go ahead and create the app and enter the run loop */ - qemu_sem_post(&display_init_sem); - qemu_sem_wait(&app_started_sem); - COCOA_DEBUG("cocoa_display_init: app start completed\n"); + qemu_main = cocoa_main; + + // Pull this console process up to being a fully-fledged graphical + // app with a menubar and Dock icon + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + + [QemuApplication sharedApplication]; + + create_initial_menus(); + + /* + * Create the menu entries which depend on QEMU state (for consoles + * and removeable devices). These make calls back into QEMU functions, + * which is OK because at this point we know that the second thread + * holds the iothread lock and is synchronously waiting for us to + * finish. + */ + add_console_menu_entries(); + addRemovableDevicesMenuItems(); + + // Create an Application controller + QemuCocoaAppController *controller = [[QemuCocoaAppController alloc] init]; + [NSApp setDelegate:controller]; - QemuCocoaAppController *controller = (QemuCocoaAppController *)[[NSApplication sharedApplication] delegate]; /* if fullscreen mode is to be used */ if (opts->has_full_screen && opts->full_screen) { - dispatch_async(dispatch_get_main_queue(), ^{ - [NSApp activateIgnoringOtherApps: YES]; - [controller toggleFullScreen: nil]; - }); + [NSApp activateIgnoringOtherApps: YES]; + [controller toggleFullScreen: nil]; } if (opts->u.cocoa.has_full_grab && opts->u.cocoa.full_grab) { - dispatch_async(dispatch_get_main_queue(), ^{ - [controller setFullGrab: nil]; - }); + [controller setFullGrab: nil]; } if (opts->has_show_cursor && opts->show_cursor) { @@ -2121,6 +2075,8 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts) qemu_event_init(&cbevent, false); cbowner = [[QemuCocoaPasteboardTypeOwner alloc] init]; qemu_clipboard_peer_register(&cbpeer); + + [pool release]; } static QemuDisplay qemu_display_cocoa = { diff --git a/ui/console.c b/ui/console.c index e139f7115e..49da6a91df 100644 --- a/ui/console.c +++ b/ui/console.c @@ -304,8 +304,8 @@ static bool png_save(int fd, pixman_image_t *image, Error **errp) { int width = pixman_image_get_width(image); int height = pixman_image_get_height(image); - g_autofree png_struct *png_ptr = NULL; - g_autofree png_info *info_ptr = NULL; + png_struct *png_ptr; + png_info *info_ptr; g_autoptr(pixman_image_t) linebuf = qemu_pixman_linebuf_create(PIXMAN_a8r8g8b8, width); uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf); @@ -346,7 +346,6 @@ static bool png_save(int fd, pixman_image_t *image, Error **errp) qemu_pixman_linebuf_fill(linebuf, image, width, 0, y); png_write_row(png_ptr, buf); } - qemu_pixman_image_unref(linebuf); png_write_end(png_ptr, NULL); @@ -1368,6 +1367,7 @@ static const int qcode_to_keysym[Q_KEY_CODE__MAX] = { [Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP, [Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN, [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE, + [Q_KEY_CODE_TAB] = QEMU_KEY_TAB, [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE, }; @@ -2575,11 +2575,13 @@ static void vc_chr_open(Chardev *chr, void qemu_console_resize(QemuConsole *s, int width, int height) { - DisplaySurface *surface; + DisplaySurface *surface = qemu_console_surface(s); assert(s->console_type == GRAPHIC_CONSOLE); - if (qemu_console_get_width(s, -1) == width && + if ((s->scanout.kind != SCANOUT_SURFACE || + (surface && surface->flags & QEMU_ALLOCATED_FLAG)) && + qemu_console_get_width(s, -1) == width && qemu_console_get_height(s, -1) == height) { return; } diff --git a/ui/curses.c b/ui/curses.c index 861d63244c..de962faa7c 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -69,7 +69,7 @@ static void curses_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { console_ch_t *line; - cchar_t curses_line[width]; + g_autofree cchar_t *curses_line = g_new(cchar_t, width); wchar_t wch[CCHARW_MAX]; attr_t attrs; short colors; diff --git a/ui/dbus.h b/ui/dbus.h index c001c11f70..9c149e7b41 100644 --- a/ui/dbus.h +++ b/ui/dbus.h @@ -31,7 +31,7 @@ #include "ui/console.h" #include "ui/clipboard.h" -#include "dbus-display1.h" +#include "ui/dbus-display1.h" typedef struct DBusClipboardRequest { GDBusMethodInvocation *invocation; diff --git a/ui/meson.build b/ui/meson.build index e9f48c5315..ec13949776 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -81,7 +81,7 @@ if dbus_display '--interface-prefix', 'org.qemu.', '--c-namespace', 'QemuDBus', '--generate-c-code', '@BASENAME@']) - dbus_ss.add(when: [gio, pixman, opengl], + dbus_ss.add(when: [gio, pixman, opengl, gbm], if_true: [files( 'dbus-chardev.c', 'dbus-clipboard.c', diff --git a/ui/trace-events b/ui/trace-events index a922f00e10..977577fbba 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -127,15 +127,20 @@ xkeymap_vendor(const char *name) "vendor '%s'" xkeymap_keycodes(const char *name) "keycodes '%s'" xkeymap_keymap(const char *name) "keymap '%s'" +# clipboard.c +clipboard_check_serial(int cur, int recv, bool ok) "cur:%d recv:%d %d" + # vdagent.c vdagent_open(void) "" vdagent_close(void) "" +vdagent_disconnect(void) "" vdagent_send(const char *name) "msg %s" vdagent_send_empty_clipboard(void) "" vdagent_recv_chunk(uint32_t size) "size %d" vdagent_recv_msg(const char *name, uint32_t size) "msg %s, size %d" vdagent_peer_cap(const char *name) "cap %s" vdagent_cb_grab_selection(const char *name) "selection %s" +vdagent_cb_grab_discard(const char *name, int cur, int recv) "selection %s, cur:%d recv:%d" vdagent_cb_grab_type(const char *name) "type %s" vdagent_cb_serial_discard(uint32_t current, uint32_t received) "current=%u, received=%u" diff --git a/ui/vdagent.c b/ui/vdagent.c index aa6167f0b4..4bf50f0c4d 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -471,7 +471,7 @@ static void vdagent_clipboard_reset_serial(VDAgentChardev *vd) /* reopen the agent connection to reset the serial state */ qemu_chr_be_event(chr, CHR_EVENT_CLOSED); - qemu_chr_be_event(chr, CHR_EVENT_OPENED); + /* OPENED again after the guest disconnected, see set_fe_open */ } static void vdagent_clipboard_notify(Notifier *notifier, void *data) @@ -533,6 +533,8 @@ static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t info->has_serial = true; info->serial = *(uint32_t *)data; if (info->serial < vd->last_serial[s]) { + trace_vdagent_cb_grab_discard(GET_NAME(sel_name, s), + vd->last_serial[s], info->serial); /* discard lower-ordering guest grab */ return; } @@ -544,7 +546,7 @@ static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t if (size > sizeof(uint32_t) * 10) { /* * spice has 6 types as of 2021. Limiting to 10 entries - * so we we have some wiggle room. + * so we have some wiggle room. */ return; } @@ -717,8 +719,10 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg) if (have_mouse(vd) && vd->mouse_hs) { qemu_input_handler_activate(vd->mouse_hs); } + + memset(vd->last_serial, 0, sizeof(vd->last_serial)); + if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) { - memset(vd->last_serial, 0, sizeof(vd->last_serial)); vd->cbpeer.name = "vdagent"; vd->cbpeer.notifier.notify = vdagent_clipboard_notify; vd->cbpeer.request = vdagent_clipboard_request; @@ -853,6 +857,8 @@ static void vdagent_chr_accept_input(Chardev *chr) static void vdagent_disconnect(VDAgentChardev *vd) { + trace_vdagent_disconnect(); + buffer_reset(&vd->outbuf); vdagent_reset_bufs(vd); vd->caps = 0; @@ -869,6 +875,9 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open) { if (!fe_open) { trace_vdagent_close(); + /* To reset_serial, we CLOSED our side. Make sure the other end knows we + * are ready again. */ + qemu_chr_be_event(chr, CHR_EVENT_OPENED); return; } diff --git a/util/cutils.c b/util/cutils.c index cb43dda213..def9c746ce 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -39,6 +39,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + #ifdef G_OS_WIN32 #include #include diff --git a/util/iova-tree.c b/util/iova-tree.c index fee530a579..536789797e 100644 --- a/util/iova-tree.c +++ b/util/iova-tree.c @@ -164,11 +164,11 @@ void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator) g_tree_foreach(tree->tree, iova_tree_traverse, iterator); } -void iova_tree_remove(IOVATree *tree, const DMAMap *map) +void iova_tree_remove(IOVATree *tree, DMAMap map) { const DMAMap *overlap; - while ((overlap = iova_tree_find(tree, map))) { + while ((overlap = iova_tree_find(tree, &map))) { g_tree_remove(tree->tree, overlap); } } diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c index 5b90cb68ea..5ed7d29183 100644 --- a/util/mmap-alloc.c +++ b/util/mmap-alloc.c @@ -53,37 +53,6 @@ size_t qemu_fd_getpagesize(int fd) return qemu_real_host_page_size(); } -size_t qemu_mempath_getpagesize(const char *mem_path) -{ -#ifdef CONFIG_LINUX - struct statfs fs; - int ret; - - if (mem_path) { - do { - ret = statfs(mem_path, &fs); - } while (ret != 0 && errno == EINTR); - - if (ret != 0) { - fprintf(stderr, "Couldn't statfs() memory path: %s\n", - strerror(errno)); - exit(1); - } - - if (fs.f_type == HUGETLBFS_MAGIC) { - /* It's hugepage, return the huge page size */ - return fs.f_bsize; - } - } -#ifdef __sparc__ - /* SPARC Linux needs greater alignment than the pagesize */ - return QEMU_VMALLOC_ALIGN; -#endif -#endif - - return qemu_real_host_page_size(); -} - #define OVERCOMMIT_MEMORY_PATH "/proc/sys/vm/overcommit_memory" static bool map_noreserve_effective(int fd, uint32_t qemu_map_flags) { diff --git a/util/oslib-posix.c b/util/oslib-posix.c index bffec18869..827a7aadba 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -58,10 +58,6 @@ #include #endif -#ifdef __APPLE__ -#include -#endif - #include "qemu/mmap-alloc.h" #ifdef CONFIG_DEBUG_STACK_USAGE @@ -257,6 +253,25 @@ void qemu_set_cloexec(int fd) assert(f != -1); } +int qemu_socketpair(int domain, int type, int protocol, int sv[2]) +{ + int ret; + +#ifdef SOCK_CLOEXEC + ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv); + if (ret != -1 || errno != EINVAL) { + return ret; + } +#endif + ret = socketpair(domain, type, protocol, sv);; + if (ret == 0) { + qemu_set_cloexec(sv[0]); + qemu_set_cloexec(sv[1]); + } + + return ret; +} + char * qemu_get_local_state_dir(void) { diff --git a/util/qemu-config.c b/util/qemu-config.c index 433488aa56..5325f6bf80 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -236,6 +236,10 @@ static QemuOptsList machine_opts = { .help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars" " converted to upper case) to pass to machine" " loader, boot manager, and guest kernel", + },{ + .name = "zpcii-disable", + .type = QEMU_OPT_BOOL, + .help = "disable zPCI interpretation facilities", }, { /* End of list */ } } diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 9ad24ab1af..15c82d9348 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -135,7 +135,7 @@ typedef struct CoWaitRecord { QSLIST_ENTRY(CoWaitRecord) next; } CoWaitRecord; -static void push_waiter(CoMutex *mutex, CoWaitRecord *w) +static void coroutine_fn push_waiter(CoMutex *mutex, CoWaitRecord *w) { w->co = qemu_coroutine_self(); QSLIST_INSERT_HEAD_ATOMIC(&mutex->from_push, w, next); @@ -332,7 +332,7 @@ void qemu_co_rwlock_init(CoRwlock *lock) } /* Releases the internal CoMutex. */ -static void qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) +static void coroutine_fn qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) { CoRwTicket *tkt = QSIMPLEQ_FIRST(&lock->tickets); Coroutine *co = NULL; @@ -365,7 +365,7 @@ static void qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) } } -void qemu_co_rwlock_rdlock(CoRwlock *lock) +void coroutine_fn qemu_co_rwlock_rdlock(CoRwlock *lock) { Coroutine *self = qemu_coroutine_self(); @@ -390,7 +390,7 @@ void qemu_co_rwlock_rdlock(CoRwlock *lock) self->locks_held++; } -void qemu_co_rwlock_unlock(CoRwlock *lock) +void coroutine_fn qemu_co_rwlock_unlock(CoRwlock *lock) { Coroutine *self = qemu_coroutine_self(); @@ -408,7 +408,7 @@ void qemu_co_rwlock_unlock(CoRwlock *lock) qemu_co_rwlock_maybe_wake_one(lock); } -void qemu_co_rwlock_downgrade(CoRwlock *lock) +void coroutine_fn qemu_co_rwlock_downgrade(CoRwlock *lock) { qemu_co_mutex_lock(&lock->mutex); assert(lock->owners == -1); @@ -418,7 +418,7 @@ void qemu_co_rwlock_downgrade(CoRwlock *lock) qemu_co_rwlock_maybe_wake_one(lock); } -void qemu_co_rwlock_wrlock(CoRwlock *lock) +void coroutine_fn qemu_co_rwlock_wrlock(CoRwlock *lock) { Coroutine *self = qemu_coroutine_self(); @@ -438,7 +438,7 @@ void qemu_co_rwlock_wrlock(CoRwlock *lock) self->locks_held++; } -void qemu_co_rwlock_upgrade(CoRwlock *lock) +void coroutine_fn qemu_co_rwlock_upgrade(CoRwlock *lock) { qemu_co_mutex_lock(&lock->mutex); assert(lock->owners > 0); diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 4a8bd63ef0..356b746f0b 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -213,7 +213,7 @@ bool qemu_coroutine_entered(Coroutine *co) return co->caller; } -AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co) +AioContext *qemu_coroutine_get_aio_context(Coroutine *co) { return co->ctx; } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 13b5b197f9..83f4bd6fd2 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -487,7 +487,7 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp) if (ret < 0) { error_setg_errno(errp, errno, "Unable to set KEEPALIVE"); - close(sock); + closesocket(sock); return -1; } } @@ -880,8 +880,6 @@ static int vsock_parse(VsockSocketAddress *addr, const char *str, } #endif /* CONFIG_AF_VSOCK */ -#ifndef _WIN32 - static bool saddr_is_abstract(UnixSocketAddress *saddr) { #ifdef CONFIG_LINUX @@ -1050,29 +1048,10 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) return sock; err: - close(sock); + closesocket(sock); return -1; } -#else - -static int unix_listen_saddr(UnixSocketAddress *saddr, - int num, - Error **errp) -{ - error_setg(errp, "unix sockets are not available on windows"); - errno = ENOTSUP; - return -1; -} - -static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) -{ - error_setg(errp, "unix sockets are not available on windows"); - errno = ENOTSUP; - return -1; -} -#endif - /* compatibility wrapper */ int unix_listen(const char *str, Error **errp) { @@ -1335,7 +1314,6 @@ socket_sockaddr_to_address_inet(struct sockaddr_storage *sa, } -#ifndef WIN32 static SocketAddress * socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, socklen_t salen, @@ -1362,7 +1340,6 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, addr->u.q_unix.path = g_strndup(su->sun_path, salen); return addr; } -#endif /* WIN32 */ #ifdef CONFIG_AF_VSOCK static SocketAddress * @@ -1394,10 +1371,8 @@ socket_sockaddr_to_address(struct sockaddr_storage *sa, case AF_INET6: return socket_sockaddr_to_address_inet(sa, salen, errp); -#ifndef WIN32 case AF_UNIX: return socket_sockaddr_to_address_unix(sa, salen, errp); -#endif /* WIN32 */ #ifdef CONFIG_AF_VSOCK case AF_VSOCK: